From 76bf5351c6649eed80237319a8e5d8cd5178c5c5 Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Thu, 5 Jun 2014 19:57:43 +0300 Subject: [PATCH] Line endings are now unix-style --- lib/mapObjects/CObjectClassesHandler.cpp | 666 ++++++------ lib/mapObjects/CObjectClassesHandler.h | 348 +++---- lib/mapObjects/CObjectHandler.cpp | 1212 +++++++++++----------- lib/mapObjects/CObjectHandler.h | 408 ++++---- 4 files changed, 1317 insertions(+), 1317 deletions(-) diff --git a/lib/mapObjects/CObjectClassesHandler.cpp b/lib/mapObjects/CObjectClassesHandler.cpp index 86d20d519..cbb1233dd 100644 --- a/lib/mapObjects/CObjectClassesHandler.cpp +++ b/lib/mapObjects/CObjectClassesHandler.cpp @@ -1,333 +1,333 @@ -#include "StdInc.h" -#include "CObjectClassesHandler.h" - -#include "filesystem/Filesystem.h" -#include "filesystem/CBinaryReader.h" -#include "../lib/VCMI_Lib.h" -#include "GameConstants.h" -#include "StringConstants.h" -#include "CGeneralTextHandler.h" -#include "CModHandler.h" -#include "JsonNode.h" - -#include "CRewardableConstructor.h" -#include "MapObjects.h" - -/* - * CObjectClassesHandler.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 - * - */ - -CObjectClassesHandler::CObjectClassesHandler() -{ -#define SET_HANDLER_CLASS(STRING, CLASSNAME) handlerConstructors[STRING] = std::make_shared; -#define SET_HANDLER(STRING, TYPENAME) handlerConstructors[STRING] = std::make_shared > - - // list of all known handlers, hardcoded for now since the only way to add new objects is via C++ code - //WARNING: should be in sync with registerTypesMapObjectTypes function - SET_HANDLER_CLASS("configurable", CRewardableConstructor); - - SET_HANDLER("", CGObjectInstance); - SET_HANDLER("generic", CGObjectInstance); - - SET_HANDLER("market", CGMarket); - SET_HANDLER("bank", CBank); - SET_HANDLER("cartographer", CCartographer); - SET_HANDLER("artifact", CGArtifact); - SET_HANDLER("blackMarket", CGBlackMarket); - SET_HANDLER("boat", CGBoat); - SET_HANDLER("bonusingObject", CGBonusingObject); - SET_HANDLER("borderGate", CGBorderGate); - SET_HANDLER("borderGuard", CGBorderGuard); - SET_HANDLER("monster", CGCreature); - SET_HANDLER("denOfThieves", CGDenOfthieves); - SET_HANDLER("dwelling", CGDwelling); - SET_HANDLER("event", CGEvent); - SET_HANDLER("garrison", CGGarrison); - SET_HANDLER("hero", CGHeroInstance); - SET_HANDLER("heroPlaceholder", CGHeroPlaceholder); - SET_HANDLER("keymaster", CGKeymasterTent); - SET_HANDLER("lighthouse", CGLighthouse); - SET_HANDLER("magi", CGMagi); - SET_HANDLER("magicSpring", CGMagicSpring); - SET_HANDLER("magicWell", CGMagicWell); - SET_HANDLER("market", CGMarket); - SET_HANDLER("mine", CGMine); - SET_HANDLER("obelisk", CGObelisk); - SET_HANDLER("observatory", CGObservatory); - SET_HANDLER("onceVisitable", CGOnceVisitable); - SET_HANDLER("pandora", CGPandoraBox); - SET_HANDLER("pickable", CGPickable); - SET_HANDLER("pyramid", CGPyramid); - SET_HANDLER("questGuard", CGQuestGuard); - SET_HANDLER("resource", CGResource); - SET_HANDLER("scholar", CGScholar); - SET_HANDLER("seerHut", CGSeerHut); - SET_HANDLER("shipyard", CGShipyard); - SET_HANDLER("shrine", CGShrine); - SET_HANDLER("sign", CGSignBottle); - SET_HANDLER("siren", CGSirens); - SET_HANDLER("teleport", CGTeleport); - SET_HANDLER("town", CGTownInstance); - SET_HANDLER("university", CGUniversity); - SET_HANDLER("oncePerHero", CGVisitableOPH); - SET_HANDLER("oncePerWeek", CGVisitableOPW); - SET_HANDLER("witch", CGWitchHut); - -#undef SET_HANDLER_CLASS -#undef SET_HANDLER -} - -template -void readTextFile(Container & objects, std::string path) -{ - CLegacyConfigParser parser(path); - size_t totalNumber = parser.readNumber(); // first line contains number of objects to read and nothing else - parser.endLine(); - - for (size_t i=0; i CObjectClassesHandler::loadLegacyData(size_t dataSize) -{ - readTextFile(legacyTemplates, "Data/Objects.txt"); - readTextFile(legacyTemplates, "Data/Heroes.txt"); - - std::vector ret(dataSize);// create storage for 256 objects - assert(dataSize == 256); - - CLegacyConfigParser parser("Data/ObjNames.txt"); - for (size_t i=0; i<256; i++) - { - ret[i]["name"].String() = parser.readString(); - parser.endLine(); - } - return ret; -} - -/// selects preferred ID (or subID) for new object -template -si32 selectNextID(const JsonNode & fixedID, const Map & map, si32 defaultID) -{ - if (!fixedID.isNull() && fixedID.Float() < defaultID) - return fixedID.Float(); // H3M object with fixed ID - - if (map.empty()) - return defaultID; // no objects loaded, keep gap for H3M objects - if (map.rbegin()->first > defaultID) - return map.rbegin()->first + 1; // some modded objects loaded, return next available - - return defaultID; // some H3M objects loaded, first modded found -} - -void CObjectClassesHandler::loadObjectEntry(const JsonNode & entry, ObjectContainter * obj) -{ - auto handler = handlerConstructors.at(obj->handlerName)(); - handler->init(entry); - - si32 id = selectNextID(entry["index"], obj->objects, 1000); - handler->setType(obj->id, id); - - if (handler->getTemplates().empty()) - { - auto range = legacyTemplates.equal_range(std::make_pair(obj->id, id)); - for (auto & templ : boost::make_iterator_range(range.first, range.second)) - { - handler->addTemplate(templ.second); - } - legacyTemplates.erase(range.first, range.second); - } - - obj->objects[id] = handler; -} - -CObjectClassesHandler::ObjectContainter * CObjectClassesHandler::loadFromJson(const JsonNode & json) -{ - auto obj = new ObjectContainter(); - obj->name = json["name"].String(); - obj->handlerName = json["handler"].String(); - obj->base = json["base"]; // FIXME: when this data will be actually merged? - obj->id = selectNextID(json["index"], objects, 256); - for (auto entry : json["types"].Struct()) - { - loadObjectEntry(entry.second, obj); - } - return obj; -} - -void CObjectClassesHandler::loadObject(std::string scope, std::string name, const JsonNode & data) -{ - auto object = loadFromJson(data); - objects[object->id] = object; - - VLC->modh->identifiers.registerObject(scope, "object", name, object->id); -} - -void CObjectClassesHandler::loadObject(std::string scope, std::string name, const JsonNode & data, size_t index) -{ - auto object = loadFromJson(data); - - assert(objects[index] == nullptr); // ensure that this id was not loaded before - objects[index] = object; - - VLC->modh->identifiers.registerObject(scope, "object", name, object->id); -} - -void CObjectClassesHandler::createObject(std::string name, JsonNode config, si32 ID, boost::optional subID) -{ - config.setType(JsonNode::DATA_STRUCT); // ensure that input is not NULL - assert(objects.count(ID)); - if (subID) - { - assert(objects.at(ID)->objects.count(subID.get()) == 0); - assert(config["index"].isNull()); - config["index"].Float() = subID.get(); - } - - JsonUtils::inherit(config, objects.at(ID)->base); - - loadObjectEntry(config, objects[ID]); -} - -void CObjectClassesHandler::eraseObject(si32 ID, si32 subID) -{ - assert(objects.count(ID)); - assert(objects.at(ID)->objects.count(subID)); - objects.at(ID)->objects.erase(subID); -} - -std::vector CObjectClassesHandler::getDefaultAllowed() const -{ - return std::vector(); //TODO? -} - -TObjectTypeHandler CObjectClassesHandler::getHandlerFor(si32 type, si32 subtype) const -{ - if (objects.count(type)) - { - if (objects.at(type)->objects.count(subtype)) - return objects.at(type)->objects.at(subtype); - } - logGlobal->errorStream() << "Failed to find object of type " << type << ":" << subtype; - assert(0); // FIXME: throw error? - return nullptr; -} - -void CObjectClassesHandler::beforeValidate(JsonNode & object) -{ - for (auto & entry : object["types"].Struct()) - { - JsonUtils::inherit(entry.second, object["base"]); - for (auto & templ : entry.second["templates"].Struct()) - { - JsonUtils::inherit(templ.second, entry.second["base"]); - } - } -} - -void CObjectClassesHandler::afterLoadFinalization() -{ - legacyTemplates.clear(); // whatever left there is no longer needed - for (auto entry : objects) - { - for (auto obj : entry.second->objects) - { - if (obj.second->getTemplates().empty()) - logGlobal->warnStream() << "No templates found for " << entry.first << ":" << obj.first; - } - } -} - -std::string CObjectClassesHandler::getObjectName(si32 type) const -{ - assert(objects.count(type)); - return objects.at(type)->name; -} - -void AObjectTypeHandler::setType(si32 type, si32 subtype) -{ - this->type = type; - this->subtype = subtype; -} - -void AObjectTypeHandler::init(const JsonNode & input) -{ - base = input["base"]; - for (auto entry : input["templates"].Struct()) - { - entry.second.setType(JsonNode::DATA_STRUCT); - JsonUtils::inherit(entry.second, base); - - ObjectTemplate tmpl; - tmpl.id = Obj(type); - tmpl.subid = subtype; - tmpl.stringID = entry.first; // FIXME: create "fullID" - type.object.template? - tmpl.readJson(entry.second); - templates.push_back(tmpl); - } -} - -bool AObjectTypeHandler::objectFilter(const CGObjectInstance *, const ObjectTemplate &) const -{ - return true; // by default - accept all. -} - -void AObjectTypeHandler::addTemplate(ObjectTemplate templ) -{ - templ.id = Obj(type); - templ.subid = subtype; - templates.push_back(templ); -} - -void AObjectTypeHandler::addTemplate(JsonNode config) -{ - config.setType(JsonNode::DATA_STRUCT); // ensure that input is not null - JsonUtils::inherit(config, base); - ObjectTemplate tmpl; - tmpl.id = Obj(type); - tmpl.subid = subtype; - tmpl.stringID = ""; // TODO? - tmpl.readJson(config); - addTemplate(tmpl); -} - -std::vector AObjectTypeHandler::getTemplates() const -{ - return templates; -} - -std::vector AObjectTypeHandler::getTemplates(si32 terrainType) const// FIXME: replace with ETerrainType -{ - std::vector ret = getTemplates(); - std::vector filtered; - - std::copy_if(ret.begin(), ret.end(), std::back_inserter(filtered), [&](const ObjectTemplate & obj) - { - return obj.canBePlacedAt(ETerrainType(terrainType)); - }); - // it is possible that there are no templates usable on specific terrain. In this case - return list before filtering - return filtered.empty() ? ret : filtered; -} - -boost::optional AObjectTypeHandler::getOverride(si32 terrainType, const CGObjectInstance * object) const -{ - std::vector ret = getTemplates(terrainType); - for (auto & tmpl : ret) - { - if (objectFilter(object, tmpl)) - return tmpl; - } - return boost::optional(); -} +#include "StdInc.h" +#include "CObjectClassesHandler.h" + +#include "filesystem/Filesystem.h" +#include "filesystem/CBinaryReader.h" +#include "../lib/VCMI_Lib.h" +#include "GameConstants.h" +#include "StringConstants.h" +#include "CGeneralTextHandler.h" +#include "CModHandler.h" +#include "JsonNode.h" + +#include "CRewardableConstructor.h" +#include "MapObjects.h" + +/* + * CObjectClassesHandler.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 + * + */ + +CObjectClassesHandler::CObjectClassesHandler() +{ +#define SET_HANDLER_CLASS(STRING, CLASSNAME) handlerConstructors[STRING] = std::make_shared; +#define SET_HANDLER(STRING, TYPENAME) handlerConstructors[STRING] = std::make_shared > + + // list of all known handlers, hardcoded for now since the only way to add new objects is via C++ code + //WARNING: should be in sync with registerTypesMapObjectTypes function + SET_HANDLER_CLASS("configurable", CRewardableConstructor); + + SET_HANDLER("", CGObjectInstance); + SET_HANDLER("generic", CGObjectInstance); + + SET_HANDLER("market", CGMarket); + SET_HANDLER("bank", CBank); + SET_HANDLER("cartographer", CCartographer); + SET_HANDLER("artifact", CGArtifact); + SET_HANDLER("blackMarket", CGBlackMarket); + SET_HANDLER("boat", CGBoat); + SET_HANDLER("bonusingObject", CGBonusingObject); + SET_HANDLER("borderGate", CGBorderGate); + SET_HANDLER("borderGuard", CGBorderGuard); + SET_HANDLER("monster", CGCreature); + SET_HANDLER("denOfThieves", CGDenOfthieves); + SET_HANDLER("dwelling", CGDwelling); + SET_HANDLER("event", CGEvent); + SET_HANDLER("garrison", CGGarrison); + SET_HANDLER("hero", CGHeroInstance); + SET_HANDLER("heroPlaceholder", CGHeroPlaceholder); + SET_HANDLER("keymaster", CGKeymasterTent); + SET_HANDLER("lighthouse", CGLighthouse); + SET_HANDLER("magi", CGMagi); + SET_HANDLER("magicSpring", CGMagicSpring); + SET_HANDLER("magicWell", CGMagicWell); + SET_HANDLER("market", CGMarket); + SET_HANDLER("mine", CGMine); + SET_HANDLER("obelisk", CGObelisk); + SET_HANDLER("observatory", CGObservatory); + SET_HANDLER("onceVisitable", CGOnceVisitable); + SET_HANDLER("pandora", CGPandoraBox); + SET_HANDLER("pickable", CGPickable); + SET_HANDLER("pyramid", CGPyramid); + SET_HANDLER("questGuard", CGQuestGuard); + SET_HANDLER("resource", CGResource); + SET_HANDLER("scholar", CGScholar); + SET_HANDLER("seerHut", CGSeerHut); + SET_HANDLER("shipyard", CGShipyard); + SET_HANDLER("shrine", CGShrine); + SET_HANDLER("sign", CGSignBottle); + SET_HANDLER("siren", CGSirens); + SET_HANDLER("teleport", CGTeleport); + SET_HANDLER("town", CGTownInstance); + SET_HANDLER("university", CGUniversity); + SET_HANDLER("oncePerHero", CGVisitableOPH); + SET_HANDLER("oncePerWeek", CGVisitableOPW); + SET_HANDLER("witch", CGWitchHut); + +#undef SET_HANDLER_CLASS +#undef SET_HANDLER +} + +template +void readTextFile(Container & objects, std::string path) +{ + CLegacyConfigParser parser(path); + size_t totalNumber = parser.readNumber(); // first line contains number of objects to read and nothing else + parser.endLine(); + + for (size_t i=0; i CObjectClassesHandler::loadLegacyData(size_t dataSize) +{ + readTextFile(legacyTemplates, "Data/Objects.txt"); + readTextFile(legacyTemplates, "Data/Heroes.txt"); + + std::vector ret(dataSize);// create storage for 256 objects + assert(dataSize == 256); + + CLegacyConfigParser parser("Data/ObjNames.txt"); + for (size_t i=0; i<256; i++) + { + ret[i]["name"].String() = parser.readString(); + parser.endLine(); + } + return ret; +} + +/// selects preferred ID (or subID) for new object +template +si32 selectNextID(const JsonNode & fixedID, const Map & map, si32 defaultID) +{ + if (!fixedID.isNull() && fixedID.Float() < defaultID) + return fixedID.Float(); // H3M object with fixed ID + + if (map.empty()) + return defaultID; // no objects loaded, keep gap for H3M objects + if (map.rbegin()->first > defaultID) + return map.rbegin()->first + 1; // some modded objects loaded, return next available + + return defaultID; // some H3M objects loaded, first modded found +} + +void CObjectClassesHandler::loadObjectEntry(const JsonNode & entry, ObjectContainter * obj) +{ + auto handler = handlerConstructors.at(obj->handlerName)(); + handler->init(entry); + + si32 id = selectNextID(entry["index"], obj->objects, 1000); + handler->setType(obj->id, id); + + if (handler->getTemplates().empty()) + { + auto range = legacyTemplates.equal_range(std::make_pair(obj->id, id)); + for (auto & templ : boost::make_iterator_range(range.first, range.second)) + { + handler->addTemplate(templ.second); + } + legacyTemplates.erase(range.first, range.second); + } + + obj->objects[id] = handler; +} + +CObjectClassesHandler::ObjectContainter * CObjectClassesHandler::loadFromJson(const JsonNode & json) +{ + auto obj = new ObjectContainter(); + obj->name = json["name"].String(); + obj->handlerName = json["handler"].String(); + obj->base = json["base"]; // FIXME: when this data will be actually merged? + obj->id = selectNextID(json["index"], objects, 256); + for (auto entry : json["types"].Struct()) + { + loadObjectEntry(entry.second, obj); + } + return obj; +} + +void CObjectClassesHandler::loadObject(std::string scope, std::string name, const JsonNode & data) +{ + auto object = loadFromJson(data); + objects[object->id] = object; + + VLC->modh->identifiers.registerObject(scope, "object", name, object->id); +} + +void CObjectClassesHandler::loadObject(std::string scope, std::string name, const JsonNode & data, size_t index) +{ + auto object = loadFromJson(data); + + assert(objects[index] == nullptr); // ensure that this id was not loaded before + objects[index] = object; + + VLC->modh->identifiers.registerObject(scope, "object", name, object->id); +} + +void CObjectClassesHandler::createObject(std::string name, JsonNode config, si32 ID, boost::optional subID) +{ + config.setType(JsonNode::DATA_STRUCT); // ensure that input is not NULL + assert(objects.count(ID)); + if (subID) + { + assert(objects.at(ID)->objects.count(subID.get()) == 0); + assert(config["index"].isNull()); + config["index"].Float() = subID.get(); + } + + JsonUtils::inherit(config, objects.at(ID)->base); + + loadObjectEntry(config, objects[ID]); +} + +void CObjectClassesHandler::eraseObject(si32 ID, si32 subID) +{ + assert(objects.count(ID)); + assert(objects.at(ID)->objects.count(subID)); + objects.at(ID)->objects.erase(subID); +} + +std::vector CObjectClassesHandler::getDefaultAllowed() const +{ + return std::vector(); //TODO? +} + +TObjectTypeHandler CObjectClassesHandler::getHandlerFor(si32 type, si32 subtype) const +{ + if (objects.count(type)) + { + if (objects.at(type)->objects.count(subtype)) + return objects.at(type)->objects.at(subtype); + } + logGlobal->errorStream() << "Failed to find object of type " << type << ":" << subtype; + assert(0); // FIXME: throw error? + return nullptr; +} + +void CObjectClassesHandler::beforeValidate(JsonNode & object) +{ + for (auto & entry : object["types"].Struct()) + { + JsonUtils::inherit(entry.second, object["base"]); + for (auto & templ : entry.second["templates"].Struct()) + { + JsonUtils::inherit(templ.second, entry.second["base"]); + } + } +} + +void CObjectClassesHandler::afterLoadFinalization() +{ + legacyTemplates.clear(); // whatever left there is no longer needed + for (auto entry : objects) + { + for (auto obj : entry.second->objects) + { + if (obj.second->getTemplates().empty()) + logGlobal->warnStream() << "No templates found for " << entry.first << ":" << obj.first; + } + } +} + +std::string CObjectClassesHandler::getObjectName(si32 type) const +{ + assert(objects.count(type)); + return objects.at(type)->name; +} + +void AObjectTypeHandler::setType(si32 type, si32 subtype) +{ + this->type = type; + this->subtype = subtype; +} + +void AObjectTypeHandler::init(const JsonNode & input) +{ + base = input["base"]; + for (auto entry : input["templates"].Struct()) + { + entry.second.setType(JsonNode::DATA_STRUCT); + JsonUtils::inherit(entry.second, base); + + ObjectTemplate tmpl; + tmpl.id = Obj(type); + tmpl.subid = subtype; + tmpl.stringID = entry.first; // FIXME: create "fullID" - type.object.template? + tmpl.readJson(entry.second); + templates.push_back(tmpl); + } +} + +bool AObjectTypeHandler::objectFilter(const CGObjectInstance *, const ObjectTemplate &) const +{ + return true; // by default - accept all. +} + +void AObjectTypeHandler::addTemplate(ObjectTemplate templ) +{ + templ.id = Obj(type); + templ.subid = subtype; + templates.push_back(templ); +} + +void AObjectTypeHandler::addTemplate(JsonNode config) +{ + config.setType(JsonNode::DATA_STRUCT); // ensure that input is not null + JsonUtils::inherit(config, base); + ObjectTemplate tmpl; + tmpl.id = Obj(type); + tmpl.subid = subtype; + tmpl.stringID = ""; // TODO? + tmpl.readJson(config); + addTemplate(tmpl); +} + +std::vector AObjectTypeHandler::getTemplates() const +{ + return templates; +} + +std::vector AObjectTypeHandler::getTemplates(si32 terrainType) const// FIXME: replace with ETerrainType +{ + std::vector ret = getTemplates(); + std::vector filtered; + + std::copy_if(ret.begin(), ret.end(), std::back_inserter(filtered), [&](const ObjectTemplate & obj) + { + return obj.canBePlacedAt(ETerrainType(terrainType)); + }); + // it is possible that there are no templates usable on specific terrain. In this case - return list before filtering + return filtered.empty() ? ret : filtered; +} + +boost::optional AObjectTypeHandler::getOverride(si32 terrainType, const CGObjectInstance * object) const +{ + std::vector ret = getTemplates(terrainType); + for (auto & tmpl : ret) + { + if (objectFilter(object, tmpl)) + return tmpl; + } + return boost::optional(); +} diff --git a/lib/mapObjects/CObjectClassesHandler.h b/lib/mapObjects/CObjectClassesHandler.h index 17b072321..9a750e71f 100644 --- a/lib/mapObjects/CObjectClassesHandler.h +++ b/lib/mapObjects/CObjectClassesHandler.h @@ -1,174 +1,174 @@ -#pragma once - -#include "ObjectTemplate.h" - -#include "../GameConstants.h" -#include "../ConstTransitivePtr.h" -#include "../IHandlerBase.h" - -/* - * CObjectClassesHandler.h, 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 - * - */ - -class JsonNode; -class CRandomGenerator; - -class IObjectInfo -{ -public: - virtual bool givesResources() const = 0; - - virtual bool givesExperience() const = 0; - virtual bool givesMana() const = 0; - virtual bool givesMovement() const = 0; - - virtual bool givesPrimarySkills() const = 0; - virtual bool givesSecondarySkills() const = 0; - - virtual bool givesArtifacts() const = 0; - virtual bool givesCreatures() const = 0; - virtual bool givesSpells() const = 0; - - virtual bool givesBonuses() const = 0; -}; - -class CGObjectInstance; - -class AObjectTypeHandler -{ - si32 type; - si32 subtype; - - JsonNode base; /// describes base template - - std::vector templates; -protected: - - virtual bool objectFilter(const CGObjectInstance *, const ObjectTemplate &) const; -public: - virtual ~AObjectTypeHandler(){} - - void setType(si32 type, si32 subtype); - - /// loads templates from Json structure using fields "base" and "templates" - virtual void init(const JsonNode & input); - - void addTemplate(ObjectTemplate templ); - void addTemplate(JsonNode config); - - /// returns all templates, without any filters - std::vector getTemplates() const; - - /// returns all templates that can be placed on specific terrain type - std::vector getTemplates(si32 terrainType) const; - - /// returns preferred template for this object, if present (e.g. one of 3 possible templates for town - village, fort and castle) - /// note that appearance will not be changed - this must be done separately (either by assignment or via pack from server) - boost::optional getOverride(si32 terrainType, const CGObjectInstance * object) const; - - /// Creates object and set up core properties (like ID/subID). Object is NOT initialized - /// to allow creating objects before game start (e.g. map loading) - virtual CGObjectInstance * create(ObjectTemplate tmpl) const = 0; - - /// Configures object properties. Should be re-entrable, resetting state of the object if necessarily - virtual void configureObject(CGObjectInstance * object, CRandomGenerator & rng) const = 0; - - /// Returns object configuration, if available. Othervice returns NULL - virtual const IObjectInfo * getObjectInfo(ObjectTemplate tmpl) const = 0; - - template void serialize(Handler &h, const int version) - { - h & type & subtype & templates; - } -}; - -/// Class that is used for objects that do not have dedicated handler -template -class CDefaultObjectTypeHandler : public AObjectTypeHandler -{ - CGObjectInstance * create(ObjectTemplate tmpl) const - { - auto obj = new ObjectType(); - obj->ID = tmpl.id; - obj->subID = tmpl.subid; - obj->appearance = tmpl; - return obj; - } - - virtual void configureObject(CGObjectInstance * object, CRandomGenerator & rng) const - { - } - - virtual const IObjectInfo * getObjectInfo(ObjectTemplate tmpl) const - { - return nullptr; - } -}; - -typedef std::shared_ptr TObjectTypeHandler; - -class DLL_LINKAGE CObjectClassesHandler : public IHandlerBase -{ - /// Small internal structure that contains information on specific group of objects - /// (creating separate entity is overcomplicating at least at this point) - struct ObjectContainter - { - si32 id; - - std::string name; // human-readable name - std::string handlerName; // ID of handler that controls this object, shoul be determined using hadlerConstructor map - - JsonNode base; - std::map objects; - - template void serialize(Handler &h, const int version) - { - h & base & objects; - } - }; - - typedef std::multimap, ObjectTemplate> TTemplatesContainer; - - /// list of object handlers, each of them handles only one type - std::map objects; - - /// map that is filled during contruction with all known handlers. Not serializeable - std::map > handlerConstructors; - - /// container with H3 templates, used only during loading - TTemplatesContainer legacyTemplates; - - void loadObjectEntry(const JsonNode & entry, ObjectContainter * obj); - ObjectContainter * loadFromJson(const JsonNode & json); -public: - CObjectClassesHandler(); - - std::vector loadLegacyData(size_t dataSize) override; - - void loadObject(std::string scope, std::string name, const JsonNode & data) override; - void loadObject(std::string scope, std::string name, const JsonNode & data, size_t index) override; - - void createObject(std::string name, JsonNode config, si32 ID, boost::optional subID = boost::optional()); - void eraseObject(si32 ID, si32 subID); - - void beforeValidate(JsonNode & object) override; - void afterLoadFinalization() override; - - std::vector getDefaultAllowed() const override; - - /// returns handler for specified object (ID-based). ObjectHandler keeps ownership - TObjectTypeHandler getHandlerFor(si32 type, si32 subtype) const; - - std::string getObjectName(si32 type) const; - - template void serialize(Handler &h, const int version) - { - h & objects; - } -}; +#pragma once + +#include "ObjectTemplate.h" + +#include "../GameConstants.h" +#include "../ConstTransitivePtr.h" +#include "../IHandlerBase.h" + +/* + * CObjectClassesHandler.h, 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 + * + */ + +class JsonNode; +class CRandomGenerator; + +class IObjectInfo +{ +public: + virtual bool givesResources() const = 0; + + virtual bool givesExperience() const = 0; + virtual bool givesMana() const = 0; + virtual bool givesMovement() const = 0; + + virtual bool givesPrimarySkills() const = 0; + virtual bool givesSecondarySkills() const = 0; + + virtual bool givesArtifacts() const = 0; + virtual bool givesCreatures() const = 0; + virtual bool givesSpells() const = 0; + + virtual bool givesBonuses() const = 0; +}; + +class CGObjectInstance; + +class AObjectTypeHandler +{ + si32 type; + si32 subtype; + + JsonNode base; /// describes base template + + std::vector templates; +protected: + + virtual bool objectFilter(const CGObjectInstance *, const ObjectTemplate &) const; +public: + virtual ~AObjectTypeHandler(){} + + void setType(si32 type, si32 subtype); + + /// loads templates from Json structure using fields "base" and "templates" + virtual void init(const JsonNode & input); + + void addTemplate(ObjectTemplate templ); + void addTemplate(JsonNode config); + + /// returns all templates, without any filters + std::vector getTemplates() const; + + /// returns all templates that can be placed on specific terrain type + std::vector getTemplates(si32 terrainType) const; + + /// returns preferred template for this object, if present (e.g. one of 3 possible templates for town - village, fort and castle) + /// note that appearance will not be changed - this must be done separately (either by assignment or via pack from server) + boost::optional getOverride(si32 terrainType, const CGObjectInstance * object) const; + + /// Creates object and set up core properties (like ID/subID). Object is NOT initialized + /// to allow creating objects before game start (e.g. map loading) + virtual CGObjectInstance * create(ObjectTemplate tmpl) const = 0; + + /// Configures object properties. Should be re-entrable, resetting state of the object if necessarily + virtual void configureObject(CGObjectInstance * object, CRandomGenerator & rng) const = 0; + + /// Returns object configuration, if available. Othervice returns NULL + virtual const IObjectInfo * getObjectInfo(ObjectTemplate tmpl) const = 0; + + template void serialize(Handler &h, const int version) + { + h & type & subtype & templates; + } +}; + +/// Class that is used for objects that do not have dedicated handler +template +class CDefaultObjectTypeHandler : public AObjectTypeHandler +{ + CGObjectInstance * create(ObjectTemplate tmpl) const + { + auto obj = new ObjectType(); + obj->ID = tmpl.id; + obj->subID = tmpl.subid; + obj->appearance = tmpl; + return obj; + } + + virtual void configureObject(CGObjectInstance * object, CRandomGenerator & rng) const + { + } + + virtual const IObjectInfo * getObjectInfo(ObjectTemplate tmpl) const + { + return nullptr; + } +}; + +typedef std::shared_ptr TObjectTypeHandler; + +class DLL_LINKAGE CObjectClassesHandler : public IHandlerBase +{ + /// Small internal structure that contains information on specific group of objects + /// (creating separate entity is overcomplicating at least at this point) + struct ObjectContainter + { + si32 id; + + std::string name; // human-readable name + std::string handlerName; // ID of handler that controls this object, shoul be determined using hadlerConstructor map + + JsonNode base; + std::map objects; + + template void serialize(Handler &h, const int version) + { + h & base & objects; + } + }; + + typedef std::multimap, ObjectTemplate> TTemplatesContainer; + + /// list of object handlers, each of them handles only one type + std::map objects; + + /// map that is filled during contruction with all known handlers. Not serializeable + std::map > handlerConstructors; + + /// container with H3 templates, used only during loading + TTemplatesContainer legacyTemplates; + + void loadObjectEntry(const JsonNode & entry, ObjectContainter * obj); + ObjectContainter * loadFromJson(const JsonNode & json); +public: + CObjectClassesHandler(); + + std::vector loadLegacyData(size_t dataSize) override; + + void loadObject(std::string scope, std::string name, const JsonNode & data) override; + void loadObject(std::string scope, std::string name, const JsonNode & data, size_t index) override; + + void createObject(std::string name, JsonNode config, si32 ID, boost::optional subID = boost::optional()); + void eraseObject(si32 ID, si32 subID); + + void beforeValidate(JsonNode & object) override; + void afterLoadFinalization() override; + + std::vector getDefaultAllowed() const override; + + /// returns handler for specified object (ID-based). ObjectHandler keeps ownership + TObjectTypeHandler getHandlerFor(si32 type, si32 subtype) const; + + std::string getObjectName(si32 type) const; + + template void serialize(Handler &h, const int version) + { + h & objects; + } +}; diff --git a/lib/mapObjects/CObjectHandler.cpp b/lib/mapObjects/CObjectHandler.cpp index bd05c0bda..b1289ebfd 100644 --- a/lib/mapObjects/CObjectHandler.cpp +++ b/lib/mapObjects/CObjectHandler.cpp @@ -1,606 +1,606 @@ -/* - * CObjectHandler.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 "CObjectHandler.h" - -#include "NetPacks.h" -#include "CGeneralTextHandler.h" -#include "CHeroHandler.h" -#include "../client/CSoundBase.h" - -#include "CObjectClassesHandler.h" - -using namespace boost::assign; - -IGameCallback * IObjectInterface::cb = nullptr; - -///helpers -static void openWindow(const OpenWindow::EWindow type, const int id1, const int id2 = -1) -{ - OpenWindow ow; - ow.window = type; - ow.id1 = id1; - ow.id2 = id2; - IObjectInterface::cb->sendAndApply(&ow); -} - -static void showInfoDialog(const PlayerColor playerID, const ui32 txtID, const ui16 soundID) -{ - InfoWindow iw; - iw.soundID = soundID; - iw.player = playerID; - iw.text.addTxt(MetaString::ADVOB_TXT,txtID); - IObjectInterface::cb->sendAndApply(&iw); -} - -/*static void showInfoDialog(const ObjectInstanceID heroID, const ui32 txtID, const ui16 soundID) -{ - const PlayerColor playerID = IObjectInterface::cb->getOwner(heroID); - showInfoDialog(playerID,txtID,soundID); -}*/ - -static void showInfoDialog(const CGHeroInstance* h, const ui32 txtID, const ui16 soundID) -{ - const PlayerColor playerID = h->getOwner(); - showInfoDialog(playerID,txtID,soundID); -} - -static std::string & visitedTxt(const bool visited) -{ - int id = visited ? 352 : 353; - return VLC->generaltexth->allTexts[id]; -} - -///IObjectInterface -void IObjectInterface::onHeroVisit(const CGHeroInstance * h) const -{} - -void IObjectInterface::onHeroLeave(const CGHeroInstance * h) const -{} - -void IObjectInterface::newTurn () const -{} - -IObjectInterface::~IObjectInterface() -{} - -IObjectInterface::IObjectInterface() -{} - -void IObjectInterface::initObj() -{} - -void IObjectInterface::setProperty( ui8 what, ui32 val ) -{} - -bool IObjectInterface::wasVisited (PlayerColor player) const -{ - return false; -} -bool IObjectInterface::wasVisited (const CGHeroInstance * h) const -{ - return false; -} - -void IObjectInterface::postInit() -{} - -void IObjectInterface::preInit() -{} - -void IObjectInterface::battleFinished(const CGHeroInstance *hero, const BattleResult &result) const -{} - -void IObjectInterface::blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const -{} - -void IObjectInterface::garrisonDialogClosed(const CGHeroInstance *hero) const -{} - -void IObjectInterface::heroLevelUpDone(const CGHeroInstance *hero) const -{} - -// Bank helper. Find the creature ID and their number, and store the -// result in storage (either guards or reward creatures). -static void readCreatures(const JsonNode &creature, std::vector< std::pair > &storage) -{ - std::pair creInfo = std::make_pair(CreatureID::NONE, 0); - - //TODO: replace numeric id's with mod-friendly string id's - creInfo.second = creature["number"].Float(); - creInfo.first = CreatureID((si32)creature["id"].Float()); - storage.push_back(creInfo); -} - -// Bank helper. Process a bank level. -static void readBankLevel(const JsonNode &level, BankConfig &bc) -{ - int idx; - - bc.chance = level["chance"].Float(); - - for(const JsonNode &creature : level["guards"].Vector()) - { - readCreatures(creature, bc.guards); - } - - bc.upgradeChance = level["upgrade_chance"].Float(); - bc.combatValue = level["combat_value"].Float(); - - bc.resources = Res::ResourceSet(level["reward_resources"]); - - for(const JsonNode &creature : level["reward_creatures"].Vector()) - { - readCreatures(creature, bc.creatures); - } - - bc.artifacts.resize(4); - idx = 0; - for(const JsonNode &artifact : level["reward_artifacts"].Vector()) - { - bc.artifacts[idx] = artifact.Float(); - idx ++; - } - - bc.value = level["value"].Float(); - bc.rewardDifficulty = level["profitability"].Float(); - bc.easiest = level["easiest"].Float(); -} - -CObjectHandler::CObjectHandler() -{ - logGlobal->traceStream() << "\t\tReading cregens "; - - const JsonNode config(ResourceID("config/dwellings.json")); - for(const JsonNode &dwelling : config["dwellings"].Vector()) - { - cregens[dwelling["dwelling"].Float()] = CreatureID((si32)dwelling["creature"].Float()); - } - logGlobal->traceStream() << "\t\tDone loading cregens!"; - - logGlobal->traceStream() << "\t\tReading resources prices "; - const JsonNode config2(ResourceID("config/resources.json")); - for(const JsonNode &price : config2["resources_prices"].Vector()) - { - resVals.push_back(price.Float()); - } - logGlobal->traceStream() << "\t\tDone loading resource prices!"; - - logGlobal->traceStream() << "\t\tReading banks configs"; - const JsonNode config3(ResourceID("config/bankconfig.json")); - int bank_num = 0; - for(const JsonNode &bank : config3["banks"].Vector()) - { - creBanksNames[bank_num] = bank["name"].String(); - - int level_num = 0; - for(const JsonNode &level : bank["levels"].Vector()) - { - banksInfo[bank_num].push_back(new BankConfig); - BankConfig &bc = *banksInfo[bank_num].back(); - bc.level = level_num; - - readBankLevel(level, bc); - level_num ++; - } - - bank_num ++; - } - logGlobal->traceStream() << "\t\tDone loading banks configs"; -} - -CObjectHandler::~CObjectHandler() -{ - for(auto & mapEntry : banksInfo) - { - for(auto & vecEntry : mapEntry.second) - { - vecEntry.dellNull(); - } - } -} - -int CObjectHandler::bankObjToIndex (const CGObjectInstance * obj) -{ - switch (obj->ID) //find appriopriate key - { - case Obj::CREATURE_BANK: - return obj->subID; - case Obj::DERELICT_SHIP: - return 8; - case Obj::DRAGON_UTOPIA: - return 10; - case Obj::CRYPT: - return 9; - case Obj::SHIPWRECK: - return 7; - case Obj::PYRAMID: - return 21; - default: - logGlobal->warnStream() << "Unrecognized Bank indetifier!"; - return 0; - } -} -PlayerColor CGObjectInstance::getOwner() const -{ - //if (state) - // return state->owner; - //else - return tempOwner; //won't have owner -} - -CGObjectInstance::CGObjectInstance(): - pos(-1,-1,-1), - ID(Obj::NO_OBJ), - subID(-1), - tempOwner(PlayerColor::UNFLAGGABLE), - blockVisit(false) -{ -} -CGObjectInstance::~CGObjectInstance() -{ - //if (state) - // delete state; - //state=nullptr; -} - -const std::string & CGObjectInstance::getHoverText() const -{ - return hoverName; -} -void CGObjectInstance::setOwner(PlayerColor ow) -{ - //if (state) - // state->owner = ow; - //else - tempOwner = ow; -} -int CGObjectInstance::getWidth() const//returns width of object graphic in tiles -{ - return appearance.getWidth(); -} -int CGObjectInstance::getHeight() const //returns height of object graphic in tiles -{ - return appearance.getHeight(); -} -bool CGObjectInstance::visitableAt(int x, int y) const //returns true if object is visitable at location (x, y) form left top tile of image (x, y in tiles) -{ - return appearance.isVisitableAt(pos.x - x, pos.y - y); -} -bool CGObjectInstance::blockingAt(int x, int y) const -{ - return appearance.isBlockedAt(pos.x - x, pos.y - y); -} - -bool CGObjectInstance::coveringAt(int x, int y) const -{ - return appearance.isVisibleAt(pos.x - x, pos.y - y); -} - -std::set CGObjectInstance::getBlockedPos() const -{ - std::set ret; - for(int w=0; w CGObjectInstance::getBlockedOffsets() const -{ - std::set ret; - for(int w=0; w cmp.appearance.printPriority; - - if(pos.y != cmp.pos.y) - return pos.y < cmp.pos.y; - - if(cmp.ID==Obj::HERO && ID!=Obj::HERO) - return true; - if(cmp.ID!=Obj::HERO && ID==Obj::HERO) - return false; - - if(!isVisitable() && cmp.isVisitable()) - return true; - if(!cmp.isVisitable() && isVisitable()) - return false; - if(this->pos.xgameState()->map->getTile(visitablePos()); - - this->ID = Obj(ID); - this->subID = subID; - this->appearance = VLC->objtypeh->getHandlerFor(ID, subID)->getTemplates(tile.terType).front(); - - //recalculate blockvis tiles - new appearance might have different blockmap than before - cb->gameState()->map->removeBlockVisTiles(this, true); - cb->gameState()->map->addBlockVisTiles(this); -} - -void CGObjectInstance::initObj() -{ - switch(ID) - { - case Obj::TAVERN: - blockVisit = true; - break; - } -} - -void CGObjectInstance::setProperty( ui8 what, ui32 val ) -{ - switch(what) - { - case ObjProperty::OWNER: - tempOwner = PlayerColor(val); - break; - case ObjProperty::BLOCKVIS: - blockVisit = val; - break; - case ObjProperty::ID: - ID = Obj(val); - break; - case ObjProperty::SUBID: - subID = val; - break; - } - setPropertyDer(what, val); -} - -void CGObjectInstance::setPropertyDer( ui8 what, ui32 val ) -{} - -int3 CGObjectInstance::getSightCenter() const -{ - //return vistiable tile if possible - for(int i=0; i < 8; i++) - for(int j=0; j < 6; j++) - if(visitableAt(i,j)) - return(pos + int3(i-7, j-5, 0)); - return pos; -} - -int CGObjectInstance::getSightRadious() const -{ - return 3; -} -void CGObjectInstance::getSightTiles(std::unordered_set &tiles) const //returns reference to the set -{ - cb->getTilesInRange(tiles, getSightCenter(), getSightRadious(), tempOwner, 1); -} -void CGObjectInstance::hideTiles(PlayerColor ourplayer, int radius) const -{ - for (auto i = cb->gameState()->teams.begin(); i != cb->gameState()->teams.end(); i++) - { - if ( !vstd::contains(i->second.players, ourplayer ))//another team - { - for (auto & elem : i->second.players) - if ( cb->getPlayer(elem)->status == EPlayerStatus::INGAME )//seek for living player (if any) - { - FoWChange fw; - fw.mode = 0; - fw.player = elem; - cb->getTilesInRange (fw.tiles, pos, radius, (elem), -1); - cb->sendAndApply (&fw); - break; - } - } - } -} -int3 CGObjectInstance::getVisitableOffset() const -{ - for(int y = 0; y < appearance.getHeight(); y++) - for (int x = 0; x < appearance.getWidth(); x++) - if (appearance.isVisitableAt(x, y)) - return int3(x,y,0); - - logGlobal->warnStream() << "Warning: getVisitableOffset called on non-visitable obj!"; - return int3(0,0,0); -} - -void CGObjectInstance::getNameVis( std::string &hname ) const -{ - const CGHeroInstance *h = cb->getSelectedHero(cb->getCurrentPlayer()); - hname = VLC->objtypeh->getObjectName(ID); - if(h) - { - const bool visited = h->hasBonusFrom(Bonus::OBJECT,ID); - hname + " " + visitedTxt(visited); - } -} - -void CGObjectInstance::giveDummyBonus(ObjectInstanceID heroID, ui8 duration) const -{ - GiveBonus gbonus; - gbonus.bonus.type = Bonus::NONE; - gbonus.id = heroID.getNum(); - gbonus.bonus.duration = duration; - gbonus.bonus.source = Bonus::OBJECT; - gbonus.bonus.sid = ID; - cb->giveHeroBonus(&gbonus); -} - -void CGObjectInstance::onHeroVisit( const CGHeroInstance * h ) const -{ - switch(ID) - { - case Obj::HILL_FORT: - { - openWindow(OpenWindow::HILL_FORT_WINDOW,id.getNum(),h->id.getNum()); - } - break; - case Obj::SANCTUARY: - { - //You enter the sanctuary and immediately feel as if a great weight has been lifted off your shoulders. You feel safe here. - showInfoDialog(h,114,soundBase::GETPROTECTION); - } - break; - case Obj::TAVERN: - { - openWindow(OpenWindow::TAVERN_WINDOW,h->id.getNum(),id.getNum()); - } - break; - } -} - -ui8 CGObjectInstance::getPassableness() const -{ - return 0; -} - -int3 CGObjectInstance::visitablePos() const -{ - return pos - getVisitableOffset(); -} - -bool CGObjectInstance::isVisitable() const -{ - return appearance.isVisitable(); -} - -bool CGObjectInstance::passableFor(PlayerColor color) const -{ - return getPassableness() & 1<obj->subID == obj->subID; -} - -int3 IBoatGenerator::bestLocation() const -{ - std::vector offsets; - getOutOffsets(offsets); - - for (auto & offset : offsets) - { - if (const TerrainTile *tile = IObjectInterface::cb->getTile(o->pos + offset, false)) //tile is in the map - { - if (tile->terType == ETerrainType::WATER && (!tile->blocked || tile->blockingObjects.front()->ID == 8)) //and is water and is not blocked or is blocked by boat - return o->pos + offset; - } - } - return int3 (-1,-1,-1); -} - -IBoatGenerator::EGeneratorState IBoatGenerator::shipyardStatus() const -{ - int3 tile = bestLocation(); - const TerrainTile *t = IObjectInterface::cb->getTile(tile); - if(!t) - return TILE_BLOCKED; //no available water - else if(!t->blockingObjects.size()) - return GOOD; //OK - else if(t->blockingObjects.front()->ID == Obj::BOAT) - return BOAT_ALREADY_BUILT; //blocked with boat - else - return TILE_BLOCKED; //blocked -} - -int IBoatGenerator::getBoatType() const -{ - //We make good ships by default - return 1; -} - - -IBoatGenerator::IBoatGenerator(const CGObjectInstance *O) -: o(O) -{ -} - -void IBoatGenerator::getProblemText(MetaString &out, const CGHeroInstance *visitor) const -{ - switch(shipyardStatus()) - { - case BOAT_ALREADY_BUILT: - out.addTxt(MetaString::GENERAL_TXT, 51); - break; - case TILE_BLOCKED: - if(visitor) - { - out.addTxt(MetaString::GENERAL_TXT, 134); - out.addReplacement(visitor->name); - } - else - out.addTxt(MetaString::ADVOB_TXT, 189); - break; - case NO_WATER: - logGlobal->errorStream() << "Shipyard without water!!! " << o->pos << "\t" << o->id; - return; - } -} - -void IShipyard::getBoatCost( std::vector &cost ) const -{ - cost.resize(GameConstants::RESOURCE_QUANTITY); - cost[Res::WOOD] = 10; - cost[Res::GOLD] = 1000; -} - -IShipyard::IShipyard(const CGObjectInstance *O) - : IBoatGenerator(O) -{ -} - -IShipyard * IShipyard::castFrom( CGObjectInstance *obj ) -{ - if(!obj) - return nullptr; - - if(obj->ID == Obj::TOWN) - { - return static_cast(obj); - } - else if(obj->ID == Obj::SHIPYARD) - { - return static_cast(obj); - } - else - { - return nullptr; - } -} - -const IShipyard * IShipyard::castFrom( const CGObjectInstance *obj ) -{ - return castFrom(const_cast(obj)); -} +/* + * CObjectHandler.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 "CObjectHandler.h" + +#include "NetPacks.h" +#include "CGeneralTextHandler.h" +#include "CHeroHandler.h" +#include "../client/CSoundBase.h" + +#include "CObjectClassesHandler.h" + +using namespace boost::assign; + +IGameCallback * IObjectInterface::cb = nullptr; + +///helpers +static void openWindow(const OpenWindow::EWindow type, const int id1, const int id2 = -1) +{ + OpenWindow ow; + ow.window = type; + ow.id1 = id1; + ow.id2 = id2; + IObjectInterface::cb->sendAndApply(&ow); +} + +static void showInfoDialog(const PlayerColor playerID, const ui32 txtID, const ui16 soundID) +{ + InfoWindow iw; + iw.soundID = soundID; + iw.player = playerID; + iw.text.addTxt(MetaString::ADVOB_TXT,txtID); + IObjectInterface::cb->sendAndApply(&iw); +} + +/*static void showInfoDialog(const ObjectInstanceID heroID, const ui32 txtID, const ui16 soundID) +{ + const PlayerColor playerID = IObjectInterface::cb->getOwner(heroID); + showInfoDialog(playerID,txtID,soundID); +}*/ + +static void showInfoDialog(const CGHeroInstance* h, const ui32 txtID, const ui16 soundID) +{ + const PlayerColor playerID = h->getOwner(); + showInfoDialog(playerID,txtID,soundID); +} + +static std::string & visitedTxt(const bool visited) +{ + int id = visited ? 352 : 353; + return VLC->generaltexth->allTexts[id]; +} + +///IObjectInterface +void IObjectInterface::onHeroVisit(const CGHeroInstance * h) const +{} + +void IObjectInterface::onHeroLeave(const CGHeroInstance * h) const +{} + +void IObjectInterface::newTurn () const +{} + +IObjectInterface::~IObjectInterface() +{} + +IObjectInterface::IObjectInterface() +{} + +void IObjectInterface::initObj() +{} + +void IObjectInterface::setProperty( ui8 what, ui32 val ) +{} + +bool IObjectInterface::wasVisited (PlayerColor player) const +{ + return false; +} +bool IObjectInterface::wasVisited (const CGHeroInstance * h) const +{ + return false; +} + +void IObjectInterface::postInit() +{} + +void IObjectInterface::preInit() +{} + +void IObjectInterface::battleFinished(const CGHeroInstance *hero, const BattleResult &result) const +{} + +void IObjectInterface::blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const +{} + +void IObjectInterface::garrisonDialogClosed(const CGHeroInstance *hero) const +{} + +void IObjectInterface::heroLevelUpDone(const CGHeroInstance *hero) const +{} + +// Bank helper. Find the creature ID and their number, and store the +// result in storage (either guards or reward creatures). +static void readCreatures(const JsonNode &creature, std::vector< std::pair > &storage) +{ + std::pair creInfo = std::make_pair(CreatureID::NONE, 0); + + //TODO: replace numeric id's with mod-friendly string id's + creInfo.second = creature["number"].Float(); + creInfo.first = CreatureID((si32)creature["id"].Float()); + storage.push_back(creInfo); +} + +// Bank helper. Process a bank level. +static void readBankLevel(const JsonNode &level, BankConfig &bc) +{ + int idx; + + bc.chance = level["chance"].Float(); + + for(const JsonNode &creature : level["guards"].Vector()) + { + readCreatures(creature, bc.guards); + } + + bc.upgradeChance = level["upgrade_chance"].Float(); + bc.combatValue = level["combat_value"].Float(); + + bc.resources = Res::ResourceSet(level["reward_resources"]); + + for(const JsonNode &creature : level["reward_creatures"].Vector()) + { + readCreatures(creature, bc.creatures); + } + + bc.artifacts.resize(4); + idx = 0; + for(const JsonNode &artifact : level["reward_artifacts"].Vector()) + { + bc.artifacts[idx] = artifact.Float(); + idx ++; + } + + bc.value = level["value"].Float(); + bc.rewardDifficulty = level["profitability"].Float(); + bc.easiest = level["easiest"].Float(); +} + +CObjectHandler::CObjectHandler() +{ + logGlobal->traceStream() << "\t\tReading cregens "; + + const JsonNode config(ResourceID("config/dwellings.json")); + for(const JsonNode &dwelling : config["dwellings"].Vector()) + { + cregens[dwelling["dwelling"].Float()] = CreatureID((si32)dwelling["creature"].Float()); + } + logGlobal->traceStream() << "\t\tDone loading cregens!"; + + logGlobal->traceStream() << "\t\tReading resources prices "; + const JsonNode config2(ResourceID("config/resources.json")); + for(const JsonNode &price : config2["resources_prices"].Vector()) + { + resVals.push_back(price.Float()); + } + logGlobal->traceStream() << "\t\tDone loading resource prices!"; + + logGlobal->traceStream() << "\t\tReading banks configs"; + const JsonNode config3(ResourceID("config/bankconfig.json")); + int bank_num = 0; + for(const JsonNode &bank : config3["banks"].Vector()) + { + creBanksNames[bank_num] = bank["name"].String(); + + int level_num = 0; + for(const JsonNode &level : bank["levels"].Vector()) + { + banksInfo[bank_num].push_back(new BankConfig); + BankConfig &bc = *banksInfo[bank_num].back(); + bc.level = level_num; + + readBankLevel(level, bc); + level_num ++; + } + + bank_num ++; + } + logGlobal->traceStream() << "\t\tDone loading banks configs"; +} + +CObjectHandler::~CObjectHandler() +{ + for(auto & mapEntry : banksInfo) + { + for(auto & vecEntry : mapEntry.second) + { + vecEntry.dellNull(); + } + } +} + +int CObjectHandler::bankObjToIndex (const CGObjectInstance * obj) +{ + switch (obj->ID) //find appriopriate key + { + case Obj::CREATURE_BANK: + return obj->subID; + case Obj::DERELICT_SHIP: + return 8; + case Obj::DRAGON_UTOPIA: + return 10; + case Obj::CRYPT: + return 9; + case Obj::SHIPWRECK: + return 7; + case Obj::PYRAMID: + return 21; + default: + logGlobal->warnStream() << "Unrecognized Bank indetifier!"; + return 0; + } +} +PlayerColor CGObjectInstance::getOwner() const +{ + //if (state) + // return state->owner; + //else + return tempOwner; //won't have owner +} + +CGObjectInstance::CGObjectInstance(): + pos(-1,-1,-1), + ID(Obj::NO_OBJ), + subID(-1), + tempOwner(PlayerColor::UNFLAGGABLE), + blockVisit(false) +{ +} +CGObjectInstance::~CGObjectInstance() +{ + //if (state) + // delete state; + //state=nullptr; +} + +const std::string & CGObjectInstance::getHoverText() const +{ + return hoverName; +} +void CGObjectInstance::setOwner(PlayerColor ow) +{ + //if (state) + // state->owner = ow; + //else + tempOwner = ow; +} +int CGObjectInstance::getWidth() const//returns width of object graphic in tiles +{ + return appearance.getWidth(); +} +int CGObjectInstance::getHeight() const //returns height of object graphic in tiles +{ + return appearance.getHeight(); +} +bool CGObjectInstance::visitableAt(int x, int y) const //returns true if object is visitable at location (x, y) form left top tile of image (x, y in tiles) +{ + return appearance.isVisitableAt(pos.x - x, pos.y - y); +} +bool CGObjectInstance::blockingAt(int x, int y) const +{ + return appearance.isBlockedAt(pos.x - x, pos.y - y); +} + +bool CGObjectInstance::coveringAt(int x, int y) const +{ + return appearance.isVisibleAt(pos.x - x, pos.y - y); +} + +std::set CGObjectInstance::getBlockedPos() const +{ + std::set ret; + for(int w=0; w CGObjectInstance::getBlockedOffsets() const +{ + std::set ret; + for(int w=0; w cmp.appearance.printPriority; + + if(pos.y != cmp.pos.y) + return pos.y < cmp.pos.y; + + if(cmp.ID==Obj::HERO && ID!=Obj::HERO) + return true; + if(cmp.ID!=Obj::HERO && ID==Obj::HERO) + return false; + + if(!isVisitable() && cmp.isVisitable()) + return true; + if(!cmp.isVisitable() && isVisitable()) + return false; + if(this->pos.xgameState()->map->getTile(visitablePos()); + + this->ID = Obj(ID); + this->subID = subID; + this->appearance = VLC->objtypeh->getHandlerFor(ID, subID)->getTemplates(tile.terType).front(); + + //recalculate blockvis tiles - new appearance might have different blockmap than before + cb->gameState()->map->removeBlockVisTiles(this, true); + cb->gameState()->map->addBlockVisTiles(this); +} + +void CGObjectInstance::initObj() +{ + switch(ID) + { + case Obj::TAVERN: + blockVisit = true; + break; + } +} + +void CGObjectInstance::setProperty( ui8 what, ui32 val ) +{ + switch(what) + { + case ObjProperty::OWNER: + tempOwner = PlayerColor(val); + break; + case ObjProperty::BLOCKVIS: + blockVisit = val; + break; + case ObjProperty::ID: + ID = Obj(val); + break; + case ObjProperty::SUBID: + subID = val; + break; + } + setPropertyDer(what, val); +} + +void CGObjectInstance::setPropertyDer( ui8 what, ui32 val ) +{} + +int3 CGObjectInstance::getSightCenter() const +{ + //return vistiable tile if possible + for(int i=0; i < 8; i++) + for(int j=0; j < 6; j++) + if(visitableAt(i,j)) + return(pos + int3(i-7, j-5, 0)); + return pos; +} + +int CGObjectInstance::getSightRadious() const +{ + return 3; +} +void CGObjectInstance::getSightTiles(std::unordered_set &tiles) const //returns reference to the set +{ + cb->getTilesInRange(tiles, getSightCenter(), getSightRadious(), tempOwner, 1); +} +void CGObjectInstance::hideTiles(PlayerColor ourplayer, int radius) const +{ + for (auto i = cb->gameState()->teams.begin(); i != cb->gameState()->teams.end(); i++) + { + if ( !vstd::contains(i->second.players, ourplayer ))//another team + { + for (auto & elem : i->second.players) + if ( cb->getPlayer(elem)->status == EPlayerStatus::INGAME )//seek for living player (if any) + { + FoWChange fw; + fw.mode = 0; + fw.player = elem; + cb->getTilesInRange (fw.tiles, pos, radius, (elem), -1); + cb->sendAndApply (&fw); + break; + } + } + } +} +int3 CGObjectInstance::getVisitableOffset() const +{ + for(int y = 0; y < appearance.getHeight(); y++) + for (int x = 0; x < appearance.getWidth(); x++) + if (appearance.isVisitableAt(x, y)) + return int3(x,y,0); + + logGlobal->warnStream() << "Warning: getVisitableOffset called on non-visitable obj!"; + return int3(0,0,0); +} + +void CGObjectInstance::getNameVis( std::string &hname ) const +{ + const CGHeroInstance *h = cb->getSelectedHero(cb->getCurrentPlayer()); + hname = VLC->objtypeh->getObjectName(ID); + if(h) + { + const bool visited = h->hasBonusFrom(Bonus::OBJECT,ID); + hname + " " + visitedTxt(visited); + } +} + +void CGObjectInstance::giveDummyBonus(ObjectInstanceID heroID, ui8 duration) const +{ + GiveBonus gbonus; + gbonus.bonus.type = Bonus::NONE; + gbonus.id = heroID.getNum(); + gbonus.bonus.duration = duration; + gbonus.bonus.source = Bonus::OBJECT; + gbonus.bonus.sid = ID; + cb->giveHeroBonus(&gbonus); +} + +void CGObjectInstance::onHeroVisit( const CGHeroInstance * h ) const +{ + switch(ID) + { + case Obj::HILL_FORT: + { + openWindow(OpenWindow::HILL_FORT_WINDOW,id.getNum(),h->id.getNum()); + } + break; + case Obj::SANCTUARY: + { + //You enter the sanctuary and immediately feel as if a great weight has been lifted off your shoulders. You feel safe here. + showInfoDialog(h,114,soundBase::GETPROTECTION); + } + break; + case Obj::TAVERN: + { + openWindow(OpenWindow::TAVERN_WINDOW,h->id.getNum(),id.getNum()); + } + break; + } +} + +ui8 CGObjectInstance::getPassableness() const +{ + return 0; +} + +int3 CGObjectInstance::visitablePos() const +{ + return pos - getVisitableOffset(); +} + +bool CGObjectInstance::isVisitable() const +{ + return appearance.isVisitable(); +} + +bool CGObjectInstance::passableFor(PlayerColor color) const +{ + return getPassableness() & 1<obj->subID == obj->subID; +} + +int3 IBoatGenerator::bestLocation() const +{ + std::vector offsets; + getOutOffsets(offsets); + + for (auto & offset : offsets) + { + if (const TerrainTile *tile = IObjectInterface::cb->getTile(o->pos + offset, false)) //tile is in the map + { + if (tile->terType == ETerrainType::WATER && (!tile->blocked || tile->blockingObjects.front()->ID == 8)) //and is water and is not blocked or is blocked by boat + return o->pos + offset; + } + } + return int3 (-1,-1,-1); +} + +IBoatGenerator::EGeneratorState IBoatGenerator::shipyardStatus() const +{ + int3 tile = bestLocation(); + const TerrainTile *t = IObjectInterface::cb->getTile(tile); + if(!t) + return TILE_BLOCKED; //no available water + else if(!t->blockingObjects.size()) + return GOOD; //OK + else if(t->blockingObjects.front()->ID == Obj::BOAT) + return BOAT_ALREADY_BUILT; //blocked with boat + else + return TILE_BLOCKED; //blocked +} + +int IBoatGenerator::getBoatType() const +{ + //We make good ships by default + return 1; +} + + +IBoatGenerator::IBoatGenerator(const CGObjectInstance *O) +: o(O) +{ +} + +void IBoatGenerator::getProblemText(MetaString &out, const CGHeroInstance *visitor) const +{ + switch(shipyardStatus()) + { + case BOAT_ALREADY_BUILT: + out.addTxt(MetaString::GENERAL_TXT, 51); + break; + case TILE_BLOCKED: + if(visitor) + { + out.addTxt(MetaString::GENERAL_TXT, 134); + out.addReplacement(visitor->name); + } + else + out.addTxt(MetaString::ADVOB_TXT, 189); + break; + case NO_WATER: + logGlobal->errorStream() << "Shipyard without water!!! " << o->pos << "\t" << o->id; + return; + } +} + +void IShipyard::getBoatCost( std::vector &cost ) const +{ + cost.resize(GameConstants::RESOURCE_QUANTITY); + cost[Res::WOOD] = 10; + cost[Res::GOLD] = 1000; +} + +IShipyard::IShipyard(const CGObjectInstance *O) + : IBoatGenerator(O) +{ +} + +IShipyard * IShipyard::castFrom( CGObjectInstance *obj ) +{ + if(!obj) + return nullptr; + + if(obj->ID == Obj::TOWN) + { + return static_cast(obj); + } + else if(obj->ID == Obj::SHIPYARD) + { + return static_cast(obj); + } + else + { + return nullptr; + } +} + +const IShipyard * IShipyard::castFrom( const CGObjectInstance *obj ) +{ + return castFrom(const_cast(obj)); +} diff --git a/lib/mapObjects/CObjectHandler.h b/lib/mapObjects/CObjectHandler.h index ed83a28f8..640ae1c3e 100644 --- a/lib/mapObjects/CObjectHandler.h +++ b/lib/mapObjects/CObjectHandler.h @@ -1,204 +1,204 @@ -#pragma once - -#include "ObjectTemplate.h" - -#include "../IGameCallback.h" -#include "../int3.h" -#include "../HeroBonus.h" - -/* - * CObjectHandler.h, 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 - * - */ - -class CGHeroInstance; -struct BattleResult; - -class DLL_LINKAGE IObjectInterface -{ -public: - static IGameCallback *cb; - - IObjectInterface(); - virtual ~IObjectInterface(); - - virtual void onHeroVisit(const CGHeroInstance * h) const; - virtual void onHeroLeave(const CGHeroInstance * h) const; - virtual void newTurn() const; - virtual void initObj(); //synchr - virtual void setProperty(ui8 what, ui32 val);//synchr - - //Called when queries created DURING HERO VISIT are resolved - //First parameter is always hero that visited object and triggered the query - virtual void battleFinished(const CGHeroInstance *hero, const BattleResult &result) const; - virtual void blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const; - virtual void garrisonDialogClosed(const CGHeroInstance *hero) const; - virtual void heroLevelUpDone(const CGHeroInstance *hero) const; - -//unified interface, AI helpers - virtual bool wasVisited (PlayerColor player) const; - virtual bool wasVisited (const CGHeroInstance * h) const; - - static void preInit(); //called before objs receive their initObj - static void postInit();//called after objs receive their initObj - - template void serialize(Handler &h, const int version) - { - logGlobal->errorStream() << "IObjectInterface serialized, unexpected, should not happen!"; - } -}; - -class DLL_LINKAGE IBoatGenerator -{ -public: - const CGObjectInstance *o; - - IBoatGenerator(const CGObjectInstance *O); - virtual ~IBoatGenerator() {} - - virtual int getBoatType() const; //0 - evil (if a ship can be evil...?), 1 - good, 2 - neutral - virtual void getOutOffsets(std::vector &offsets) const =0; //offsets to obj pos when we boat can be placed - int3 bestLocation() const; //returns location when the boat should be placed - - enum EGeneratorState {GOOD, BOAT_ALREADY_BUILT, TILE_BLOCKED, NO_WATER}; - EGeneratorState shipyardStatus() const; //0 - can buid, 1 - there is already a boat at dest tile, 2 - dest tile is blocked, 3 - no water - void getProblemText(MetaString &out, const CGHeroInstance *visitor = nullptr) const; - - template void serialize(Handler &h, const int version) - { - h & o; - } -}; - -class DLL_LINKAGE IShipyard : public IBoatGenerator -{ -public: - IShipyard(const CGObjectInstance *O); - virtual ~IShipyard() {} - - virtual void getBoatCost(std::vector &cost) const; - - static const IShipyard *castFrom(const CGObjectInstance *obj); - static IShipyard *castFrom(CGObjectInstance *obj); - - template void serialize(Handler &h, const int version) - { - h & static_cast(*this); - } -}; - -class DLL_LINKAGE CGObjectInstance : public IObjectInterface -{ -public: - mutable std::string hoverName; - int3 pos; //h3m pos - Obj ID; - si32 subID; //normal subID (this one from OH3 maps ;]) - ObjectInstanceID id;//number of object in map's vector - ObjectTemplate appearance; - - PlayerColor tempOwner; - bool blockVisit; //if non-zero then blocks the tile but is visitable from neighbouring tile - - virtual ui8 getPassableness() const; //bitmap - if the bit is set the corresponding player can pass through the visitable tiles of object, even if it's blockvis; if not set - default properties from definfo are used - virtual int3 getSightCenter() const; //"center" tile from which the sight distance is calculated - virtual int getSightRadious() const; //sight distance (should be used if player-owned structure) - bool passableFor(PlayerColor color) const; - void getSightTiles(std::unordered_set &tiles) const; //returns reference to the set - PlayerColor getOwner() const; - void setOwner(PlayerColor ow); - int getWidth() const; //returns width of object graphic in tiles - int getHeight() const; //returns height of object graphic in tiles - virtual bool visitableAt(int x, int y) const; //returns true if object is visitable at location (x, y) (h3m pos) - virtual int3 getVisitableOffset() const; //returns (x,y,0) offset to first visitable tile from bottom right obj tile (0,0,0) (h3m pos) - int3 visitablePos() const; - bool blockingAt(int x, int y) const; //returns true if object is blocking location (x, y) (h3m pos) - bool coveringAt(int x, int y) const; //returns true if object covers with picture location (x, y) (h3m pos) - std::set getBlockedPos() const; //returns set of positions blocked by this object - std::set getBlockedOffsets() const; //returns set of relative positions blocked by this object - bool isVisitable() const; //returns true if object is visitable - bool operator<(const CGObjectInstance & cmp) const; //screen printing priority comparing - void hideTiles(PlayerColor ourplayer, int radius) const; - CGObjectInstance(); - virtual ~CGObjectInstance(); - //CGObjectInstance(const CGObjectInstance & right); - //CGObjectInstance& operator=(const CGObjectInstance & right); - virtual const std::string & getHoverText() const; - - void setType(si32 ID, si32 subID); - - ///IObjectInterface - void initObj() override; - void onHeroVisit(const CGHeroInstance * h) const override; - void setProperty(ui8 what, ui32 val) override;//synchr - - friend class CGameHandler; - - - template void serialize(Handler &h, const int version) - { - h & hoverName & pos & ID & subID & id & tempOwner & blockVisit & appearance; - //definfo is handled by map serializer - } -protected: - virtual void setPropertyDer(ui8 what, ui32 val);//synchr - - void getNameVis(std::string &hname) const; - void giveDummyBonus(ObjectInstanceID heroID, ui8 duration = Bonus::ONE_DAY) const; -}; - -/// function object which can be used to find an object with an specific sub ID -class CGObjectInstanceBySubIdFinder -{ -public: - CGObjectInstanceBySubIdFinder(CGObjectInstance * obj); - bool operator()(CGObjectInstance * obj) const; - -private: - CGObjectInstance * obj; -}; - -struct BankConfig -{ - BankConfig() {level = chance = upgradeChance = combatValue = value = rewardDifficulty = easiest = 0; }; - ui8 level; //1 - 4, how hard the battle will be - ui8 chance; //chance for this level being chosen - ui8 upgradeChance; //chance for creatures to be in upgraded versions - std::vector< std::pair > guards; //creature ID, amount - ui32 combatValue; //how hard are guards of this level - Res::ResourceSet resources; //resources given in case of victory - std::vector< std::pair > creatures; //creatures granted in case of victory (creature ID, amount) - std::vector artifacts; //number of artifacts given in case of victory [0] -> treasure, [1] -> minor [2] -> major [3] -> relic - ui32 value; //overall value of given things - ui32 rewardDifficulty; //proportion of reward value to difficulty of guards; how profitable is this creature Bank config - ui16 easiest; //?!? - - template void serialize(Handler &h, const int version) - { - h & level & chance & upgradeChance & guards & combatValue & resources & creatures & artifacts & value & rewardDifficulty & easiest; - } -}; - -class DLL_LINKAGE CObjectHandler -{ -public: - std::map cregens; //type 17. dwelling subid -> creature ID - std::map > > banksInfo; //[index][preset] - std::map creBanksNames; //[crebank index] -> name of this creature bank - std::vector resVals; //default values of resources in gold - - CObjectHandler(); - ~CObjectHandler(); - - int bankObjToIndex (const CGObjectInstance * obj); - - template void serialize(Handler &h, const int version) - { - h & cregens & banksInfo & creBanksNames & resVals; - } -}; +#pragma once + +#include "ObjectTemplate.h" + +#include "../IGameCallback.h" +#include "../int3.h" +#include "../HeroBonus.h" + +/* + * CObjectHandler.h, 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 + * + */ + +class CGHeroInstance; +struct BattleResult; + +class DLL_LINKAGE IObjectInterface +{ +public: + static IGameCallback *cb; + + IObjectInterface(); + virtual ~IObjectInterface(); + + virtual void onHeroVisit(const CGHeroInstance * h) const; + virtual void onHeroLeave(const CGHeroInstance * h) const; + virtual void newTurn() const; + virtual void initObj(); //synchr + virtual void setProperty(ui8 what, ui32 val);//synchr + + //Called when queries created DURING HERO VISIT are resolved + //First parameter is always hero that visited object and triggered the query + virtual void battleFinished(const CGHeroInstance *hero, const BattleResult &result) const; + virtual void blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const; + virtual void garrisonDialogClosed(const CGHeroInstance *hero) const; + virtual void heroLevelUpDone(const CGHeroInstance *hero) const; + +//unified interface, AI helpers + virtual bool wasVisited (PlayerColor player) const; + virtual bool wasVisited (const CGHeroInstance * h) const; + + static void preInit(); //called before objs receive their initObj + static void postInit();//called after objs receive their initObj + + template void serialize(Handler &h, const int version) + { + logGlobal->errorStream() << "IObjectInterface serialized, unexpected, should not happen!"; + } +}; + +class DLL_LINKAGE IBoatGenerator +{ +public: + const CGObjectInstance *o; + + IBoatGenerator(const CGObjectInstance *O); + virtual ~IBoatGenerator() {} + + virtual int getBoatType() const; //0 - evil (if a ship can be evil...?), 1 - good, 2 - neutral + virtual void getOutOffsets(std::vector &offsets) const =0; //offsets to obj pos when we boat can be placed + int3 bestLocation() const; //returns location when the boat should be placed + + enum EGeneratorState {GOOD, BOAT_ALREADY_BUILT, TILE_BLOCKED, NO_WATER}; + EGeneratorState shipyardStatus() const; //0 - can buid, 1 - there is already a boat at dest tile, 2 - dest tile is blocked, 3 - no water + void getProblemText(MetaString &out, const CGHeroInstance *visitor = nullptr) const; + + template void serialize(Handler &h, const int version) + { + h & o; + } +}; + +class DLL_LINKAGE IShipyard : public IBoatGenerator +{ +public: + IShipyard(const CGObjectInstance *O); + virtual ~IShipyard() {} + + virtual void getBoatCost(std::vector &cost) const; + + static const IShipyard *castFrom(const CGObjectInstance *obj); + static IShipyard *castFrom(CGObjectInstance *obj); + + template void serialize(Handler &h, const int version) + { + h & static_cast(*this); + } +}; + +class DLL_LINKAGE CGObjectInstance : public IObjectInterface +{ +public: + mutable std::string hoverName; + int3 pos; //h3m pos + Obj ID; + si32 subID; //normal subID (this one from OH3 maps ;]) + ObjectInstanceID id;//number of object in map's vector + ObjectTemplate appearance; + + PlayerColor tempOwner; + bool blockVisit; //if non-zero then blocks the tile but is visitable from neighbouring tile + + virtual ui8 getPassableness() const; //bitmap - if the bit is set the corresponding player can pass through the visitable tiles of object, even if it's blockvis; if not set - default properties from definfo are used + virtual int3 getSightCenter() const; //"center" tile from which the sight distance is calculated + virtual int getSightRadious() const; //sight distance (should be used if player-owned structure) + bool passableFor(PlayerColor color) const; + void getSightTiles(std::unordered_set &tiles) const; //returns reference to the set + PlayerColor getOwner() const; + void setOwner(PlayerColor ow); + int getWidth() const; //returns width of object graphic in tiles + int getHeight() const; //returns height of object graphic in tiles + virtual bool visitableAt(int x, int y) const; //returns true if object is visitable at location (x, y) (h3m pos) + virtual int3 getVisitableOffset() const; //returns (x,y,0) offset to first visitable tile from bottom right obj tile (0,0,0) (h3m pos) + int3 visitablePos() const; + bool blockingAt(int x, int y) const; //returns true if object is blocking location (x, y) (h3m pos) + bool coveringAt(int x, int y) const; //returns true if object covers with picture location (x, y) (h3m pos) + std::set getBlockedPos() const; //returns set of positions blocked by this object + std::set getBlockedOffsets() const; //returns set of relative positions blocked by this object + bool isVisitable() const; //returns true if object is visitable + bool operator<(const CGObjectInstance & cmp) const; //screen printing priority comparing + void hideTiles(PlayerColor ourplayer, int radius) const; + CGObjectInstance(); + virtual ~CGObjectInstance(); + //CGObjectInstance(const CGObjectInstance & right); + //CGObjectInstance& operator=(const CGObjectInstance & right); + virtual const std::string & getHoverText() const; + + void setType(si32 ID, si32 subID); + + ///IObjectInterface + void initObj() override; + void onHeroVisit(const CGHeroInstance * h) const override; + void setProperty(ui8 what, ui32 val) override;//synchr + + friend class CGameHandler; + + + template void serialize(Handler &h, const int version) + { + h & hoverName & pos & ID & subID & id & tempOwner & blockVisit & appearance; + //definfo is handled by map serializer + } +protected: + virtual void setPropertyDer(ui8 what, ui32 val);//synchr + + void getNameVis(std::string &hname) const; + void giveDummyBonus(ObjectInstanceID heroID, ui8 duration = Bonus::ONE_DAY) const; +}; + +/// function object which can be used to find an object with an specific sub ID +class CGObjectInstanceBySubIdFinder +{ +public: + CGObjectInstanceBySubIdFinder(CGObjectInstance * obj); + bool operator()(CGObjectInstance * obj) const; + +private: + CGObjectInstance * obj; +}; + +struct BankConfig +{ + BankConfig() {level = chance = upgradeChance = combatValue = value = rewardDifficulty = easiest = 0; }; + ui8 level; //1 - 4, how hard the battle will be + ui8 chance; //chance for this level being chosen + ui8 upgradeChance; //chance for creatures to be in upgraded versions + std::vector< std::pair > guards; //creature ID, amount + ui32 combatValue; //how hard are guards of this level + Res::ResourceSet resources; //resources given in case of victory + std::vector< std::pair > creatures; //creatures granted in case of victory (creature ID, amount) + std::vector artifacts; //number of artifacts given in case of victory [0] -> treasure, [1] -> minor [2] -> major [3] -> relic + ui32 value; //overall value of given things + ui32 rewardDifficulty; //proportion of reward value to difficulty of guards; how profitable is this creature Bank config + ui16 easiest; //?!? + + template void serialize(Handler &h, const int version) + { + h & level & chance & upgradeChance & guards & combatValue & resources & creatures & artifacts & value & rewardDifficulty & easiest; + } +}; + +class DLL_LINKAGE CObjectHandler +{ +public: + std::map cregens; //type 17. dwelling subid -> creature ID + std::map > > banksInfo; //[index][preset] + std::map creBanksNames; //[crebank index] -> name of this creature bank + std::vector resVals; //default values of resources in gold + + CObjectHandler(); + ~CObjectHandler(); + + int bankObjToIndex (const CGObjectInstance * obj); + + template void serialize(Handler &h, const int version) + { + h & cregens & banksInfo & creBanksNames & resVals; + } +};