#include "Block.h" #include "Inventory.h" #include "NoBlock.h" #include "Game.h" #include "BlockChangedUpdate.h" #include "PlaceBlockUpdate.h" #include "BlockRemovedUpdate.h" #include "ItemEntity.h" #include "AddEntityUpdate.h" Block::Block( const BlockType* zType, ItemType* zTool, Framework::Vec3 pos, bool hasInventory ) : Inventory( pos, hasInventory ) { transparent = false; passable = false; hp = 1; maxHP = 1; hardness = 1; this->zType = zType; this->zTool = zTool; speedModifier = 1; ticksLeftCounter = 0; wasTicked = 0; onTickCalled = 0; minTickTimeout = -1; maxTickTimeout = -1; tickSource = 0; currentTickTimeout = 0; dimensionId = 0; interactable = 0; deadAndRemoved = 0; memset( zNeighbours, 0, sizeof( Block* ) * 6 ); } Block::~Block() {} void Block::onDestroy() { if( !deadAndRemoved ) { Item* blockItem = zType->getItemFromBlock( this ); if( blockItem ) { ItemEntity* itemEntity = (ItemEntity*)ItemEntityType::INSTANCE->createEntity( location + Framework::Vec3( 0.5f, 0.5f, 0.5f ), dimensionId, Game::INSTANCE->getNextEntityId() ); ItemStack* stack = new ItemStack( blockItem, 1, blockItem->getMaxStackSize() ); itemEntity->unsaveAddItem( stack, NO_DIRECTION ); stack->release(); Game::INSTANCE->requestWorldUpdate( new AddEntityUpdate( itemEntity, dimensionId ) ); deadAndRemoved = 1; } } } void Block::tick( TickQueue* zQueue ) { if( wasTicked ) return; wasTicked = 1; ticksLeftCounter++; if( minTickTimeout >= 0 ) { if( currentTickTimeout < ticksLeftCounter ) { onTickCalled = 1; bool blocked = 0; bool result = onTick( zQueue, ticksLeftCounter, blocked ); if( blocked ) { wasTicked = 0; ticksLeftCounter--; onTickCalled = 0; return; } if( result ) currentTickTimeout = MAX( MIN( currentTickTimeout - 1, maxTickTimeout ), MAX( minTickTimeout, 0 ) ); else currentTickTimeout = MAX( MIN( currentTickTimeout + 1, maxTickTimeout ), MAX( minTickTimeout, 0 ) ); ticksLeftCounter = 0; } } } void Block::postTick() { wasTicked = 0; if( onTickCalled ) { onPostTick(); onTickCalled = 0; } } void Block::setNeighbour( Direction dir, Framework::Either neighbour ) { if( neighbour.isA() ) setNeighbourBlock( dir, neighbour ); else { setNeighbourBlock( dir, 0 ); setNeighbourType( dir, neighbour ); } } void Block::setNeighbourBlock( Direction dir, Block* zN ) { if( zN ) setNeighbourType( dir, zN->zBlockType()->getId() ); zNeighbours[ getDirectionIndex( dir ) ] = zN; } void Block::setNeighbourType( Direction dir, int type ) { neighbourTypes[ getDirectionIndex( dir ) ] = type; } void Block::setDimensionId( int id ) { dimensionId = id; } void api( Framework::StreamReader* zRequest, NetworkResponse* zResponse ) { // TODO: answer api requests } bool Block::isTickSource() const { return tickSource; } const BlockType* Block::zBlockType() const { return zType; } bool Block::isTransparent() const { return transparent; } bool Block::isPassable() const { return passable; } bool Block::isInteractable() const { return interactable; } float Block::getHP() const { return hp; } float Block::getMaxHP() const { return maxHP; } float Block::getHardness() const { return hardness; } ItemType* Block::zEffectiveTool() const { return zTool; } float Block::getSpeedModifier() const { return speedModifier; } const Framework::Vec3 Block::getPos() const { return (Framework::Vec3)location; } int Block::getDimensionId() const { return dimensionId; } bool Block::isVisible() const { if( passable || transparent ) return 1; for( int i = 0; i < 6; i++ ) { const Block* neighbour = CONST_BLOCK( zNeighbours[ i ], neighbourTypes[ i ] ); if( neighbour->isPassable() || neighbour->isTransparent() ) return 1; } return 0; } void Block::setHP( float hp ) { bool isDead = this->hp == 0.f; this->hp = MAX( 0.f, hp ); if( !isDead && this->hp == 0.f ) { for( int i = 0; i < 6; i++ ) { if( neighbourTypes[ i ] == NoBlockBlockType::ID ) { Framework::Vec3 pos = getPos() + getDirection( getDirectionFromIndex( i ) ); Game::INSTANCE->requestWorldUpdate( new PlaceBlockUpdate( Game::INSTANCE->zGenerator()->generateSingleBlock( pos, dimensionId ), pos, dimensionId ) ); } } Game::INSTANCE->requestWorldUpdate( new BlockRemovedUpdate( getPos(), dimensionId ) ); onDestroy(); } else requestTransmission(); } void Block::onAfterTransmission() { transmissionRequested = 0; } void Block::requestTransmission() { if( !transmissionRequested ) { transmissionRequested = 1; Game::INSTANCE->requestWorldUpdate( new BlockChangedUpdate( getPos(), getDimensionId() ) ); } } bool Block::isDeadAndRemoved() const { return deadAndRemoved; } BasicBlockItem::BasicBlockItem( const ItemType* zType, const BlockType* zPlacedBlockType, const char* name ) : Item( zType, name ) { placeable = 1; zBlockType = zPlacedBlockType; } bool BasicBlockItem::canBeStackedWith( Item* zItem ) const { BasicBlockItem* item = dynamic_cast(zItem); if( item ) { return Item::canBeStackedWith( zItem ) && transparent == item->transparent && passable == item->passable && hp == item->hp && maxHP == item->maxHP && hardness == item->hardness && toolId == item->toolId && speedModifier == item->speedModifier && interactable == item->interactable; } return 0; } BasicBlockItemType::BasicBlockItemType( int id, ItemSkillLevelUpRule* levelUpRule, const ItemType* zBrokenType ) : ItemType( id, levelUpRule, zBrokenType ) {} void BasicBlockItemType::loadSuperItem( Item* zItem, Framework::StreamReader* zReader ) const { ItemType::loadSuperItem( zItem, zReader ); BasicBlockItem* item = dynamic_cast(zItem); if( !item ) throw "BasicBlockItemType::loadSuperItem was called with an invalid item"; zReader->lese( (char*)&item->transparent, 1 ); zReader->lese( (char*)&item->passable, 1 ); zReader->lese( (char*)&item->hp, 4 ); zReader->lese( (char*)&item->maxHP, 4 ); zReader->lese( (char*)&item->hardness, 4 ); zReader->lese( (char*)&item->toolId, 4 ); zReader->lese( (char*)&item->speedModifier, 4 ); zReader->lese( (char*)&item->interactable, 1 ); } void BasicBlockItemType::saveSuperItem( const Item* zItem, Framework::StreamWriter* zWriter ) const { ItemType::saveSuperItem( zItem, zWriter ); const BasicBlockItem* item = dynamic_cast(zItem); if( !item ) throw "BasicBlockItemType::saveSuperItem was called with an invalid item"; zWriter->schreibe( (char*)&item->transparent, 1 ); zWriter->schreibe( (char*)&item->passable, 1 ); zWriter->schreibe( (char*)&item->hp, 4 ); zWriter->schreibe( (char*)&item->maxHP, 4 ); zWriter->schreibe( (char*)&item->hardness, 4 ); zWriter->schreibe( (char*)&item->toolId, 4 ); zWriter->schreibe( (char*)&item->speedModifier, 4 ); zWriter->schreibe( (char*)&item->interactable, 1 ); } void BasicBlockItemType::initializeItem( BasicBlockItem* zItem, bool transparent, bool passable, float hp, float maxHP, float hardness, int toolId, float speedModifier ) const { zItem->transparent = transparent; zItem->passable = passable; zItem->hp = hp; zItem->maxHP = maxHP; zItem->hardness = hardness; zItem->toolId = toolId; zItem->speedModifier = speedModifier; }