#include "FluidContainer.h" #include #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( BlockFilter* targetFilter, float staminaCost, float staminaCostDevider, float staminaCostDeviderPerLevel, int cooldownTicks, float xpGain) : targetFilter(targetFilter), staminaCost(staminaCost), staminaCostDevider(staminaCostDevider), staminaCostDeviderPerLevel(staminaCostDeviderPerLevel), cooldownTicks(cooldownTicks), xpGain(xpGain) {} FluidContainerItemSkillConfig::~FluidContainerItemSkillConfig() { if (targetFilter) targetFilter->release(); } BlockFilter* FluidContainerItemSkillConfig::zTargetFilter() const { return targetFilter; } float FluidContainerItemSkillConfig::getStaminaCost() const { return staminaCost; } float FluidContainerItemSkillConfig::getStaminaCostDevider() const { return staminaCostDevider; } float FluidContainerItemSkillConfig::getStaminaCostDeviderPerLevel() const { return staminaCostDeviderPerLevel; } int FluidContainerItemSkillConfig::getCooldownTicks() const { return cooldownTicks; } float FluidContainerItemSkillConfig::getXpGain() const { return xpGain; } FluidContainerItemSkillConfigFactory::FluidContainerItemSkillConfigFactory() : TypeFactory() {} FluidContainerItemSkillConfig* FluidContainerItemSkillConfigFactory::fromJson( Framework::JSON::JSONValue* zJson) const { return new FluidContainerItemSkillConfig( Game::INSTANCE->zTypeRegistry()->fromJson( zJson->asObject()->zValue("targetFilter")), (float)zJson->asObject() ->zValue("staminaCost") ->asNumber() ->getNumber(), (float)zJson->asObject() ->zValue("staminaCostDevider") ->asNumber() ->getNumber(), (float)zJson->asObject() ->zValue("staminaCostDeviderPerLevel") ->asNumber() ->getNumber(), (int)zJson->asObject() ->zValue("cooldownTicks") ->asNumber() ->getNumber(), (float)zJson->asObject()->zValue("xpGain")->asNumber()->getNumber()); } Framework::JSON::JSONValue* FluidContainerItemSkillConfigFactory::toJson( FluidContainerItemSkillConfig* zObject) const { Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject(); result->addValue("targetFilter", Game::INSTANCE->zTypeRegistry()->toJson(zObject->zTargetFilter())); result->addValue("staminaCost", new Framework::JSON::JSONNumber(zObject->getStaminaCost())); result->addValue("staminaCostDevider", new Framework::JSON::JSONNumber(zObject->getStaminaCostDevider())); result->addValue("staminaCostDeviderPerLevel", new Framework::JSON::JSONNumber( zObject->getStaminaCostDeviderPerLevel())); result->addValue("cooldownTicks", new Framework::JSON::JSONNumber(zObject->getCooldownTicks())); result->addValue( "xpGain", new Framework::JSON::JSONNumber(zObject->getXpGain())); return result; } Framework::JSON::Validator::JSONValidator* FluidContainerItemSkillConfigFactory::getValidator() const { return Framework::JSON::Validator::JSONValidator::buildForObject() ->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() ->finishObject(); } FluidContainerItemSkill::FluidContainerItemSkill(float xp, float maxXp, float level, int cooldownTicks, FluidContainerItemSkillConfig* invalidUseConfig, Framework::RCArray configs) : ItemSkill(xp, maxXp, level), cooldownTicks(cooldownTicks), invalidUseConfig(invalidUseConfig), configs(configs) {} 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; } FluidContainerItemSkillConfig* FluidContainerItemSkill::zInvalidUseConfig() const { return invalidUseConfig; } const Framework::RCArray& FluidContainerItemSkill::zConfigs() const { return configs; } FluidContainerItemSkillFactory::FluidContainerItemSkillFactory() {} FluidContainerItemSkill* FluidContainerItemSkillFactory::fromJson( Framework::JSON::JSONObject* zJson) const { Framework::RCArray configs; for (Framework::JSON::JSONValue* configValue : *zJson->zValue("configs")->asArray()) { configs.add(Game::INSTANCE->zTypeRegistry() ->fromJson( configValue->asObject())); } return new FluidContainerItemSkill(0, (float)zJson->zValue("maxXp")->asNumber()->getNumber(), 1, 0, new FluidContainerItemSkillConfig(0, (float)zJson->zValue("invalidUseStaminaCost") ->asNumber() ->getNumber(), (float)zJson->zValue("invalidUseStaminaCostDevider") ->asNumber() ->getNumber(), (float)zJson->zValue("invalidUseStaminaCostDeviderPerLevel") ->asNumber() ->getNumber(), (int)zJson->zValue("invalidUseCooldownTicks") ->asNumber() ->getNumber(), 0), configs); } Framework::JSON::JSONObject* FluidContainerItemSkillFactory::toJson( FluidContainerItemSkill* zObject) const { Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject(); result->addValue( "maxXp", new Framework::JSON::JSONNumber(zObject->getMaxXp())); result->addValue("invalidUseStaminaCost", new Framework::JSON::JSONNumber( zObject->zInvalidUseConfig()->getStaminaCost())); result->addValue("invalidUseStaminaCostDevider", new Framework::JSON::JSONNumber( zObject->zInvalidUseConfig()->getStaminaCostDevider())); result->addValue("invalidUseStaminaCostDeviderPerLevel", new Framework::JSON::JSONNumber( zObject->zInvalidUseConfig()->getStaminaCostDeviderPerLevel())); result->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)); } result->addValue("configs", configs); return result; } Framework::JSON::Validator::JSONValidator* FluidContainerItemSkillFactory::getValidator( Framework::JSON::Validator::ObjectValidationBuilder< Framework::JSON::Validator::JSONValidator>* builder) const { return builder->withRequiredNumber("invalidUseStaminaCost") ->whichIsGreaterOrEqual(0.0) ->withDefault(0.5) ->finishNumber() ->withRequiredNumber("invalidUseStaminaCostDevider") ->whichIsGreaterOrEqual(0.0) ->withDefault(0.9) ->finishNumber() ->withRequiredNumber("sinvalidUseStaminaCostDeviderPerLevel") ->whichIsGreaterOrEqual(0.0) ->withDefault(0.1) ->finishNumber() ->withRequiredNumber("invalidUseCooldownTicks") ->whichIsGreaterOrEqual(0) ->withDefault(10) ->finishNumber() ->withRequiredNumber("maxXp") ->whichIsGreaterOrEqual(0) ->withDefault(10) ->finishNumber() ->withRequiredArray("configs") ->addAcceptedTypeInArray( Game::INSTANCE->zTypeRegistry() ->getValidator()) ->finishArray() ->finishObject(); } Framework::Text FluidContainerItemSkillFactory::getTypeToken() const { return "fluidGathering"; } FluidContainerItemType::FluidContainerItemType(Framework::Text name, ModelInfo* model, Framework::JSON::JSONObject* itemSkillConfig, ItemSkillLevelUpRule* levelUpRule, int maxFluidAmount, int maxStackSize, Framework::RCArray groups) : ItemType(name, model, maxStackSize, groups), itemSkillConfig(itemSkillConfig), levelUpRule(levelUpRule), maxFluidAmount(maxFluidAmount) {} FluidContainerItemType::~FluidContainerItemType() { itemSkillConfig->release(); 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 { std::cout << "ERROR: FluidContainerItemType::loadSuperItem: " "zItem is not a FluidContainerItem\n"; } } 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 { std::cout << "ERROR: FluidContainerItemType::saveSuperItem: " "zItem is not a FluidContainerItem\n"; } } 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) { std::cout << "ERROR: FluidContainerItemType::setItemAttribute: " "zItem is not a FluidContainerItem\n"; 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 { std::cout << "ERROR: FluidContainerItemType::setItemAttribute: " "'fluidType' is not a valid type name\n"; } } else { std::cout << "ERROR: FluidContainerItemType::setItemAttribute: " "'fluidType' is not a string or string\n"; } } else if (name.istGleich("fluidAmount")) { if (zValue->getType() == Framework::JSON::JSONType::NUMBER) { item->fluidAmount = (int)zValue->asNumber()->getNumber(); } else { std::cout << "ERROR: FluidContainerItemType::setItemAttribute: " "'fluidAmount' is not a number\n"; } } else { ItemType::setItemAttribute(zItem, name, zValue); } } void FluidContainerItemType::addItemAttributes( Item* zItem, Framework::JSON::JSONObject* zItemObjet) const { FluidContainerItem* item = dynamic_cast(zItem); if (!item) { std::cout << "ERROR: FluidContainerItemType::addItemAttributes: " "zItem is not a FluidContainerItem\n"; 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)); } } Framework::JSON::JSONObject* FluidContainerItemType::zItemSkillConfig() const { return itemSkillConfig; } ItemSkillLevelUpRule* FluidContainerItemType::zLevelUpRule() const { return levelUpRule; } int FluidContainerItemType::getMaxFluidAmount() const { return maxFluidAmount; } FluidContainerItemType* FluidContainerItemType::setMaxFluidAmount( int maxFluidAmount) { this->maxFluidAmount = maxFluidAmount; return this; } FluidContainerItemTypeFactory::FluidContainerItemTypeFactory() : SubTypeFactory() {} FluidContainerItemType* FluidContainerItemTypeFactory::fromJson( Framework::JSON::JSONObject* zJson) const { Framework::RCArray groups; for (Framework::JSON::JSONValue* group : *zJson->zValue("groupNames")->asArray()) { groups.add(new Framework::Text(group->asString()->getString())); } return new FluidContainerItemType( zJson->zValue("name")->asString()->getString(), Game::INSTANCE->zTypeRegistry()->fromJson( zJson->zValue("model")), zJson->getValue("itemSkill")->asObject(), Game::INSTANCE->zTypeRegistry()->fromJson( zJson->zValue("levelUpRule")), (int)zJson->zValue("maxFluidAmount")->asNumber()->getNumber(), (int)zJson->zValue("maxStack")->asNumber()->getNumber(), groups); } Framework::JSON::JSONObject* FluidContainerItemTypeFactory::toJson( FluidContainerItemType* zObject) const { Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject(); result->addValue( "name", new Framework::JSON::JSONString(zObject->getName())); result->addValue( "model", Game::INSTANCE->zTypeRegistry()->toJson(zObject->zModel())); result->addValue("levelUpRule", Game::INSTANCE->zTypeRegistry()->toJson(zObject->zLevelUpRule())); result->addValue("itemSkill", dynamic_cast( zObject->zItemSkillConfig()->getThis())); result->addValue("maxFluidAmount", new Framework::JSON::JSONNumber(zObject->getMaxFluidAmount())); result->addValue("maxStack", new Framework::JSON::JSONNumber(zObject->getMaxStackSize())); Framework::JSON::JSONArray* groups = new Framework::JSON::JSONArray(); for (Framework::Text* group : zObject->getGroups()) { groups->addValue(new Framework::JSON::JSONString(group->getText())); } result->addValue("groupNames", groups); return result; } Framework::JSON::Validator::JSONValidator* FluidContainerItemTypeFactory::getValidator( Framework::JSON::Validator::ObjectValidationBuilder< Framework::JSON::Validator::JSONValidator>* builder) const { return builder->withRequiredString("name") ->finishString() ->withRequiredAttribute( "model", Game::INSTANCE->zTypeRegistry()->getValidator()) ->withRequiredAttribute("levelUpRule", Game::INSTANCE->zTypeRegistry() ->getValidator()) ->withRequiredAttribute("itemSkill", Game::INSTANCE->zTypeRegistry()->getValidator()) ->withRequiredNumber("maxFluidAmount") ->whichIsGreaterThen(0) ->withDefault(1000.0) ->finishNumber() ->withRequiredNumber("maxStack") ->withDefault(50.0) ->whichIsGreaterOrEqual(1.0) ->finishNumber() ->withRequiredArray("groupNames") ->addAcceptedStringInArray() ->finishString() ->withDefault(new Framework::JSON::JSONArray()) ->finishArray() ->finishObject(); } Framework::Text FluidContainerItemTypeFactory::getTypeToken() const { return "fluidContainer"; }