/* * AObjectTypeHandler.cpp, part of VCMI engine * * Authors: listed in file AUTHORS in main folder * * License: GNU General Public License v2.0 or later * Full text of license available in license.txt file, in main folder * */ #include "StdInc.h" #include "AObjectTypeHandler.h" #include "IObjectInfo.h" #include "../CGeneralTextHandler.h" #include "../VCMI_Lib.h" #include "../mapObjects/CGObjectInstance.h" #include "../mapObjects/ObjectTemplate.h" VCMI_LIB_NAMESPACE_BEGIN std::string AObjectTypeHandler::getJsonKey() const { return modScope + ':' + subTypeName; } si32 AObjectTypeHandler::getIndex() const { return type; } si32 AObjectTypeHandler::getSubIndex() const { return subtype; } std::string AObjectTypeHandler::getTypeName() const { return typeName; } std::string AObjectTypeHandler::getSubTypeName() const { return subTypeName; } static ui32 loadJsonOrMax(const JsonNode & input) { if (input.isNull()) return std::numeric_limits::max(); else return static_cast(input.Float()); } void AObjectTypeHandler::init(const JsonNode & input) { base = input["base"]; if (!input["rmg"].isNull()) { rmgInfo.value = static_cast(input["rmg"]["value"].Float()); const JsonNode & mapLimit = input["rmg"]["mapLimit"]; if (!mapLimit.isNull()) rmgInfo.mapLimit = static_cast(mapLimit.Float()); rmgInfo.zoneLimit = loadJsonOrMax(input["rmg"]["zoneLimit"]); rmgInfo.rarity = static_cast(input["rmg"]["rarity"].Float()); } // else block is not needed - set in constructor for (auto entry : input["templates"].Struct()) { entry.second.setType(JsonNode::JsonType::DATA_STRUCT); JsonUtils::inherit(entry.second, base); auto * tmpl = new ObjectTemplate; tmpl->id = Obj(type); tmpl->subid = subtype; tmpl->stringID = entry.first; // FIXME: create "fullID" - type.object.template? try { tmpl->readJson(entry.second); templates.push_back(std::shared_ptr(tmpl)); } catch (const std::exception & e) { logGlobal->warn("Failed to load terrains for object %s: %s", entry.first, e.what()); } } for(const JsonNode & node : input["sounds"]["ambient"].Vector()) sounds.ambient.push_back(node.String()); for(const JsonNode & node : input["sounds"]["visit"].Vector()) sounds.visit.push_back(node.String()); for(const JsonNode & node : input["sounds"]["removal"].Vector()) sounds.removal.push_back(node.String()); if(input["aiValue"].isNull()) aiValue = std::nullopt; else aiValue = static_cast>(input["aiValue"].Integer()); if(input["battleground"].getType() == JsonNode::JsonType::DATA_STRING) battlefield = input["battleground"].String(); else battlefield = std::nullopt; initTypeData(input); } bool AObjectTypeHandler::objectFilter(const CGObjectInstance * obj, std::shared_ptr tmpl) const { return false; // by default there are no overrides } void AObjectTypeHandler::preInitObject(CGObjectInstance * obj) const { obj->ID = Obj(type); obj->subID = subtype; obj->typeName = typeName; obj->subTypeName = subTypeName; } void AObjectTypeHandler::initTypeData(const JsonNode & input) { // empty implementation for overrides } bool AObjectTypeHandler::hasNameTextID() const { return false; } std::string AObjectTypeHandler::getNameTextID() const { return TextIdentifier("mapObject", modScope, typeName, subTypeName, "name").get(); } std::string AObjectTypeHandler::getNameTranslated() const { return VLC->generaltexth->translate(getNameTextID()); } SObjectSounds AObjectTypeHandler::getSounds() const { return sounds; } void AObjectTypeHandler::addTemplate(const std::shared_ptr & templ) { templates.push_back(templ); } void AObjectTypeHandler::addTemplate(JsonNode config) { config.setType(JsonNode::JsonType::DATA_STRUCT); // ensure that input is not null JsonUtils::inherit(config, base); auto * tmpl = new ObjectTemplate; tmpl->id = Obj(type); tmpl->subid = subtype; tmpl->stringID.clear(); // TODO? tmpl->readJson(config); templates.emplace_back(tmpl); } std::vector> AObjectTypeHandler::getTemplates() const { return templates; } BattleField AObjectTypeHandler::getBattlefield() const { return battlefield ? BattleField::fromString(battlefield.value()) : BattleField::NONE; } std::vector>AObjectTypeHandler::getTemplates(TerrainId terrainType) const { std::vector> templates = getTemplates(); std::vector> filtered; const auto cfun = [&](const std::shared_ptr & obj) { return obj->canBePlacedAt(terrainType); }; std::copy_if(templates.begin(), templates.end(), std::back_inserter(filtered), cfun); // H3 defines allowed terrains in a weird way - artifacts, monsters and resources have faulty masks here // Perhaps we should re-define faulty templates and remove this workaround (already done for resources) if (type == Obj::ARTIFACT || type == Obj::MONSTER) return templates; else return filtered; } std::shared_ptr AObjectTypeHandler::getOverride(TerrainId terrainType, const CGObjectInstance * object) const { std::vector> ret = getTemplates(terrainType); for (const auto & tmpl: ret) { if (objectFilter(object, tmpl)) return tmpl; } return std::shared_ptr(); //empty } const RandomMapInfo & AObjectTypeHandler::getRMGInfo() { return rmgInfo; } std::optional AObjectTypeHandler::getAiValue() const { return aiValue; } bool AObjectTypeHandler::isStaticObject() { return false; // most of classes are not static } void AObjectTypeHandler::afterLoadFinalization() { } std::unique_ptr AObjectTypeHandler::getObjectInfo(std::shared_ptr tmpl) const { return nullptr; } VCMI_LIB_NAMESPACE_END