diff --git a/lib/CTownHandler.cpp b/lib/CTownHandler.cpp index b0d0a1b11..fa4e2fd31 100644 --- a/lib/CTownHandler.cpp +++ b/lib/CTownHandler.cpp @@ -25,11 +25,21 @@ const int NAMES_PER_TOWN=16; // number of town names per faction in H3 files. Json can define any number -CBuilding::CBuilding(): - town(nullptr),mode(BUILD_NORMAL) +const std::map CBuilding::MODES = { + { "normal", CBuilding::BUILD_NORMAL }, + { "auto", CBuilding::BUILD_AUTO }, + { "special", CBuilding::BUILD_SPECIAL }, + { "grail", CBuilding::BUILD_GRAIL } +}; -} +const std::map CBuilding::TOWER_TYPES = +{ + { "low", CBuilding::HEIGHT_LOW }, + { "average", CBuilding::HEIGHT_AVERAGE }, + { "high", CBuilding::HEIGHT_HIGH }, + { "skyship", CBuilding::HEIGHT_SKYSHIP } +}; const std::string & CBuilding::Name() const { @@ -83,6 +93,52 @@ void CBuilding::deserializeFix() } } +void CBuilding::update792(const BuildingID & bid, BuildingSubID::EBuildingSubID & subId, ETowerHeight & height) +{ + subId = BuildingSubID::NONE; + height = ETowerHeight::HEIGHT_NO_TOWER; + + if(!bid.IsSpecialOrGrail() || town == nullptr || town->faction == nullptr || town->faction->identifier.empty()) + return; + + const auto buildingName = CTownHandler::getMappedValue(bid, std::string(), MappedKeys::BUILDING_TYPES_TO_NAMES); + + if(buildingName.empty()) + return; + + const auto & faction = town->faction->identifier; + auto factionsContent = VLC->modh->content["factions"]; + auto & coreData = factionsContent.modData.at("core"); + auto & coreFactions = coreData.modData; + auto & currentFaction = coreFactions[faction]; + + if (currentFaction.isNull()) + { + const auto index = faction.find(':'); + const std::string factionDir = index == std::string::npos ? faction : faction.substr(0, index); + const auto it = factionsContent.modData.find(factionDir); + + if (it == factionsContent.modData.end()) + { + logMod->warn("Warning: Update old save failed: Faction: '%s' is not found.", factionDir); + return; + } + const std::string modFaction = index == std::string::npos ? faction : faction.substr(index + 1); + currentFaction = it->second.modData[modFaction]; + } + + if (!currentFaction.isNull() && currentFaction.getType() == JsonNode::JsonType::DATA_STRUCT) + { + const auto & buildings = currentFaction["town"]["buildings"]; + const auto & currentBuilding = buildings[buildingName]; + + subId = CTownHandler::getMappedValue(currentBuilding["type"], BuildingSubID::NONE, MappedKeys::SPECIAL_BUILDINGS); + height = CBuilding::HEIGHT_NO_TOWER; + + if (subId == BuildingSubID::LOOKOUT_TOWER || bid == BuildingID::GRAIL) + height = CTownHandler::getMappedValue(currentBuilding["height"], CBuilding::HEIGHT_NO_TOWER, CBuilding::TOWER_TYPES); + } +} CFaction::CFaction() { @@ -343,8 +399,8 @@ void CTownHandler::loadBuildingRequirements(CBuilding * building, const JsonNode requirementsToLoad.push_back(hlp); } -template -R CTownHandler::getMappedValue(const std::string key, const R defval, const std::map & map, bool required) const +template +R CTownHandler::getMappedValue(const K key, const R defval, const std::map & map, bool required) { auto it = map.find(key); @@ -357,64 +413,17 @@ R CTownHandler::getMappedValue(const std::string key, const R defval, const std: } template -R CTownHandler::getMappedValue(const JsonNode & node, const R defval, const std::map & map, bool required) const +R CTownHandler::getMappedValue(const JsonNode & node, const R defval, const std::map & map, bool required) { if(!node.isNull() && node.getType() == JsonNode::JsonType::DATA_STRING) - return getMappedValue(node.String(), defval, map, required); + return getMappedValue(node.String(), defval, map, required); return defval; } void CTownHandler::loadBuilding(CTown * town, const std::string & stringID, const JsonNode & source) { - static const std::map MODES = - { - { "normal", CBuilding::BUILD_NORMAL }, - { "auto", CBuilding::BUILD_AUTO }, - { "special", CBuilding::BUILD_SPECIAL }, - { "grail", CBuilding::BUILD_GRAIL } - }; - - static const std::map BUILDING_TYPES = - { - { "special1", BuildingID::SPECIAL_1 }, - { "special2", BuildingID::SPECIAL_2 }, - { "special3", BuildingID::SPECIAL_3 }, - { "special4", BuildingID::SPECIAL_4 }, - { "grail", BuildingID::GRAIL } - }; - - static const std::map LOOKOUT_TYPES = - { - { "low", CBuilding::HEIGHT_LOW }, - { "average", CBuilding::HEIGHT_AVERAGE }, - { "high", CBuilding::HEIGHT_HIGH }, - { "skyship", CBuilding::HEIGHT_SKYSHIP } - }; - - static const std::map SPECIAL_BUILDINGS = - { - { "mysticPond", BuildingSubID::MYSTIC_POND }, - { "artifactMerchant", BuildingSubID::ARTIFACT_MERCHANT }, - { "freelancersGuild", BuildingSubID::FREELANCERS_GUILD }, - { "magicUniversity", BuildingSubID::MAGIC_UNIVERSITY }, - { "castleGate", BuildingSubID::CASTLE_GATE }, - { "creatureTransformer", BuildingSubID::CREATURE_TRANSFORMER },//only skeleton transformer yet - { "portalOfSummoning", BuildingSubID::PORTAL_OF_SUMMONING }, - { "ballistaYard", BuildingSubID::BALLISTA_YARD }, - { "stables", BuildingSubID::STABLES }, - { "manaVortex", BuildingSubID::MANA_VORTEX }, - { "lookoutTower", BuildingSubID::LOOKOUT_TOWER }, - { "library", BuildingSubID::LIBRARY }, - { "brotherhoodOfSword", BuildingSubID::BROTHERHOOD_OF_SWORD },//morale garrison bonus - { "fountainOfFortune", BuildingSubID::FOUNTAIN_OF_FORTUNE },//luck garrison bonus - { "spellPowerGarrisonBonus", BuildingSubID::SPELL_POWER_GARRISON_BONUS },//such as 'stormclouds', but this name is not ok for good towns - { "attackGarrisonBonus", BuildingSubID::ATTACK_GARRISON_BONUS }, - { "defenseGarrisonBonus", BuildingSubID::DEFENSE_GARRISON_BONUS }, - { "escapeTunnel", BuildingSubID::ESCAPE_TUNNEL } - }; - auto ret = new CBuilding(); - ret->bid = getMappedValue(stringID, BuildingID::NONE, BUILDING_TYPES, false); + ret->bid = getMappedValue(stringID, BuildingID::NONE, MappedKeys::BUILDING_NAMES_TO_TYPES, false); if(ret->bid == BuildingID::NONE) ret->bid = source["id"].isNull() ? BuildingID(BuildingID::NONE) : BuildingID(source["id"].Float()); @@ -424,14 +433,14 @@ void CTownHandler::loadBuilding(CTown * town, const std::string & stringID, cons ret->mode = ret->bid == BuildingID::GRAIL ? CBuilding::BUILD_GRAIL - : getMappedValue(source["mode"], CBuilding::BUILD_NORMAL, MODES); + : getMappedValue(source["mode"], CBuilding::BUILD_NORMAL, CBuilding::MODES); - ret->subId = getMappedValue(source["type"], BuildingSubID::NONE, SPECIAL_BUILDINGS); + ret->subId = getMappedValue(source["type"], BuildingSubID::NONE, MappedKeys::SPECIAL_BUILDINGS); ret->height = CBuilding::HEIGHT_NO_TOWER; if(ret->subId == BuildingSubID::LOOKOUT_TOWER || ret->bid == BuildingID::GRAIL) - ret->height = getMappedValue(source["height"], CBuilding::HEIGHT_NO_TOWER, LOOKOUT_TYPES); + ret->height = getMappedValue(source["height"], CBuilding::HEIGHT_NO_TOWER, CBuilding::TOWER_TYPES); ret->identifier = stringID; ret->town = town; diff --git a/lib/CTownHandler.h b/lib/CTownHandler.h index 3f9d9af91..660f185a7 100644 --- a/lib/CTownHandler.h +++ b/lib/CTownHandler.h @@ -65,7 +65,10 @@ public: HEIGHT_SKYSHIP = std::numeric_limits::max() // grail, open entire map } height; - CBuilding(); + static const std::map MODES; + static const std::map TOWER_TYPES; + + CBuilding() : town(nullptr), mode(BUILD_NORMAL) {}; const std::string &Name() const; const std::string &Description() const; @@ -75,6 +78,8 @@ public: // returns how many times build has to be upgraded to become build si32 getDistance(BuildingID build) const; + /// input: faction, bid; output: subId, height; + void update792(const BuildingID & bid, BuildingSubID::EBuildingSubID & subId, ETowerHeight & height); template void serialize(Handler &h, const int version) { @@ -94,10 +99,9 @@ public: h & subId; h & height; } - else if (!h.saving) + else if(!h.saving) { - subId = BuildingSubID::NONE; - height = CBuilding::HEIGHT_NO_TOWER; + update792(bid, subId, height); } if(!h.saving) deserializeFix(); @@ -352,12 +356,12 @@ class DLL_LINKAGE CTownHandler : public IHandlerBase void loadRandomFaction(); - template - R getMappedValue(const std::string key, const R defval, const std::map & map, bool required = true) const; - template - R getMappedValue(const JsonNode& node, const R defval, const std::map & map, bool required = true) const; - public: + template + static R getMappedValue(const K key, const R defval, const std::map & map, bool required = true); + template + static R getMappedValue(const JsonNode & node, const R defval, const std::map & map, bool required = true); + std::vector > factions; CTown * randomTown; diff --git a/lib/GameConstants.h b/lib/GameConstants.h index 36a1a7fc2..5c5471c12 100644 --- a/lib/GameConstants.h +++ b/lib/GameConstants.h @@ -409,11 +409,18 @@ public: BuildingID(EBuildingID _num = NONE) : num(_num) {} + STRONG_INLINE + bool IsSpecialOrGrail() const + { + return num == SPECIAL_1 || num == SPECIAL_2 || num == SPECIAL_3 || num == SPECIAL_4 || num == GRAIL; + } + ID_LIKE_CLASS_COMMON(BuildingID, EBuildingID) EBuildingID num; }; +ID_LIKE_OPERATORS(BuildingID, BuildingID::EBuildingID) namespace BuildingSubID { @@ -443,7 +450,49 @@ namespace BuildingSubID }; } -ID_LIKE_OPERATORS(BuildingID, BuildingID::EBuildingID) +namespace MappedKeys +{ + + static const std::map BUILDING_NAMES_TO_TYPES = + { + { "special1", BuildingID::SPECIAL_1 }, + { "special2", BuildingID::SPECIAL_2 }, + { "special3", BuildingID::SPECIAL_3 }, + { "special4", BuildingID::SPECIAL_4 }, + { "grail", BuildingID::GRAIL } + }; + + static const std::map BUILDING_TYPES_TO_NAMES = + { + { BuildingID::SPECIAL_1, "special1", }, + { BuildingID::SPECIAL_2, "special2" }, + { BuildingID::SPECIAL_3, "special3" }, + { BuildingID::SPECIAL_4, "special4" }, + { BuildingID::GRAIL, "grail"} + }; + + static const std::map SPECIAL_BUILDINGS = + { + { "mysticPond", BuildingSubID::MYSTIC_POND }, + { "artifactMerchant", BuildingSubID::ARTIFACT_MERCHANT }, + { "freelancersGuild", BuildingSubID::FREELANCERS_GUILD }, + { "magicUniversity", BuildingSubID::MAGIC_UNIVERSITY }, + { "castleGate", BuildingSubID::CASTLE_GATE }, + { "creatureTransformer", BuildingSubID::CREATURE_TRANSFORMER },//only skeleton transformer yet + { "portalOfSummoning", BuildingSubID::PORTAL_OF_SUMMONING }, + { "ballistaYard", BuildingSubID::BALLISTA_YARD }, + { "stables", BuildingSubID::STABLES }, + { "manaVortex", BuildingSubID::MANA_VORTEX }, + { "lookoutTower", BuildingSubID::LOOKOUT_TOWER }, + { "library", BuildingSubID::LIBRARY }, + { "brotherhoodOfSword", BuildingSubID::BROTHERHOOD_OF_SWORD },//morale garrison bonus + { "fountainOfFortune", BuildingSubID::FOUNTAIN_OF_FORTUNE },//luck garrison bonus + { "spellPowerGarrisonBonus", BuildingSubID::SPELL_POWER_GARRISON_BONUS },//such as 'stormclouds', but this name is not ok for good towns + { "attackGarrisonBonus", BuildingSubID::ATTACK_GARRISON_BONUS }, + { "defenseGarrisonBonus", BuildingSubID::DEFENSE_GARRISON_BONUS }, + { "escapeTunnel", BuildingSubID::ESCAPE_TUNNEL } + }; +} namespace EAiTactic { diff --git a/lib/NetPacksBase.h b/lib/NetPacksBase.h index 16d062f75..1404fc3f8 100644 --- a/lib/NetPacksBase.h +++ b/lib/NetPacksBase.h @@ -171,7 +171,7 @@ struct Component { enum EComponentType {PRIM_SKILL, SEC_SKILL, RESOURCE, CREATURE, ARTIFACT, EXPERIENCE, SPELL, MORALE, LUCK, BUILDING, HERO_PORTRAIT, FLAG}; ui16 id, subtype; //id uses ^^^ enums, when id==EXPPERIENCE subtype==0 means exp points and subtype==1 levels) - si64 val; // + give; - take + si32 val; // + give; - take si16 when; // 0 - now; +x - within x days; -x - per x days template void serialize(Handler &h, const int version) @@ -186,7 +186,7 @@ struct Component { } DLL_LINKAGE explicit Component(const CStackBasicDescriptor &stack); - Component(Component::EComponentType Type, ui16 Subtype, si64 Val, si16 When) + Component(Component::EComponentType Type, ui16 Subtype, si32 Val, si16 When) :id(Type),subtype(Subtype),val(Val),when(When) { } diff --git a/lib/mapObjects/CGTownInstance.cpp b/lib/mapObjects/CGTownInstance.cpp index a1bc816ec..69c473349 100644 --- a/lib/mapObjects/CGTownInstance.cpp +++ b/lib/mapObjects/CGTownInstance.cpp @@ -435,17 +435,15 @@ void CGDwelling::serializeJsonOptions(JsonSerializeFormat & handler) } } +TPropagatorPtr CGTownInstance::emptyPropagator = TPropagatorPtr(); + int CGTownInstance::getSightRadius() const //returns sight distance { auto ret = CBuilding::HEIGHT_NO_TOWER; for(const auto & bid : builtBuildings) { - if(bid == BuildingID::SPECIAL_1 - || bid == BuildingID::SPECIAL_2 - || bid == BuildingID::SPECIAL_3 - || bid == BuildingID::SPECIAL_4 - || bid == BuildingID::GRAIL) + if(bid.IsSpecialOrGrail()) { auto height = town->buildings.at(bid)->height; if(ret < height) @@ -797,6 +795,81 @@ void CGTownInstance::initObj(CRandomGenerator & rand) updateAppearance(); } +void CGTownInstance::updateBonusingBuildings() +{ + if (this->town->faction != nullptr) + { + //firstly, update subtype for the Bonusing objects, which are already stored in the bonusing list + for (auto building : bonusingBuildings) + { + switch (this->town->faction->index) + { + case ETownType::CASTLE: + if (building->getBuildingType() == BuildingID::SPECIAL_2) + building->setBuildingSubtype(BuildingSubID::STABLES); + break; + + case ETownType::DUNGEON: + if(building->getBuildingType() == BuildingID::SPECIAL_2) + building->setBuildingSubtype(BuildingSubID::MANA_VORTEX); + break; + } + } + } + //secondly, supplement bonusing buildings list and active bonuses; subtypes for these objects are already set in update792 + for (auto & kvp : town->buildings) + { + auto & building = kvp.second; + + switch (building->subId) + { + case BuildingSubID::PORTAL_OF_SUMMONING: + creatures.resize(GameConstants::CREATURES_PER_TOWN + 1); + break; + ///'hasBuilt' checking for COPW bonuses is in the COPWBonus::onHeroVisit + case BuildingSubID::STABLES: + if(getBonusingBuilding(building->subId) == nullptr) + bonusingBuildings.push_back(new COPWBonus(BuildingID::STABLES, BuildingSubID::STABLES, this)); + break; + + case BuildingSubID::MANA_VORTEX: + if(getBonusingBuilding(building->subId) == nullptr) + bonusingBuildings.push_back(new COPWBonus(BuildingID::MANA_VORTEX, BuildingSubID::MANA_VORTEX, this)); + break; + ///add new bonus if bonusing building was built in the user added towns: + case BuildingSubID::BROTHERHOOD_OF_SWORD: + if(!hasBuiltInOldWay(ETownType::CASTLE, BuildingID::BROTHERHOOD)) + addBonusIfBuilt(BuildingID::BROTHERHOOD, BuildingSubID::BROTHERHOOD_OF_SWORD, Bonus::MORALE, +2); + break; + + case BuildingSubID::FOUNTAIN_OF_FORTUNE: + if(!hasBuiltInOldWay(ETownType::RAMPART, BuildingID::FOUNTAIN_OF_FORTUNE)) + addBonusIfBuilt(BuildingID::FOUNTAIN_OF_FORTUNE, BuildingSubID::FOUNTAIN_OF_FORTUNE, Bonus::LUCK, +2); + break; + + case BuildingSubID::SPELL_POWER_GARRISON_BONUS: + if(!hasBuiltInOldWay(ETownType::INFERNO, BuildingID::STORMCLOUDS)) + addBonusIfBuilt(BuildingID::STORMCLOUDS, BuildingSubID::SPELL_POWER_GARRISON_BONUS, Bonus::PRIMARY_SKILL, +2, PrimarySkill::SPELL_POWER); + break; + + case BuildingSubID::ATTACK_GARRISON_BONUS: + if(!hasBuiltInOldWay(ETownType::FORTRESS, BuildingID::BLOOD_OBELISK)) + addBonusIfBuilt(BuildingID::BLOOD_OBELISK, BuildingSubID::ATTACK_GARRISON_BONUS, Bonus::PRIMARY_SKILL, +2, PrimarySkill::ATTACK); + break; + + case BuildingSubID::DEFENSE_GARRISON_BONUS: + if(!hasBuiltInOldWay(ETownType::FORTRESS, BuildingID::GLYPHS_OF_FEAR)) + addBonusIfBuilt(BuildingID::GLYPHS_OF_FEAR, BuildingSubID::DEFENSE_GARRISON_BONUS, Bonus::PRIMARY_SKILL, +2, PrimarySkill::DEFENSE); + break; + } + } +} + +bool CGTownInstance::hasBuiltInOldWay(ETownType::ETownType type, BuildingID bid) const +{ + return (this->town->faction != nullptr && this->town->faction->index == type && hasBuilt(bid)); +} + void CGTownInstance::newTurn(CRandomGenerator & rand) const { if (cb->getDate(Date::DAY_OF_WEEK) == 1) //reset on new week @@ -1122,13 +1195,13 @@ void CGTownInstance::recreateBuildingsBonuses() removeBonus(b); //tricky! -> checks tavern only if no bratherhood of sword or not a castle - if(!addBonusIfBuilt(BuildingSubID::BROTHERHOOD_OF_SWORD, Bonus::MORALE, +2)) + if(!addBonusIfBuilt(BuildingID::BROTHERHOOD, BuildingSubID::BROTHERHOOD_OF_SWORD, Bonus::MORALE, +2)) addBonusIfBuilt(BuildingID::TAVERN, Bonus::MORALE, +1); - addBonusIfBuilt(BuildingSubID::FOUNTAIN_OF_FORTUNE, Bonus::LUCK, +2); //fountain of fortune - addBonusIfBuilt(BuildingSubID::SPELL_POWER_GARRISON_BONUS, Bonus::PRIMARY_SKILL, +2, PrimarySkill::SPELL_POWER);//works as Brimstone Clouds - addBonusIfBuilt(BuildingSubID::ATTACK_GARRISON_BONUS, Bonus::PRIMARY_SKILL, +2, PrimarySkill::ATTACK);//works as Blood Obelisk - addBonusIfBuilt(BuildingSubID::DEFENSE_GARRISON_BONUS, Bonus::PRIMARY_SKILL, +2, PrimarySkill::DEFENSE);//works as Glyphs of Fear + addBonusIfBuilt(BuildingID::FOUNTAIN_OF_FORTUNE, BuildingSubID::FOUNTAIN_OF_FORTUNE, Bonus::LUCK, +2); //fountain of fortune + addBonusIfBuilt(BuildingID::STORMCLOUDS, BuildingSubID::SPELL_POWER_GARRISON_BONUS, Bonus::PRIMARY_SKILL, +2, PrimarySkill::SPELL_POWER);//works as Brimstone Clouds + addBonusIfBuilt(BuildingID::BLOOD_OBELISK, BuildingSubID::ATTACK_GARRISON_BONUS, Bonus::PRIMARY_SKILL, +2, PrimarySkill::ATTACK);//works as Blood Obelisk + addBonusIfBuilt(BuildingID::GLYPHS_OF_FEAR, BuildingSubID::DEFENSE_GARRISON_BONUS, Bonus::PRIMARY_SKILL, +2, PrimarySkill::DEFENSE);//works as Glyphs of Fear if(subID == ETownType::CASTLE) //castle { @@ -1164,50 +1237,47 @@ void CGTownInstance::recreateBuildingsBonuses() } } -bool CGTownInstance::addBonusIfBuilt(BuildingSubID::EBuildingSubID building, Bonus::BonusType type, int val, int subtype) +bool CGTownInstance::addBonusIfBuilt(BuildingID bid, BuildingSubID::EBuildingSubID subId, Bonus::BonusType type, int val, int subtype) { - bool ret = false; + bool hasBuilt = false; + std::ostringstream descr; - if (hasBuilt(building)) + for (const auto & bid : builtBuildings) { - std::ostringstream descr; - - for (const auto & it : town->buildings) + if (town->buildings.at(bid)->subId == subId) { - if (it.second->subId == building) - { - descr << it.second->Name(); - break; - } + descr << town->buildings.at(bid)->Name(); + hasBuilt = true; + break; } - auto b = std::make_shared(Bonus::PERMANENT, type, Bonus::TOWN_STRUCTURE, val, building, descr.str(), subtype); - addNewBonus(b); //looks like a propagator is not necessary in this case - ret = true; } - return ret; + if(hasBuilt) + hasBuilt = addBonusImpl(bid, type, val, emptyPropagator, descr.str(), subtype); + return hasBuilt; } bool CGTownInstance::addBonusIfBuilt(BuildingID building, Bonus::BonusType type, int val, int subtype) { - static auto emptyPropagator = TPropagatorPtr(); return addBonusIfBuilt(building, type, val, emptyPropagator, subtype); } bool CGTownInstance::addBonusIfBuilt(BuildingID building, Bonus::BonusType type, int val, TPropagatorPtr & prop, int subtype) { - if(hasBuilt(building)) - { - std::ostringstream descr; - descr << town->buildings.at(building)->Name(); + if(!hasBuilt(building)) + return false; + + std::ostringstream descr; + descr << town->buildings.at(building)->Name(); + return addBonusImpl(building, type, val, prop, descr.str(), subtype); +} - auto b = std::make_shared(Bonus::PERMANENT, type, Bonus::TOWN_STRUCTURE, val, building, descr.str(), subtype); - if(prop) - b->addPropagator(prop); - addNewBonus(b); - return true; - } - - return false; +bool CGTownInstance::addBonusImpl(BuildingID building, Bonus::BonusType type, int val, TPropagatorPtr & prop, const std::string & description, int subtype) +{ + auto b = std::make_shared(Bonus::PERMANENT, type, Bonus::TOWN_STRUCTURE, val, building, description, subtype); + if(prop) + b->addPropagator(prop); + addNewBonus(b); + return true; } void CGTownInstance::setVisitingHero(CGHeroInstance *h) @@ -1402,7 +1472,7 @@ CBuilding::TRequired CGTownInstance::genBuildingRequirements(BuildingID buildID, return ret; } -void CGTownInstance::addHeroToStructureVisitors( const CGHeroInstance *h, si64 structureInstanceID ) const +void CGTownInstance::addHeroToStructureVisitors(const CGHeroInstance *h, si64 structureInstanceID ) const { if(visitingHero == h) cb->setObjProperty(id, ObjProperty::STRUCTURE_ADD_VISITING_HERO, structureInstanceID); //add to visitors @@ -1583,7 +1653,7 @@ void COPWBonus::setProperty(ui8 what, ui32 val) } } -void COPWBonus::onHeroVisit (const CGHeroInstance * h) const +void COPWBonus::onHeroVisit(const CGHeroInstance * h) const { ObjectInstanceID heroID = h->id; if (town->hasBuilt(bID)) diff --git a/lib/mapObjects/CGTownInstance.h b/lib/mapObjects/CGTownInstance.h index c44fcb7bf..85da7c8e2 100644 --- a/lib/mapObjects/CGTownInstance.h +++ b/lib/mapObjects/CGTownInstance.h @@ -107,6 +107,18 @@ public: return bType; } + STRONG_INLINE + const BuildingID & getBuildingType() const + { + return bID; + } + + STRONG_INLINE + void setBuildingSubtype(BuildingSubID::EBuildingSubID subId) + { + bType = subId; + } + template void serialize(Handler &h, const int version) { h & bID; @@ -114,8 +126,6 @@ public: if(version >= 792) h & bType; - else if(!h.saving) - bType = BuildingSubID::NONE; } protected: BuildingID bID; //from buildig list @@ -240,6 +250,9 @@ public: } return false; }); + + if(!h.saving && version < 792) + updateBonusingBuildings(); } ////////////////////////////////////////////////////////////////////////// @@ -248,7 +261,8 @@ public: void updateMoraleBonusFromArmy() override; void deserializationFix(); void recreateBuildingsBonuses(); - bool addBonusIfBuilt(BuildingSubID::EBuildingSubID building, Bonus::BonusType type, int val, int subtype = -1); + ///bid: param to bind a building with a bonus, subId: param to check if already built + bool addBonusIfBuilt(BuildingID bid, BuildingSubID::EBuildingSubID subId, Bonus::BonusType type, int val, int subtype = -1); bool addBonusIfBuilt(BuildingID building, Bonus::BonusType type, int val, TPropagatorPtr &prop, int subtype = -1); //returns true if building is built and bonus has been added bool addBonusIfBuilt(BuildingID building, Bonus::BonusType type, int val, int subtype = -1); //convienence version of above void setVisitingHero(CGHeroInstance *h); @@ -317,8 +331,12 @@ public: void afterAddToMap(CMap * map) override; static void reset(); protected: + static TPropagatorPtr emptyPropagator; void setPropertyDer(ui8 what, ui32 val) override; void serializeJsonOptions(JsonSerializeFormat & handler) override; private: int getDwellingBonus(const std::vector& creatureIds, const std::vector >& dwellings) const; + void updateBonusingBuildings(); + bool hasBuiltInOldWay(ETownType::ETownType type, BuildingID bid) const; + bool addBonusImpl(BuildingID building, Bonus::BonusType type, int val, TPropagatorPtr & prop, const std::string & description, int subtype = -1); }; diff --git a/lib/mapObjects/CObjectClassesHandler.cpp b/lib/mapObjects/CObjectClassesHandler.cpp index 86da0dcd6..5c8794d3a 100644 --- a/lib/mapObjects/CObjectClassesHandler.cpp +++ b/lib/mapObjects/CObjectClassesHandler.cpp @@ -214,7 +214,7 @@ CObjectClassesHandler::ObjectContainter * CObjectClassesHandler::loadFromJson(co if(json["defaultAiValue"].isNull()) obj->groupDefaultAiValue = boost::none; else - obj->groupDefaultAiValue = static_cast(json["defaultAiValue"].Integer()); + obj->groupDefaultAiValue = static_cast>(json["defaultAiValue"].Integer()); for (auto entry : json["types"].Struct()) { @@ -475,7 +475,7 @@ void AObjectTypeHandler::init(const JsonNode & input, boost::optional(input["aiValue"].Integer()); + aiValue = static_cast>(input["aiValue"].Integer()); initTypeData(input); } diff --git a/server/CGameHandler.cpp b/server/CGameHandler.cpp index 2cd6f2126..7767c548d 100644 --- a/server/CGameHandler.cpp +++ b/server/CGameHandler.cpp @@ -2521,9 +2521,8 @@ void CGameHandler::heroVisitCastle(const CGTownInstance * obj, const CGHeroInsta void CGameHandler::visitCastleObjects(const CGTownInstance * t, const CGHeroInstance * h) { - std::vector::const_iterator i; - for (i = t->bonusingBuildings.begin(); i != t->bonusingBuildings.end(); i++) - (*i)->onHeroVisit (h); + for (auto building : t->bonusingBuildings) + building->onHeroVisit(h); } void CGameHandler::stopHeroVisitCastle(const CGTownInstance * obj, const CGHeroInstance * hero)