#include "FluidContainer.h" #include #include #include "Dimension.h" #include "Entity.h" #include "FluidBlock.h" #include "Game.h" FluidContainerItem::FluidContainerItem(int itemTypeId, Framework::Text name) : Item(itemTypeId, name), fluidTypeId(0), fluidAmount(0) { placeable = 1; usable = 1; eatable = 1; } const BlockType* FluidContainerItem::zPlacedBlockType() const { return fluidTypeId && fluidAmount >= 1000 ? Game::INSTANCE->zBlockType(fluidTypeId) : 0; } bool FluidContainerItem::canBeStackedWith(const Item* zItem) const { const FluidContainerItem* other = dynamic_cast(zItem); if (!other) return false; return Item::canBeStackedWith(zItem) && other->fluidTypeId == fluidTypeId && other->fluidAmount == fluidAmount; } bool FluidContainerItem::canBePlacedAt( const int dimensionId, Framework::Vec3 worldPos) const { if (fluidAmount >= 1000) { Dimension* dim = Game::INSTANCE->zDimension(dimensionId); if (dim) { const Block* block = dim->zBlockOrDefault(worldPos); if (block) { if (block->zBlockType()->getId() == BlockTypeEnum::AIR) return true; if (block->zBlockType()->getId() == fluidTypeId) { const FluidBlock* fluidBlock = dynamic_cast(block); return fluidBlock && fluidBlock->getDistanceToSource() > 0; } } } } return false; } void FluidContainerItem::onPlaced() { setAmount(fluidAmount - 1000); } Framework::Text FluidContainerItem::getTooltipUIML() const { Framework::Text uiml = ""; uiml.append() << getName(); if (fluidTypeId != 0) { uiml.append() << "\nFluid: " << Game::INSTANCE->zBlockType(fluidTypeId)->getName() << "\nAmount: " << fluidAmount << " L"; } else { uiml.append() << "\nEmpty"; } uiml.append() << ""; return uiml; } bool FluidContainerItem::applyFoodEffects(Entity* zTarget) { if (fluidTypeId) { const FluidBlockType* fluidType = dynamic_cast( Game::INSTANCE->zBlockType(fluidTypeId)); if (fluidType && (fluidType->getHungerRecoveryPerL() || fluidType->getThirstRecoveryPerL())) { int drinkable = fluidType->getThirstRecoveryPerL() > 0 ? (int)((zTarget->getMaxThirst() - zTarget->getThirst()) / fluidType->getThirstRecoveryPerL()) : (int)((zTarget->getMaxHunger() - zTarget->getHunger()) / fluidType->getHungerRecoveryPerL()); if (fluidType->getHungerRecoveryPerL() > 0 && fluidType->getThirstRecoveryPerL() > 0) { int drinkable2 = (int)((zTarget->getMaxHunger() - zTarget->getHunger()) / fluidType->getHungerRecoveryPerL()); if (drinkable2 < drinkable) drinkable = drinkable2; } if (getAmount() < drinkable) drinkable = getAmount(); if (!drinkable) return false; setAmount(getAmount() - drinkable); zTarget->setThirst( zTarget->getThirst() + drinkable * fluidType->getThirstRecoveryPerL()); zTarget->setHunger( zTarget->getHunger() + drinkable * fluidType->getHungerRecoveryPerL()); return true; } } return false; } bool FluidContainerItem::canApplyFoodEffectsFully(Entity* zTarget) const { return false; } int FluidContainerItem::getAmount() const { return fluidAmount; } void FluidContainerItem::setAmount(int amount) { fluidAmount = amount; if (!fluidAmount) { fluidTypeId = 0; } } int FluidContainerItem::getFluidTypeId() const { return fluidTypeId; } void FluidContainerItem::setFluidTypeId(int fluidTypeId) { this->fluidTypeId = fluidTypeId; if (!fluidTypeId) { fluidAmount = 0; } } FluidContainerItemSkillConfig::FluidContainerItemSkillConfig() : ReferenceCounter(), targetFilter(0), staminaCost(0.5f), staminaCostDevider(0.9f), staminaCostDeviderPerLevel(1.f), cooldownTicks(10), xpGain(0.5f) {} FluidContainerItemSkillConfig::~FluidContainerItemSkillConfig() { if (targetFilter) targetFilter->release(); } void FluidContainerItemSkillConfig::setTargetFilter(BlockFilter* targetFilter) { this->targetFilter = targetFilter; } BlockFilter* FluidContainerItemSkillConfig::zTargetFilter() const { return targetFilter; } void FluidContainerItemSkillConfig::setStaminaCost(float staminaCost) { this->staminaCost = staminaCost; } float FluidContainerItemSkillConfig::getStaminaCost() const { return staminaCost; } void FluidContainerItemSkillConfig::setStaminaCostDevider( float staminaCostDevider) { this->staminaCostDevider = staminaCostDevider; } float FluidContainerItemSkillConfig::getStaminaCostDevider() const { return staminaCostDevider; } void FluidContainerItemSkillConfig::setStaminaCostDeviderPerLevel( float staminaCostDeviderPerLevel) { this->staminaCostDeviderPerLevel = staminaCostDeviderPerLevel; } float FluidContainerItemSkillConfig::getStaminaCostDeviderPerLevel() const { return staminaCostDeviderPerLevel; } void FluidContainerItemSkillConfig::setCooldownTicks(int cooldownTicks) { this->cooldownTicks = cooldownTicks; } int FluidContainerItemSkillConfig::getCooldownTicks() const { return cooldownTicks; } void FluidContainerItemSkillConfig::setXpGain(float xpGain) { this->xpGain = xpGain; } float FluidContainerItemSkillConfig::getXpGain() const { return xpGain; } FluidContainerItemSkillConfigFactory::FluidContainerItemSkillConfigFactory() : TypeFactory() {} FluidContainerItemSkillConfig* FluidContainerItemSkillConfigFactory::createValue( Framework::JSON::JSONObject* zJson) const { return new FluidContainerItemSkillConfig(); } void FluidContainerItemSkillConfigFactory::fromJson( FluidContainerItemSkillConfig* zResult, Framework::JSON::JSONObject* zJson) const { zResult->setTargetFilter( Game::INSTANCE->zTypeRegistry()->fromJson( zJson->asObject()->zValue("targetFilter"))); zResult->setStaminaCost((float)zJson->asObject() ->zValue("staminaCost") ->asNumber() ->getNumber()); zResult->setStaminaCostDevider((float)zJson->asObject() ->zValue("staminaCostDevider") ->asNumber() ->getNumber()); zResult->setStaminaCostDeviderPerLevel( (float)zJson->asObject() ->zValue("staminaCostDeviderPerLevel") ->asNumber() ->getNumber()); zResult->setCooldownTicks((int)zJson->asObject() ->zValue("cooldownTicks") ->asNumber() ->getNumber()); zResult->setXpGain( (float)zJson->asObject()->zValue("xpGain")->asNumber()->getNumber()); } void FluidContainerItemSkillConfigFactory::toJson( FluidContainerItemSkillConfig* zObject, Framework::JSON::JSONObject* zResult) const { zResult->addValue("targetFilter", Game::INSTANCE->zTypeRegistry()->toJson(zObject->zTargetFilter())); zResult->addValue("staminaCost", new Framework::JSON::JSONNumber(zObject->getStaminaCost())); zResult->addValue("staminaCostDevider", new Framework::JSON::JSONNumber(zObject->getStaminaCostDevider())); zResult->addValue("staminaCostDeviderPerLevel", new Framework::JSON::JSONNumber( zObject->getStaminaCostDeviderPerLevel())); zResult->addValue("cooldownTicks", new Framework::JSON::JSONNumber(zObject->getCooldownTicks())); zResult->addValue( "xpGain", new Framework::JSON::JSONNumber(zObject->getXpGain())); } JSONObjectValidationBuilder* FluidContainerItemSkillConfigFactory::addToValidator( JSONObjectValidationBuilder* builder) const { return builder ->withRequiredAttribute("targetFilter", Game::INSTANCE->zTypeRegistry()->getValidator()) ->withRequiredNumber("staminaCost") ->whichIsGreaterOrEqual(0.0) ->withDefault(0.5) ->finishNumber() ->withRequiredNumber("staminaCostDevider") ->whichIsGreaterOrEqual(0.0) ->withDefault(0.9) ->finishNumber() ->withRequiredNumber("staminaCostDeviderPerLevel") ->whichIsGreaterOrEqual(0.0) ->withDefault(0.1) ->finishNumber() ->withRequiredNumber("cooldownTicks") ->whichIsGreaterOrEqual(0) ->withDefault(10) ->finishNumber() ->withRequiredNumber("xpGain") ->whichIsGreaterOrEqual(0.0) ->withDefault(0.5) ->finishNumber(); } FluidContainerItemSkill::FluidContainerItemSkill() : ItemSkill(), cooldownTicks(0), invalidUseConfig(0) {} FluidContainerItemSkill::~FluidContainerItemSkill() { if (invalidUseConfig) invalidUseConfig->release(); } bool FluidContainerItemSkill::use( Entity* zActor, Item* zUsedItem, Block* zTarget) { if (cooldownTicks) { cooldownTicks--; return false; } FluidContainerItem* usedItem = dynamic_cast(zUsedItem); FluidBlock* fluidBlock = dynamic_cast(zTarget); const FluidContainerItemType* usedItemType = dynamic_cast(usedItem->zItemType()); FluidContainerItemSkillConfig* usedConfig = 0; bool invalid = false; if (!zTarget->zBlockType()->isFluid() || zTarget->getHP() <= 0) { usedConfig = invalidUseConfig; invalid = true; } else if (!usedItem) { usedConfig = invalidUseConfig; invalid = true; } else if (!fluidBlock || fluidBlock->getDistanceToSource()) { usedConfig = invalidUseConfig; invalid = true; } else if (!usedItemType) { usedConfig = invalidUseConfig; invalid = true; } else if (usedItem->getAmount() + 1000 > usedItemType->getMaxFluidAmount()) { usedConfig = invalidUseConfig; invalid = true; } else if (usedItem->getFluidTypeId() && usedItem->getFluidTypeId() != fluidBlock->zBlockType()->getId()) { usedConfig = invalidUseConfig; invalid = true; } if (!usedConfig) { for (FluidContainerItemSkillConfig* config : configs) { if (config->zTargetFilter()->test(zTarget)) { usedConfig = config; break; } } } if (!usedConfig) { usedConfig = invalidUseConfig; invalid = true; } float staminaCost = usedConfig->getStaminaCost(); float staminaCostDevider = usedConfig->getStaminaCostDevider() + usedConfig->getStaminaCostDeviderPerLevel() * getLevel(); if (staminaCostDevider) { staminaCost /= staminaCostDevider; } if (zActor->getStamina() < staminaCost) { return false; } zActor->setStamina(zActor->getStamina() - staminaCost); if (!invalid && usedItem->getAmount() + 1000 <= usedItemType->getMaxFluidAmount()) { usedItem->setFluidTypeId(fluidBlock->zBlockType()->getId()); usedItem->setAmount(usedItem->getAmount() + 1000); zTarget->setHP(0); } this->cooldownTicks = usedConfig->getCooldownTicks(); setXp(getXp() + usedConfig->getXpGain()); return true; } bool FluidContainerItemSkill::use( Entity* zActor, Item* zUsedItem, Entity* zTarget) { // TODO: get milk from cows and something else from other mobs return false; } void FluidContainerItemSkill::setInvalidUseConfig( FluidContainerItemSkillConfig* invalidUseConfig) { if (this->invalidUseConfig) this->invalidUseConfig->release(); this->invalidUseConfig = invalidUseConfig; } FluidContainerItemSkillConfig* FluidContainerItemSkill::zInvalidUseConfig() const { return invalidUseConfig; } void FluidContainerItemSkill::addConfig(FluidContainerItemSkillConfig* config) { configs.add(config); } const Framework::RCArray& FluidContainerItemSkill::zConfigs() const { return configs; } FluidContainerItemSkillFactory::FluidContainerItemSkillFactory() : ItemSkillFactoryBase() {} FluidContainerItemSkill* FluidContainerItemSkillFactory::createValue( Framework::JSON::JSONObject* zJson) const { return new FluidContainerItemSkill(); } void FluidContainerItemSkillFactory::fromJson( FluidContainerItemSkill* zResult, Framework::JSON::JSONObject* zJson) const { for (Framework::JSON::JSONValue* configValue : *zJson->zValue("configs")->asArray()) { zResult->addConfig(Game::INSTANCE->zTypeRegistry() ->fromJson( configValue->asObject())); } FluidContainerItemSkillConfig* invalidConfig = new FluidContainerItemSkillConfig(); invalidConfig->setStaminaCost( (float)zJson->zValue("invalidUseStaminaCost")->asNumber()->getNumber()); invalidConfig->setStaminaCostDevider( (float)zJson->zValue("invalidUseStaminaCostDevider") ->asNumber() ->getNumber()); invalidConfig->setStaminaCostDeviderPerLevel( (float)zJson->zValue("invalidUseStaminaCostDeviderPerLevel") ->asNumber() ->getNumber()); invalidConfig->setCooldownTicks( (int)zJson->zValue("invalidUseCooldownTicks")->asNumber()->getNumber()); zResult->setInvalidUseConfig(invalidConfig); ItemSkillFactoryBase::fromJson(zResult, zJson); } void FluidContainerItemSkillFactory::toJson(FluidContainerItemSkill* zObject, Framework::JSON::JSONObject* zResult) const { zResult->addValue("invalidUseStaminaCost", new Framework::JSON::JSONNumber( zObject->zInvalidUseConfig()->getStaminaCost())); zResult->addValue("invalidUseStaminaCostDevider", new Framework::JSON::JSONNumber( zObject->zInvalidUseConfig()->getStaminaCostDevider())); zResult->addValue("invalidUseStaminaCostDeviderPerLevel", new Framework::JSON::JSONNumber( zObject->zInvalidUseConfig()->getStaminaCostDeviderPerLevel())); zResult->addValue("invalidUseCooldownTicks", new Framework::JSON::JSONNumber( zObject->zInvalidUseConfig()->getCooldownTicks())); Framework::JSON::JSONArray* configs = new Framework::JSON::JSONArray(); for (FluidContainerItemSkillConfig* config : zObject->zConfigs()) { configs->addValue(Game::INSTANCE->zTypeRegistry()->toJson(config)); } zResult->addValue("configs", configs); ItemSkillFactoryBase::toJson(zObject, zResult); } JSONObjectValidationBuilder* FluidContainerItemSkillFactory::addToValidator( JSONObjectValidationBuilder* builder) const { return ItemSkillFactoryBase::addToValidator(builder) ->withRequiredNumber("invalidUseStaminaCost") ->whichIsGreaterOrEqual(0.0) ->withDefault(0.5) ->finishNumber() ->withRequiredNumber("invalidUseStaminaCostDevider") ->whichIsGreaterOrEqual(0.0) ->withDefault(0.9) ->finishNumber() ->withRequiredNumber("invalidUseStaminaCostDeviderPerLevel") ->whichIsGreaterOrEqual(0.0) ->withDefault(0.1) ->finishNumber() ->withRequiredNumber("invalidUseCooldownTicks") ->whichIsGreaterOrEqual(0) ->withDefault(10) ->finishNumber() ->withRequiredArray("configs") ->addAcceptedTypeInArray( Game::INSTANCE->zTypeRegistry() ->getValidator()) ->finishArray(); } Framework::Text FluidContainerItemSkillFactory::getTypeToken() const { return "fluidGathering"; } FluidContainerItemType::FluidContainerItemType() : ItemType(), maxFluidAmount(1000), itemSkillConfig(0), levelUpRule(0) {} FluidContainerItemType::~FluidContainerItemType() { if (itemSkillConfig) itemSkillConfig->release(); if (levelUpRule) levelUpRule->release(); } void FluidContainerItemType::loadSuperItem( Item* zItem, Framework::StreamReader* zReader) const { ItemType::loadSuperItem(zItem, zReader); FluidContainerItem* item = dynamic_cast(zItem); if (item) { zReader->lese((char*)&item->fluidTypeId, 4); zReader->lese((char*)&item->fluidAmount, 4); } else { Framework::Logging::error() << "FluidContainerItemType::loadSuperItem: " "zItem is not a FluidContainerItem"; } } void FluidContainerItemType::saveSuperItem( const Item* zItem, Framework::StreamWriter* zWriter) const { ItemType::saveSuperItem(zItem, zWriter); const FluidContainerItem* item = dynamic_cast(zItem); if (item) { zWriter->schreibe((char*)&item->fluidTypeId, 4); zWriter->schreibe((char*)&item->fluidAmount, 4); } else { Framework::Logging::error() << "FluidContainerItemType::saveSuperItem: " "zItem is not a FluidContainerItem"; } } Item* FluidContainerItemType::createItem() const { Item* result = new FluidContainerItem(getId(), getName()); return result; } ItemSkill* FluidContainerItemType::createDefaultItemSkill() const { return Game::INSTANCE->zTypeRegistry()->fromJson( itemSkillConfig); } void FluidContainerItemType::levelUpItemSkill(ItemSkill* zSkill) const { levelUpRule->applyOn(zSkill); } void FluidContainerItemType::setItemAttribute( Item* zItem, Framework::Text name, Framework::JSON::JSONValue* zValue) const { FluidContainerItem* item = dynamic_cast(zItem); if (!item) { Framework::Logging::error() << "FluidContainerItemType::setItemAttribute: " "zItem is not a FluidContainerItem"; return; } if (name.istGleich("fluidType")) { if (zValue->getType() == Framework::JSON::JSONType::STRING) { int id = ItemType::getTypeId(zValue->asString()->getString()); if (id) { item->fluidTypeId = id; } else { Framework::Logging::error() << "FluidContainerItemType::setItemAttribute: " "'fluidType' is not a valid type name"; } } else { Framework::Logging::error() << "FluidContainerItemType::setItemAttribute: " "'fluidType' is not a string or string"; } } else if (name.istGleich("fluidAmount")) { if (zValue->getType() == Framework::JSON::JSONType::NUMBER) { item->fluidAmount = (int)zValue->asNumber()->getNumber(); } else { Framework::Logging::error() << "FluidContainerItemType::setItemAttribute: " "'fluidAmount' is not a number"; } } else { ItemType::setItemAttribute(zItem, name, zValue); } } void FluidContainerItemType::addItemAttributes( Item* zItem, Framework::JSON::JSONObject* zItemObjet) const { FluidContainerItem* item = dynamic_cast(zItem); if (!item) { Framework::Logging::error() << "FluidContainerItemType::addItemAttributes: " "zItem is not a FluidContainerItem"; return; } ItemType::addItemAttributes(zItem, zItemObjet); if (item->fluidTypeId) { zItemObjet->addValue("fluidType", new Framework::JSON::JSONString( Game::INSTANCE->zItemType(item->fluidTypeId)->getName())); zItemObjet->addValue( "fluidAmount", new Framework::JSON::JSONNumber(item->fluidAmount)); } } void FluidContainerItemType::setItemSkillConfig( Framework::JSON::JSONObject* itemSkillConfig) { if (this->itemSkillConfig) this->itemSkillConfig->release(); this->itemSkillConfig = itemSkillConfig; } Framework::JSON::JSONObject* FluidContainerItemType::zItemSkillConfig() const { return itemSkillConfig; } void FluidContainerItemType::setLevelUpRule(ItemSkillLevelUpRule* levelUpRule) { if (this->levelUpRule) this->levelUpRule->release(); this->levelUpRule = levelUpRule; } ItemSkillLevelUpRule* FluidContainerItemType::zLevelUpRule() const { return levelUpRule; } void FluidContainerItemType::setMaxFluidAmount(int maxFluidAmount) { this->maxFluidAmount = maxFluidAmount; } int FluidContainerItemType::getMaxFluidAmount() const { return maxFluidAmount; } FluidContainerItemTypeFactory::FluidContainerItemTypeFactory() : ItemTypeFactoryBase() {} FluidContainerItemType* FluidContainerItemTypeFactory::createValue( Framework::JSON::JSONObject* zJson) const { return new FluidContainerItemType(); } void FluidContainerItemTypeFactory::fromJson( FluidContainerItemType* zResult, Framework::JSON::JSONObject* zJson) const { zResult->setItemSkillConfig(zJson->getValue("itemSkill")->asObject()); zResult->setLevelUpRule( Game::INSTANCE->zTypeRegistry()->fromJson( zJson->zValue("levelUpRule"))); zResult->setMaxFluidAmount( (int)zJson->zValue("maxFluidAmount")->asNumber()->getNumber()); ItemTypeFactoryBase::fromJson(zResult, zJson); } void FluidContainerItemTypeFactory::toJson( FluidContainerItemType* zObject, Framework::JSON::JSONObject* zResult) const { zResult->addValue("levelUpRule", Game::INSTANCE->zTypeRegistry()->toJson(zObject->zLevelUpRule())); zResult->addValue("itemSkill", dynamic_cast( zObject->zItemSkillConfig()->getThis())); zResult->addValue("maxFluidAmount", new Framework::JSON::JSONNumber(zObject->getMaxFluidAmount())); ItemTypeFactoryBase::toJson(zObject, zResult); } JSONObjectValidationBuilder* FluidContainerItemTypeFactory::addToValidator( JSONObjectValidationBuilder* builder) const { return ItemTypeFactoryBase::addToValidator( builder ->withRequiredAttribute("levelUpRule", Game::INSTANCE->zTypeRegistry() ->getValidator()) ->withRequiredAttribute("itemSkill", Game::INSTANCE->zTypeRegistry()->getValidator()) ->withRequiredNumber("maxFluidAmount") ->whichIsGreaterThen(0) ->withDefault(1000.0) ->finishNumber()); } Framework::Text FluidContainerItemTypeFactory::getTypeToken() const { return "fluidContainer"; }