#include "Block.h" #include "Inventory.h" #include "NoBlock.h" #include "Game.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 { NetworkResponse changeMsg; changeMsg.adressBlock(this); char msg[5]; msg[0] = 0; // hp changed *(float*)(msg + 1) = this->hp; changeMsg.setMessage(msg, 5, 0); Game::INSTANCE->distributeResponse(&changeMsg); } } 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, const char* name, ItemSkillLevelUpRule* levelUpRule, const ItemType* zBrokenType, ModelInfo model) : ItemType(id, name, levelUpRule, zBrokenType, model) {} 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; }