#include "GrowingPlant.h" #include "Dimension.h" #include "Game.h" GrowthState::GrowthState(float percentage, ModelInfo* model) : ReferenceCounter(), percentage(percentage), model(model) {} GrowthState::~GrowthState() { model->release(); } float GrowthState::getPercentage() const { return percentage; } ModelInfo* GrowthState::zModel() const { return model; } GrowingPlantBlock::GrowingPlantBlock(int typeId, Framework::Vec3 pos, int dimensionId, int maxTicks, Framework::Text name, int blockTypeAfterGrowth) : Block(typeId, pos, dimensionId, 0), seblingTicks(0), seblingTicksMax(maxTicks), name(name), states(), blockTypeAfterGrowth(blockTypeAfterGrowth), plantSpawned(0), lastSendState(-1) {} bool GrowingPlantBlock::onTick(TickQueue* zQueue, int numTicks, bool& blocked) { float beforePercentage = seblingTicks / (float)seblingTicksMax; seblingTicks += (float)numTicks; if ((int)(seblingTicks / (float)seblingTicksMax * 100.f) != (int)(beforePercentage * 100.f)) { Game::INSTANCE->blockTargetChanged(this); } int index = 0; int currentIndex = 0; for (GrowthState* state : states) { if (state->getPercentage() <= seblingTicks / (float)seblingTicksMax) { currentIndex = index; } else { break; } index++; } if (lastSendState != currentIndex) { updateModel(states.z(currentIndex)->zModel()); lastSendState = currentIndex; } return 1; } void GrowingPlantBlock::onPostTick() { if (seblingTicks >= (float)seblingTicksMax && !plantSpawned) { plantSpawned = 1; Game::INSTANCE->doLater([this]() { Game::INSTANCE->zDimension(getDimensionId()) ->placeBlock(getPos(), blockTypeAfterGrowth); }); } } void GrowingPlantBlock::sendModelInfo(NetworkMessage* zMessage) { GrowthState* current = 0; for (GrowthState* state : states) { if (state->getPercentage() <= seblingTicks / (float)seblingTicksMax) { current = state; } } if (current) { zMessage->addressBlock(this); Framework::InMemoryBuffer buffer; current->zModel()->writeTo(&buffer); char* msg = new char[(int)buffer.getSize() + 1]; msg[0] = 1; // hmodel change buffer.lese(msg + 1, (int)buffer.getSize()); zMessage->setMessage(msg, (int)buffer.getSize() + 1); } } TickSourceType GrowingPlantBlock::isTickSource() const { return TickSourceType::EACH_TICK; } Framework::Text GrowingPlantBlock::getTargetUIML() { return Framework::Text("") + name + "\n" + "Growth: " + Framework::Text((int)(seblingTicks / (float)seblingTicksMax * 100.f)) + "%"; } GrowingPlantBlock* GrowingPlantBlock::addGrowthState(GrowthState* state) { int index = 0; for (GrowthState* s : states) { if (s->getPercentage() > state->getPercentage()) { states.add(state, index); return this; } index++; } states.add(state); return this; } GrowingPlantBlockType::GrowingPlantBlockType() : BlockType(), transparent(1), passable(1), speedModifier(0.3f), interactable(1), ticksNeeded(0) {} void GrowingPlantBlockType::createSuperBlock(Block* zBlock, Item* zItem) const { GrowingPlantBlock* block = dynamic_cast(zBlock); block->transparent = transparent; block->passable = passable; block->hardness = getHardness(); block->speedModifier = speedModifier; block->interactable = interactable; BlockType::createSuperBlock(zBlock, zItem); } void GrowingPlantBlockType::loadSuperBlock( Block* zBlock, Framework::StreamReader* zReader, int dimensionId) const { BlockType::loadSuperBlock(zBlock, zReader, dimensionId); GrowingPlantBlock* block = dynamic_cast(zBlock); zReader->lese((char*)&block->seblingTicks, 4); } void GrowingPlantBlockType::saveSuperBlock( Block* zBlock, Framework::StreamWriter* zWriter) const { BlockType::saveSuperBlock(zBlock, zWriter); GrowingPlantBlock* block = dynamic_cast(zBlock); zWriter->schreibe((char*)&block->seblingTicks, 4); } Item* GrowingPlantBlockType::createItem() const { return 0; } Block* GrowingPlantBlockType::createBlock( Framework::Vec3 position, int dimensionId) const { GrowingPlantBlock* block = new GrowingPlantBlock(getId(), position, dimensionId, ticksNeeded, readableName, blockTypeIdAfterGrowth); for (GrowthState* state : states) { block->addGrowthState(dynamic_cast(state->getThis())); } return block; } GrowingPlantBlockType* GrowingPlantBlockType::addGrowthState( float growthPercentage, ModelInfo* model) { states.add(new GrowthState(growthPercentage, model)); return this; } Framework::Text GrowingPlantBlockType::getBlockTypeNameAfterGrowth() const { return blockTypeNameAfterGrowth; } void GrowingPlantBlockType::setReadableName(Framework::Text readableName) { this->readableName = readableName; } Framework::Text GrowingPlantBlockType::getReadableName() const { return readableName; } void GrowingPlantBlockType::setTicksNeeded(int ticksNeeded) { this->ticksNeeded = ticksNeeded; } int GrowingPlantBlockType::getTicksNeeded() const { return ticksNeeded; } void GrowingPlantBlockType::setTransparent(bool transparent) { this->transparent = transparent; } bool GrowingPlantBlockType::isTransparent() const { return transparent; } void GrowingPlantBlockType::setPassable(bool passable) { this->passable = passable; } bool GrowingPlantBlockType::isPassable() const { return passable; } void GrowingPlantBlockType::setSpeedModifier(float speedModifier) { this->speedModifier = speedModifier; } float GrowingPlantBlockType::getSpeedModifier() const { return speedModifier; } void GrowingPlantBlockType::setInteractable(bool interactable) { this->interactable = interactable; } bool GrowingPlantBlockType::isInteractable() const { return interactable; } const Framework::RCArray& GrowingPlantBlockType::getStates() const { return states; } void GrowingPlantBlockType::setBlockTypeNameAfterGrowth( Framework::Text blockTypeIdAfterGrowth) {} ItemType* GrowingPlantBlockType::createItemType() const { return 0; } GrowingPlantBlockTypeFactory::GrowingPlantBlockTypeFactory() : BlockTypeFactoryBase() {} GrowingPlantBlockType* GrowingPlantBlockTypeFactory::createValue( Framework::JSON::JSONObject* zJson) const { return new GrowingPlantBlockType(); } void GrowingPlantBlockTypeFactory::fromJson( GrowingPlantBlockType* zResult, Framework::JSON::JSONObject* zJson) const { zResult->setBlockTypeNameAfterGrowth( zJson->zValue("blockTypeAfterGrowth")->asString()->getString()); zResult->setReadableName( zJson->zValue("readableName")->asString()->getString()); zResult->setTicksNeeded( (int)zJson->zValue("ticksNeeded")->asNumber()->getNumber()); zResult->setTransparent(zJson->zValue("transparent")->asBool()->getBool()); zResult->setPassable(zJson->zValue("passable")->asBool()->getBool()); zResult->setSpeedModifier( (float)zJson->zValue("speedModifier")->asNumber()->getNumber()); zResult->setInteractable( zJson->zValue("interactable")->asBool()->getBool()); for (Framework::JSON::JSONValue* state : *zJson->zValue("states")->asArray()) { zResult->addGrowthState((float)state->asObject() ->zValue("percentage") ->asNumber() ->getNumber(), Game::INSTANCE->zTypeRegistry()->fromJson( state->asObject()->zValue("model"))); } BlockTypeFactoryBase::fromJson(zResult, zJson); } void GrowingPlantBlockTypeFactory::toJson( GrowingPlantBlockType* zObject, Framework::JSON::JSONObject* zResult) const { zResult->addValue("readableName", new Framework::JSON::JSONString(zObject->getReadableName())); zResult->addValue( "model", Game::INSTANCE->zTypeRegistry()->toJson(zObject->zModel())); zResult->addValue( "name", new Framework::JSON::JSONString(zObject->getName())); zResult->addValue( "hardness", new Framework::JSON::JSONNumber(zObject->getHardness())); zResult->addValue( "mapColor", new Framework::JSON::JSONString(zObject->getMapColor())); zResult->addValue("blockTypeAfterGrowth", new Framework::JSON::JSONString( zObject->getBlockTypeNameAfterGrowth())); zResult->addValue("ticksNeeded", new Framework::JSON::JSONNumber((double)zObject->getTicksNeeded())); Framework::JSON::JSONArray* states = new Framework::JSON::JSONArray(); for (GrowthState* state : zObject->getStates()) { Framework::JSON::JSONObject* stateObj = new Framework::JSON::JSONObject(); stateObj->addValue( "model", Game::INSTANCE->zTypeRegistry()->toJson(state->zModel())); stateObj->addValue("percentage", new Framework::JSON::JSONNumber(state->getPercentage())); states->addValue(stateObj); } zResult->addValue("states", states); Framework::JSON::JSONArray* groupNames = new Framework::JSON::JSONArray(); for (Framework::Text* groupName : zObject->getGroupNames()) { groupNames->addValue(new Framework::JSON::JSONString(*groupName)); } zResult->addValue("groupNames", groupNames); } JSONObjectValidationBuilder* GrowingPlantBlockTypeFactory::addToValidator( JSONObjectValidationBuilder* builder) const { return BlockTypeFactoryBase::addToValidator( builder->withRequiredString("readableName") ->finishString() ->withRequiredNumber("ticksNeeded") ->finishNumber() ->withRequiredString("blockTypeAfterGrowth") ->finishString() ->withRequiredArray("states") ->addAcceptedObjectInArray() ->withRequiredNumber("percentage") ->whichIsGreaterOrEqual(0.0) ->whichIsLessOrEqual(1.0) ->finishNumber() ->withRequiredAttribute("model", Game::INSTANCE->zTypeRegistry()->getValidator()) ->finishObject() ->finishArray() ->withRequiredBool("transparent") ->withDefault(true) ->finishBool() ->withRequiredBool("passable") ->withDefault(true) ->finishBool() ->withRequiredNumber("speedModifier") ->withDefault(0.5) ->finishNumber() ->withRequiredBool("interactable") ->withDefault(true) ->finishBool()); } Framework::Text GrowingPlantBlockTypeFactory::getTypeToken() const { return "growingPlant"; }