mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-24 22:14:36 +02:00
Feature: Mods system improvement, Part III. Bunusing buildings customization.
This commit is contained in:
parent
9cf953157a
commit
854a2e6c39
@ -88,7 +88,7 @@ size_t OptionsTab::CPlayerSettingsHelper::getImageIndex()
|
|||||||
switch(type)
|
switch(type)
|
||||||
{
|
{
|
||||||
case TOWN:
|
case TOWN:
|
||||||
switch (settings.castle)
|
switch(settings.castle)
|
||||||
{
|
{
|
||||||
case PlayerSettings::NONE:
|
case PlayerSettings::NONE:
|
||||||
return TOWN_NONE;
|
return TOWN_NONE;
|
||||||
|
@ -176,7 +176,7 @@
|
|||||||
"ship": { "id" : 20, "upgrades" : "shipyard" },
|
"ship": { "id" : 20, "upgrades" : "shipyard" },
|
||||||
"special2": { "type" : "stables", "requires" : [ "dwellingLvl4" ] },
|
"special2": { "type" : "stables", "requires" : [ "dwellingLvl4" ] },
|
||||||
"special3": { "type" : "brotherhoodOfSword", "upgrades" : "tavern" },
|
"special3": { "type" : "brotherhoodOfSword", "upgrades" : "tavern" },
|
||||||
"grail": { "id" : 26, "mode" : "grail", "produce": { "gold": 5000 }},
|
"grail": { "id" : 26, "mode" : "grail", "produce": { "gold": 5000 }, "bonuses": [ { "type": "MORALE", "val": 2, "propagator": "PLAYER_PROPAGATOR" } ] },
|
||||||
|
|
||||||
"dwellingLvl1": { "id" : 30, "requires" : [ "fort" ] },
|
"dwellingLvl1": { "id" : 30, "requires" : [ "fort" ] },
|
||||||
"dwellingLvl2": { "id" : 31, "requires" : [ "dwellingLvl1" ] },
|
"dwellingLvl2": { "id" : 31, "requires" : [ "dwellingLvl1" ] },
|
||||||
|
@ -175,7 +175,8 @@
|
|||||||
"special2": { "type" : "manaVortex", "requires" : [ "mageGuild1" ] },
|
"special2": { "type" : "manaVortex", "requires" : [ "mageGuild1" ] },
|
||||||
"special3": { "type" : "portalOfSummoning" },
|
"special3": { "type" : "portalOfSummoning" },
|
||||||
"special4": { "type" : "experienceVisitingBonus" },
|
"special4": { "type" : "experienceVisitingBonus" },
|
||||||
"grail": { "id" : 26, "mode" : "grail", "produce": { "gold": 5000 }},
|
"grail": { "id" : 26, "mode" : "grail", "produce": { "gold": 5000 },
|
||||||
|
"bonuses": [ { "type": "PRIMARY_SKILL", "subtype": "primSkill.spellpower", "val": 12 } ] },
|
||||||
|
|
||||||
"dwellingLvl1": { "id" : 30, "requires" : [ "fort" ] },
|
"dwellingLvl1": { "id" : 30, "requires" : [ "fort" ] },
|
||||||
"dwellingLvl2": { "id" : 31, "requires" : [ "dwellingLvl1" ] },
|
"dwellingLvl2": { "id" : 31, "requires" : [ "dwellingLvl1" ] },
|
||||||
|
@ -175,9 +175,14 @@
|
|||||||
"ship": { "id" : 20, "upgrades" : "shipyard" },
|
"ship": { "id" : 20, "upgrades" : "shipyard" },
|
||||||
"special2": { "type" : "defenseGarrisonBonus", "requires" : [ "fort" ] },
|
"special2": { "type" : "defenseGarrisonBonus", "requires" : [ "fort" ] },
|
||||||
"special3": { "type" : "attackGarrisonBonus", "requires" : [ "special2" ] },
|
"special3": { "type" : "attackGarrisonBonus", "requires" : [ "special2" ] },
|
||||||
"grail": { "id" : 26, "mode" : "grail", "produce": { "gold": 5000 }},
|
"grail": { "id" : 26, "mode" : "grail", "produce": { "gold": 5000 },
|
||||||
"extraCapitol": { "id" : 29, "requires" : [ "capitol" ], "mode" : "auto" },
|
"bonuses": [
|
||||||
|
{ "type": "PRIMARY_SKILL", "subtype": "primSkill.attack", "val": 10 },
|
||||||
|
{ "type": "PRIMARY_SKILL", "subtype": "primSkill.defence", "val": 10 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
"extraCapitol": { "id" : 29, "requires" : [ "capitol" ], "mode" : "auto" },
|
||||||
"dwellingLvl1": { "id" : 30, "requires" : [ "fort" ] },
|
"dwellingLvl1": { "id" : 30, "requires" : [ "fort" ] },
|
||||||
"dwellingLvl2": { "id" : 31, "requires" : [ "dwellingLvl1" ] },
|
"dwellingLvl2": { "id" : 31, "requires" : [ "dwellingLvl1" ] },
|
||||||
"dwellingLvl3": { "id" : 32, "requires" : [ "dwellingLvl1" ] },
|
"dwellingLvl3": { "id" : 32, "requires" : [ "dwellingLvl1" ] },
|
||||||
|
@ -175,13 +175,16 @@
|
|||||||
"resourceSilo": { "id" : 15, "requires" : [ "marketplace" ], "produce": { "ore": 1, "wood": 1 } },
|
"resourceSilo": { "id" : 15, "requires" : [ "marketplace" ], "produce": { "ore": 1, "wood": 1 } },
|
||||||
"blacksmith": { "id" : 16 },
|
"blacksmith": { "id" : 16 },
|
||||||
|
|
||||||
"special1": { "requires" : [ "fort" ] },
|
"special1": { "requires" : [ "fort" ], "bonuses": [ { "type": "DARKNESS", "val": 20 } ] },
|
||||||
"horde1": { "id" : 18, "upgrades" : "dwellingLvl1", "requires" : [ "special3" ] },
|
"horde1": { "id" : 18, "upgrades" : "dwellingLvl1", "requires" : [ "special3" ] },
|
||||||
"horde1Upgr": { "id" : 19, "upgrades" : "dwellingUpLvl1", "requires" : [ "horde1" ], "mode" : "auto" },
|
"horde1Upgr": { "id" : 19, "upgrades" : "dwellingUpLvl1", "requires" : [ "horde1" ], "mode" : "auto" },
|
||||||
"ship": { "id" : 20, "upgrades" : "shipyard" },
|
"ship": { "id" : 20, "upgrades" : "shipyard" },
|
||||||
"special2": { "requires" : [ "mageGuild1" ] },
|
"special2": { "requires" : [ "mageGuild1" ],
|
||||||
|
"bonuses": [ { "type": "SECONDARY_SKILL_PREMY", "subtype": "skill.necromancy", "val": 10, "propagator": "PLAYER_PROPAGATOR" } ] },
|
||||||
"special3": { "type" : "creatureTransformer", "requires" : [ "dwellingLvl1" ] },
|
"special3": { "type" : "creatureTransformer", "requires" : [ "dwellingLvl1" ] },
|
||||||
"grail": { "id" : 26, "mode" : "grail", "produce": { "gold": 5000 }},
|
"grail": { "id" : 26, "mode" : "grail", "produce": { "gold": 5000 },
|
||||||
|
"bonuses": [ { "type": "SECONDARY_SKILL_PREMY", "subtype": "skill.necromancy", "val": 20, "propagator": "PLAYER_PROPAGATOR" } ] },
|
||||||
|
|
||||||
"extraTownHall": { "id" : 27, "requires" : [ "townHall" ], "mode" : "auto" },
|
"extraTownHall": { "id" : 27, "requires" : [ "townHall" ], "mode" : "auto" },
|
||||||
"extraCityHall": { "id" : 28, "requires" : [ "cityHall" ], "mode" : "auto" },
|
"extraCityHall": { "id" : 28, "requires" : [ "cityHall" ], "mode" : "auto" },
|
||||||
"extraCapitol": { "id" : 29, "requires" : [ "capitol" ], "mode" : "auto" },
|
"extraCapitol": { "id" : 29, "requires" : [ "capitol" ], "mode" : "auto" },
|
||||||
|
@ -181,7 +181,8 @@
|
|||||||
"special3": { "type" : "treasury", "requires" : [ "horde1" ] },
|
"special3": { "type" : "treasury", "requires" : [ "horde1" ] },
|
||||||
"horde2": { "id" : 24, "upgrades" : "dwellingLvl5" },
|
"horde2": { "id" : 24, "upgrades" : "dwellingLvl5" },
|
||||||
"horde2Upgr": { "id" : 25, "upgrades" : "dwellingUpLvl5", "requires" : [ "horde2" ], "mode" : "auto" },
|
"horde2Upgr": { "id" : 25, "upgrades" : "dwellingUpLvl5", "requires" : [ "horde2" ], "mode" : "auto" },
|
||||||
"grail": { "id" : 26, "mode" : "grail", "produce": { "gold": 5000 }},
|
"grail": { "id" : 26, "mode" : "grail", "produce": { "gold": 5000 }, "bonuses": [ { "type": "LUCK", "val": 2, "propagator": "PLAYER_PROPAGATOR" } ] },
|
||||||
|
|
||||||
"extraTownHall": { "id" : 27, "requires" : [ "townHall" ], "mode" : "auto" },
|
"extraTownHall": { "id" : 27, "requires" : [ "townHall" ], "mode" : "auto" },
|
||||||
"extraCityHall": { "id" : 28, "requires" : [ "cityHall" ], "mode" : "auto" },
|
"extraCityHall": { "id" : 28, "requires" : [ "cityHall" ], "mode" : "auto" },
|
||||||
"extraCapitol": { "id" : 29, "requires" : [ "capitol" ], "mode" : "auto" },
|
"extraCapitol": { "id" : 29, "requires" : [ "capitol" ], "mode" : "auto" },
|
||||||
|
@ -172,7 +172,8 @@
|
|||||||
"special2": { "type" : "freelancersGuild", "requires" : [ "marketplace" ] },
|
"special2": { "type" : "freelancersGuild", "requires" : [ "marketplace" ] },
|
||||||
"special3": { "type" : "ballistaYard", "requires" : [ "blacksmith" ] },
|
"special3": { "type" : "ballistaYard", "requires" : [ "blacksmith" ] },
|
||||||
"special4": { "type" : "attackVisitingBonus", "requires" : [ "fort" ] },
|
"special4": { "type" : "attackVisitingBonus", "requires" : [ "fort" ] },
|
||||||
"grail": { "id" : 26, "mode" : "grail", "produce": { "gold": 5000 }},
|
"grail": { "id" : 26, "mode" : "grail", "produce": { "gold": 5000 },
|
||||||
|
"bonuses": [ { "type": "PRIMARY_SKILL", "subtype": "primSkill.attack", "val": 20 } ] },
|
||||||
|
|
||||||
"dwellingLvl1": { "id" : 30, "requires" : [ "fort" ] },
|
"dwellingLvl1": { "id" : 30, "requires" : [ "fort" ] },
|
||||||
"dwellingLvl2": { "id" : 31, "requires" : [ "dwellingLvl1" ] },
|
"dwellingLvl2": { "id" : 31, "requires" : [ "dwellingLvl1" ] },
|
||||||
|
@ -175,7 +175,7 @@
|
|||||||
"special2": { "type" : "lookoutTower", "height" : "high", "requires" : [ "fort" ] },
|
"special2": { "type" : "lookoutTower", "height" : "high", "requires" : [ "fort" ] },
|
||||||
"special3": { "type" : "library", "requires" : [ "mageGuild1" ] },
|
"special3": { "type" : "library", "requires" : [ "mageGuild1" ] },
|
||||||
"special4": { "type" : "knowledgeVisitingBonus", "requires" : [ "mageGuild1" ] },
|
"special4": { "type" : "knowledgeVisitingBonus", "requires" : [ "mageGuild1" ] },
|
||||||
"grail": { "height" : "skyship", "produce" : { "gold": 5000 } },
|
"grail": { "height" : "skyship", "produce" : { "gold": 5000 }, "bonuses": [ { "type": "PRIMARY_SKILL", "subtype": "primSkill.knowledge", "val": 15 } ] },
|
||||||
|
|
||||||
"dwellingLvl1": { "id" : 30, "requires" : [ "fort" ] },
|
"dwellingLvl1": { "id" : 30, "requires" : [ "fort" ] },
|
||||||
"dwellingLvl2": { "id" : 31, "requires" : [ "dwellingLvl1" ] },
|
"dwellingLvl2": { "id" : 31, "requires" : [ "dwellingLvl1" ] },
|
||||||
|
@ -85,7 +85,25 @@
|
|||||||
"gems": { "type":"number"},
|
"gems": { "type":"number"},
|
||||||
"gold": { "type":"number"}
|
"gold": { "type":"number"}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"overrides": {
|
||||||
|
"type" : "array",
|
||||||
|
"items" : [
|
||||||
|
{
|
||||||
|
"description" : "The buildings which bonuses should be overridden with bonuses of the current building",
|
||||||
|
"type" : "string"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"bonuses": {
|
||||||
|
"type":"array",
|
||||||
|
"description": "Bonuses, provided by this special building on build using bonus system",
|
||||||
|
"items": { "$ref" : "bonus.json" }
|
||||||
|
},
|
||||||
|
"onVisitBonuses": {
|
||||||
|
"type":"array",
|
||||||
|
"description": "Bonuses, provided by this special building on hero visit and applied to the visiting hero",
|
||||||
|
"items": { "$ref" : "bonus.json" }
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -51,7 +51,9 @@
|
|||||||
"greetingAttack" : "Some time spent at the %s allows you to learn more effective combat skills (+1 Attack Skill).",
|
"greetingAttack" : "Some time spent at the %s allows you to learn more effective combat skills (+1 Attack Skill).",
|
||||||
"greetingDefence" : "Spending time in the %s, the experienced warriors therein teach you additional defensive skills (+1 Defense).",
|
"greetingDefence" : "Spending time in the %s, the experienced warriors therein teach you additional defensive skills (+1 Defense).",
|
||||||
"hasNotProduced" : "The %s has not produced anything yet.",
|
"hasNotProduced" : "The %s has not produced anything yet.",
|
||||||
"hasProduced" : "The %s produced %d %s this week."
|
"hasProduced" : "The %s produced %d %s this week.",
|
||||||
|
"greetingCustomBonus" : "%s gives you +%d %s%s",
|
||||||
|
"greetingCustomUntil" : " until next battle."
|
||||||
},
|
},
|
||||||
"logicalExpressions" :
|
"logicalExpressions" :
|
||||||
{
|
{
|
||||||
|
@ -1210,6 +1210,11 @@ void CCreatureHandler::removeBonusesFromAllCreatures()
|
|||||||
allCreatures.removeBonuses(Selector::all);
|
allCreatures.removeBonuses(Selector::all);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CCreatureHandler::restoreAllCreaturesNodeType794()
|
||||||
|
{
|
||||||
|
allCreatures.setNodeType(CBonusSystemNode::ENodeTypes::ALL_CREATURES);
|
||||||
|
}
|
||||||
|
|
||||||
void CCreatureHandler::buildBonusTreeForTiers()
|
void CCreatureHandler::buildBonusTreeForTiers()
|
||||||
{
|
{
|
||||||
for(CCreature *c : creatures)
|
for(CCreature *c : creatures)
|
||||||
|
@ -249,6 +249,7 @@ public:
|
|||||||
void addBonusForTier(int tier, std::shared_ptr<Bonus> b); //tier must be <1-7>
|
void addBonusForTier(int tier, std::shared_ptr<Bonus> b); //tier must be <1-7>
|
||||||
void addBonusForAllCreatures(std::shared_ptr<Bonus> b);
|
void addBonusForAllCreatures(std::shared_ptr<Bonus> b);
|
||||||
void removeBonusesFromAllCreatures();
|
void removeBonusesFromAllCreatures();
|
||||||
|
void restoreAllCreaturesNodeType794(); //restore ALL_CREATURES node type for old saves
|
||||||
|
|
||||||
CCreatureHandler();
|
CCreatureHandler();
|
||||||
~CCreatureHandler();
|
~CCreatureHandler();
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
#include "filesystem/Filesystem.h"
|
#include "filesystem/Filesystem.h"
|
||||||
#include "mapObjects/CObjectClassesHandler.h"
|
#include "mapObjects/CObjectClassesHandler.h"
|
||||||
#include "mapObjects/CObjectHandler.h"
|
#include "mapObjects/CObjectHandler.h"
|
||||||
|
#include "HeroBonus.h"
|
||||||
|
|
||||||
const int NAMES_PER_TOWN=16; // number of town names per faction in H3 files. Json can define any number
|
const int NAMES_PER_TOWN=16; // number of town names per faction in H3 files. Json can define any number
|
||||||
|
|
||||||
@ -93,7 +94,37 @@ void CBuilding::deserializeFix()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CBuilding::update792(const BuildingID & bid, BuildingSubID::EBuildingSubID & subId, ETowerHeight & height)
|
void CBuilding::addNewBonus(std::shared_ptr<Bonus> b, BonusList & bonusList)
|
||||||
|
{
|
||||||
|
bonusList.push_back(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
const JsonNode & CBuilding::getCurrentFactionForUpdateRoutine() const
|
||||||
|
{
|
||||||
|
const auto & faction = town->faction->identifier;
|
||||||
|
const auto & factionsContent = (*VLC->modh->content)["factions"];
|
||||||
|
const auto & coreData = factionsContent.modData.at("core");
|
||||||
|
const auto & coreFactions = coreData.modData;
|
||||||
|
const 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 currentFaction;
|
||||||
|
}
|
||||||
|
const std::string modFaction = index == std::string::npos ? faction : faction.substr(index + 1);
|
||||||
|
return it->second.modData[modFaction];
|
||||||
|
}
|
||||||
|
return currentFaction;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CBuilding::update792()
|
||||||
{
|
{
|
||||||
subId = BuildingSubID::NONE;
|
subId = BuildingSubID::NONE;
|
||||||
height = ETowerHeight::HEIGHT_NO_TOWER;
|
height = ETowerHeight::HEIGHT_NO_TOWER;
|
||||||
@ -106,37 +137,72 @@ void CBuilding::update792(const BuildingID & bid, BuildingSubID::EBuildingSubID
|
|||||||
if(buildingName.empty())
|
if(buildingName.empty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const auto & faction = town->faction->identifier;
|
auto & currentFaction = getCurrentFactionForUpdateRoutine();
|
||||||
auto factionsContent = (*VLC->modh->content)["factions"];
|
|
||||||
auto & coreData = factionsContent.modData.at("core");
|
|
||||||
auto & coreFactions = coreData.modData;
|
|
||||||
auto & currentFaction = coreFactions[faction];
|
|
||||||
|
|
||||||
if (currentFaction.isNull())
|
if(!currentFaction.isNull() && currentFaction.getType() == JsonNode::JsonType::DATA_STRUCT)
|
||||||
{
|
|
||||||
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 & buildings = currentFaction["town"]["buildings"];
|
||||||
const auto & currentBuilding = buildings[buildingName];
|
const auto & currentBuilding = buildings[buildingName];
|
||||||
|
|
||||||
subId = CTownHandler::getMappedValue<BuildingSubID::EBuildingSubID>(currentBuilding["type"], BuildingSubID::NONE, MappedKeys::SPECIAL_BUILDINGS);
|
subId = CTownHandler::getMappedValue<BuildingSubID::EBuildingSubID>(currentBuilding["type"], BuildingSubID::NONE, MappedKeys::SPECIAL_BUILDINGS);
|
||||||
height = CBuilding::HEIGHT_NO_TOWER;
|
height = subId == BuildingSubID::LOOKOUT_TOWER || bid == BuildingID::GRAIL
|
||||||
|
? CTownHandler::getMappedValue<CBuilding::ETowerHeight>(currentBuilding["height"], CBuilding::HEIGHT_NO_TOWER, CBuilding::TOWER_TYPES)
|
||||||
|
: height = CBuilding::HEIGHT_NO_TOWER;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (subId == BuildingSubID::LOOKOUT_TOWER || bid == BuildingID::GRAIL)
|
void CBuilding::update794()
|
||||||
height = CTownHandler::getMappedValue<CBuilding::ETowerHeight>(currentBuilding["height"], CBuilding::HEIGHT_NO_TOWER, CBuilding::TOWER_TYPES);
|
{
|
||||||
|
if(bid == BuildingID::TAVERN || subId == BuildingSubID::BROTHERHOOD_OF_SWORD)
|
||||||
|
{
|
||||||
|
VLC->townh->addBonusesForVanilaBuilding(this);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(!bid.IsSpecialOrGrail())
|
||||||
|
return;
|
||||||
|
|
||||||
|
VLC->townh->addBonusesForVanilaBuilding(this);
|
||||||
|
|
||||||
|
if(!buildingBonuses.empty() //addBonusesForVanilaBuilding has done all work
|
||||||
|
|| town->faction == nullptr //or faction data is not valid
|
||||||
|
|| town->faction->identifier.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
const auto buildingName = CTownHandler::getMappedValue<std::string, BuildingID>(bid, std::string(), MappedKeys::BUILDING_TYPES_TO_NAMES, false);
|
||||||
|
|
||||||
|
if(buildingName.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto & currentFaction = getCurrentFactionForUpdateRoutine();
|
||||||
|
|
||||||
|
if(currentFaction.isNull() || currentFaction.getType() != JsonNode::JsonType::DATA_STRUCT)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const auto & buildings = currentFaction["town"]["buildings"];
|
||||||
|
const auto & currentBuilding = buildings[buildingName];
|
||||||
|
|
||||||
|
CTownHandler::loadSpecialBuildingBonuses(currentBuilding["bonuses"], buildingBonuses, this);
|
||||||
|
CTownHandler::loadSpecialBuildingBonuses(currentBuilding["onVisitBonuses"], onVisitBonuses, this);
|
||||||
|
|
||||||
|
if(!onVisitBonuses.empty())
|
||||||
|
{
|
||||||
|
if(subId == BuildingSubID::NONE)
|
||||||
|
subId = BuildingSubID::CUSTOM_VISITING_BONUS;
|
||||||
|
|
||||||
|
for(auto & bonus : onVisitBonuses)
|
||||||
|
bonus->sid = Bonus::getSid32(town->faction->index, bid);
|
||||||
|
}
|
||||||
|
const auto & overriddenBids = currentBuilding["overrides"];
|
||||||
|
|
||||||
|
if(overriddenBids.isNull())
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto scope = town->getBuildingScope();
|
||||||
|
|
||||||
|
for(auto b : overriddenBids.Vector())
|
||||||
|
{
|
||||||
|
auto bid = BuildingID(VLC->modh->identifiers.getIdentifier(scope, b).get());
|
||||||
|
overrideBids.insert(bid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -258,6 +324,8 @@ JsonNode readBuilding(CLegacyConfigParser & parser)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TPropagatorPtr CTownHandler::emptyPropagator = std::make_shared<CPropagatorNodeType>();
|
||||||
|
|
||||||
std::vector<JsonNode> CTownHandler::loadLegacyData(size_t dataSize)
|
std::vector<JsonNode> CTownHandler::loadLegacyData(size_t dataSize)
|
||||||
{
|
{
|
||||||
std::vector<JsonNode> dest(dataSize);
|
std::vector<JsonNode> dest(dataSize);
|
||||||
@ -412,7 +480,7 @@ std::vector<JsonNode> CTownHandler::loadLegacyData(size_t dataSize)
|
|||||||
return dest;
|
return dest;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CTownHandler::loadBuildingRequirements(CBuilding * building, const JsonNode & source)
|
void CTownHandler::loadBuildingRequirements(CBuilding * building, const JsonNode & source, std::vector<BuildingRequirementsHelper> & bidsToLoad)
|
||||||
{
|
{
|
||||||
if (source.isNull())
|
if (source.isNull())
|
||||||
return;
|
return;
|
||||||
@ -421,7 +489,7 @@ void CTownHandler::loadBuildingRequirements(CBuilding * building, const JsonNode
|
|||||||
hlp.building = building;
|
hlp.building = building;
|
||||||
hlp.town = building->town;
|
hlp.town = building->town;
|
||||||
hlp.json = source;
|
hlp.json = source;
|
||||||
requirementsToLoad.push_back(hlp);
|
bidsToLoad.push_back(hlp);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename R, typename K>
|
template<typename R, typename K>
|
||||||
@ -445,6 +513,100 @@ R CTownHandler::getMappedValue(const JsonNode & node, const R defval, const std:
|
|||||||
return defval;
|
return defval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CTownHandler::addBonusesForVanilaBuilding(CBuilding * building)
|
||||||
|
{
|
||||||
|
std::shared_ptr<Bonus> b;
|
||||||
|
static TPropagatorPtr playerPropagator = std::make_shared<CPropagatorNodeType>(CBonusSystemNode::ENodeTypes::PLAYER);
|
||||||
|
|
||||||
|
if(building->subId == BuildingSubID::NONE)
|
||||||
|
{
|
||||||
|
if(building->bid == BuildingID::TAVERN)
|
||||||
|
b = createBonus(building, Bonus::MORALE, +1);
|
||||||
|
else if(building->bid == BuildingID::GRAIL
|
||||||
|
&& building->town->faction != nullptr
|
||||||
|
&& boost::algorithm::ends_with(building->town->faction->identifier, ":cove"))
|
||||||
|
{
|
||||||
|
static TPropagatorPtr allCreaturesPropagator(new CPropagatorNodeType(CBonusSystemNode::ENodeTypes::ALL_CREATURES));
|
||||||
|
static auto factionLimiter = std::make_shared<CreatureFactionLimiter>(building->town->faction->index);
|
||||||
|
b = createBonus(building, Bonus::NO_TERRAIN_PENALTY, 0, allCreaturesPropagator);
|
||||||
|
b->addLimiter(factionLimiter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
switch(building->subId)
|
||||||
|
{
|
||||||
|
case BuildingSubID::BROTHERHOOD_OF_SWORD:
|
||||||
|
b = createBonus(building, Bonus::MORALE, +2);
|
||||||
|
building->overrideBids.insert(BuildingID::TAVERN);
|
||||||
|
break;
|
||||||
|
case BuildingSubID::FOUNTAIN_OF_FORTUNE:
|
||||||
|
b = createBonus(building, Bonus::LUCK, +2);
|
||||||
|
break;
|
||||||
|
case BuildingSubID::SPELL_POWER_GARRISON_BONUS:
|
||||||
|
b = createBonus(building, Bonus::PRIMARY_SKILL, +2, PrimarySkill::SPELL_POWER);
|
||||||
|
break;
|
||||||
|
case BuildingSubID::ATTACK_GARRISON_BONUS:
|
||||||
|
b = createBonus(building, Bonus::PRIMARY_SKILL, +2, PrimarySkill::ATTACK);
|
||||||
|
break;
|
||||||
|
case BuildingSubID::DEFENSE_GARRISON_BONUS:
|
||||||
|
b = createBonus(building, Bonus::PRIMARY_SKILL, +2, PrimarySkill::DEFENSE);
|
||||||
|
break;
|
||||||
|
case BuildingSubID::LIGHTHOUSE:
|
||||||
|
b = createBonus(building, Bonus::SEA_MOVEMENT, +500, playerPropagator);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(b)
|
||||||
|
building->addNewBonus(b, building->buildingBonuses);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<Bonus> CTownHandler::createBonus(CBuilding * build, Bonus::BonusType type, int val, int subtype)
|
||||||
|
{
|
||||||
|
return createBonus(build, type, val, emptyPropagator, subtype);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<Bonus> CTownHandler::createBonus(CBuilding * build, Bonus::BonusType type, int val, TPropagatorPtr & prop, int subtype)
|
||||||
|
{
|
||||||
|
std::ostringstream descr;
|
||||||
|
descr << build->name;
|
||||||
|
return createBonusImpl(build->bid, type, val, prop, descr.str(), subtype);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<Bonus> CTownHandler::createBonusImpl(BuildingID building, Bonus::BonusType type, int val, TPropagatorPtr & prop, const std::string & description, int subtype)
|
||||||
|
{
|
||||||
|
auto b = std::make_shared<Bonus>(Bonus::PERMANENT, type, Bonus::TOWN_STRUCTURE, val, building, description, subtype);
|
||||||
|
|
||||||
|
if(prop)
|
||||||
|
b->addPropagator(prop);
|
||||||
|
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CTownHandler::loadSpecialBuildingBonuses(const JsonNode & source, BonusList & bonusList, CBuilding * building)
|
||||||
|
{
|
||||||
|
for(auto b : source.Vector())
|
||||||
|
{
|
||||||
|
auto bonus = JsonUtils::parseBuildingBonus(b, building->bid, building->name);
|
||||||
|
|
||||||
|
if(bonus == nullptr)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if(bonus->limiter != nullptr)
|
||||||
|
{
|
||||||
|
auto limPtr = dynamic_cast<CreatureFactionLimiter*>(bonus->limiter.get());
|
||||||
|
|
||||||
|
if(limPtr != nullptr && limPtr->faction == (TFaction)-1)
|
||||||
|
limPtr->faction = building->town->faction->index;
|
||||||
|
}
|
||||||
|
//JsonUtils::parseBuildingBonus produces UNKNOWN type propagator instead of empty.
|
||||||
|
if(bonus->propagator != nullptr
|
||||||
|
&& bonus->propagator->getPropagatorType() == CBonusSystemNode::ENodeTypes::UNKNOWN)
|
||||||
|
bonus->addPropagator(emptyPropagator);
|
||||||
|
building->addNewBonus(bonus, bonusList);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void CTownHandler::loadBuilding(CTown * town, const std::string & stringID, const JsonNode & source)
|
void CTownHandler::loadBuilding(CTown * town, const std::string & stringID, const JsonNode & source)
|
||||||
{
|
{
|
||||||
auto ret = new CBuilding();
|
auto ret = new CBuilding();
|
||||||
@ -474,6 +636,26 @@ void CTownHandler::loadBuilding(CTown * town, const std::string & stringID, cons
|
|||||||
ret->resources = TResources(source["cost"]);
|
ret->resources = TResources(source["cost"]);
|
||||||
ret->produce = TResources(source["produce"]);
|
ret->produce = TResources(source["produce"]);
|
||||||
|
|
||||||
|
if(ret->bid == BuildingID::TAVERN)
|
||||||
|
addBonusesForVanilaBuilding(ret);
|
||||||
|
else if(ret->bid.IsSpecialOrGrail())
|
||||||
|
{
|
||||||
|
loadSpecialBuildingBonuses(source["bonuses"], ret->buildingBonuses, ret);
|
||||||
|
|
||||||
|
if(ret->buildingBonuses.empty())
|
||||||
|
addBonusesForVanilaBuilding(ret);
|
||||||
|
|
||||||
|
loadSpecialBuildingBonuses(source["onVisitBonuses"], ret->onVisitBonuses, ret);
|
||||||
|
|
||||||
|
if(!ret->onVisitBonuses.empty())
|
||||||
|
{
|
||||||
|
if(ret->subId == BuildingSubID::NONE)
|
||||||
|
ret->subId = BuildingSubID::CUSTOM_VISITING_BONUS;
|
||||||
|
|
||||||
|
for(auto & bonus : ret->onVisitBonuses)
|
||||||
|
bonus->sid = Bonus::getSid32(ret->town->faction->index, ret->bid);
|
||||||
|
}
|
||||||
|
}
|
||||||
//MODS COMPATIBILITY FOR 0.96
|
//MODS COMPATIBILITY FOR 0.96
|
||||||
if(!ret->produce.nonZero())
|
if(!ret->produce.nonZero())
|
||||||
{
|
{
|
||||||
@ -501,8 +683,10 @@ void CTownHandler::loadBuilding(CTown * town, const std::string & stringID, cons
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
loadBuildingRequirements(ret, source["requires"], requirementsToLoad);
|
||||||
|
|
||||||
loadBuildingRequirements(ret, source["requires"]);
|
if(ret->bid.IsSpecialOrGrail())
|
||||||
|
loadBuildingRequirements(ret, source["overrides"], overriddenBidsToLoad);
|
||||||
|
|
||||||
if (!source["upgrades"].isNull())
|
if (!source["upgrades"].isNull())
|
||||||
{
|
{
|
||||||
@ -828,9 +1012,10 @@ ETerrainType::EETerrainType CTownHandler::getDefaultTerrainForAlignment(EAlignme
|
|||||||
return terrain;
|
return terrain;
|
||||||
}
|
}
|
||||||
|
|
||||||
CFaction * CTownHandler::loadFromJson(const JsonNode &source, const std::string & identifier)
|
CFaction * CTownHandler::loadFromJson(const JsonNode &source, const std::string & identifier, TFaction index)
|
||||||
{
|
{
|
||||||
auto faction = new CFaction();
|
auto faction = new CFaction();
|
||||||
|
faction->index = index;
|
||||||
|
|
||||||
faction->name = source["name"].String();
|
faction->name = source["name"].String();
|
||||||
faction->identifier = identifier;
|
faction->identifier = identifier;
|
||||||
@ -871,9 +1056,9 @@ CFaction * CTownHandler::loadFromJson(const JsonNode &source, const std::string
|
|||||||
|
|
||||||
void CTownHandler::loadObject(std::string scope, std::string name, const JsonNode & data)
|
void CTownHandler::loadObject(std::string scope, std::string name, const JsonNode & data)
|
||||||
{
|
{
|
||||||
auto object = loadFromJson(data, normalizeIdentifier(scope, "core", name));
|
auto index = static_cast<TFaction>(factions.size());
|
||||||
|
auto object = loadFromJson(data, normalizeIdentifier(scope, "core", name), index);
|
||||||
|
|
||||||
object->index = static_cast<TFaction>(factions.size());
|
|
||||||
factions.push_back(object);
|
factions.push_back(object);
|
||||||
|
|
||||||
if (object->town)
|
if (object->town)
|
||||||
@ -911,8 +1096,8 @@ void CTownHandler::loadObject(std::string scope, std::string name, const JsonNod
|
|||||||
|
|
||||||
void CTownHandler::loadObject(std::string scope, std::string name, const JsonNode & data, size_t index)
|
void CTownHandler::loadObject(std::string scope, std::string name, const JsonNode & data, size_t index)
|
||||||
{
|
{
|
||||||
auto object = loadFromJson(data, normalizeIdentifier(scope, "core", name));
|
auto object = loadFromJson(data, normalizeIdentifier(scope, "core", name), static_cast<TFaction>(index));
|
||||||
object->index = static_cast<TFaction>(index);
|
|
||||||
if (factions.size() > index)
|
if (factions.size() > index)
|
||||||
assert(factions[index] == nullptr); // ensure that this id was not loaded before
|
assert(factions[index] == nullptr); // ensure that this id was not loaded before
|
||||||
else
|
else
|
||||||
@ -957,6 +1142,7 @@ void CTownHandler::loadCustom()
|
|||||||
void CTownHandler::afterLoadFinalization()
|
void CTownHandler::afterLoadFinalization()
|
||||||
{
|
{
|
||||||
initializeRequirements();
|
initializeRequirements();
|
||||||
|
initializeOverridden();
|
||||||
initializeWarMachines();
|
initializeWarMachines();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -979,6 +1165,22 @@ void CTownHandler::initializeRequirements()
|
|||||||
requirementsToLoad.clear();
|
requirementsToLoad.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CTownHandler::initializeOverridden()
|
||||||
|
{
|
||||||
|
for(auto & bidHelper : overriddenBidsToLoad)
|
||||||
|
{
|
||||||
|
auto jsonNode = bidHelper.json;
|
||||||
|
auto scope = bidHelper.town->getBuildingScope();
|
||||||
|
|
||||||
|
for(auto b : jsonNode.Vector())
|
||||||
|
{
|
||||||
|
auto bid = BuildingID(VLC->modh->identifiers.getIdentifier(scope, b).get());
|
||||||
|
bidHelper.building->overrideBids.insert(bid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
overriddenBidsToLoad.clear();
|
||||||
|
}
|
||||||
|
|
||||||
void CTownHandler::initializeWarMachines()
|
void CTownHandler::initializeWarMachines()
|
||||||
{
|
{
|
||||||
// must be done separately after all objects are loaded
|
// must be done separately after all objects are loaded
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
#include "IHandlerBase.h"
|
#include "IHandlerBase.h"
|
||||||
#include "LogicalExpression.h"
|
#include "LogicalExpression.h"
|
||||||
#include "battle/BattleHex.h"
|
#include "battle/BattleHex.h"
|
||||||
|
#include "HeroBonus.h"
|
||||||
|
|
||||||
class CLegacyConfigParser;
|
class CLegacyConfigParser;
|
||||||
class JsonNode;
|
class JsonNode;
|
||||||
@ -47,6 +48,9 @@ public:
|
|||||||
BuildingID bid; //structure ID
|
BuildingID bid; //structure ID
|
||||||
BuildingID upgrade; /// indicates that building "upgrade" can be improved by this, -1 = empty
|
BuildingID upgrade; /// indicates that building "upgrade" can be improved by this, -1 = empty
|
||||||
BuildingSubID::EBuildingSubID subId; /// subtype for special buildings, -1 = the building is not special
|
BuildingSubID::EBuildingSubID subId; /// subtype for special buildings, -1 = the building is not special
|
||||||
|
std::set<BuildingID> overrideBids; /// the building which bonuses should be overridden with bonuses of the current building
|
||||||
|
BonusList buildingBonuses;
|
||||||
|
BonusList onVisitBonuses;
|
||||||
|
|
||||||
enum EBuildMode
|
enum EBuildMode
|
||||||
{
|
{
|
||||||
@ -95,14 +99,16 @@ public:
|
|||||||
bool IsVisitingBonus() const
|
bool IsVisitingBonus() const
|
||||||
{
|
{
|
||||||
return subId == BuildingSubID::ATTACK_VISITING_BONUS ||
|
return subId == BuildingSubID::ATTACK_VISITING_BONUS ||
|
||||||
subId == BuildingSubID::DEFENSE_VISITING_BONUS ||
|
subId == BuildingSubID::DEFENSE_VISITING_BONUS ||
|
||||||
subId == BuildingSubID::SPELL_POWER_VISITING_BONUS ||
|
subId == BuildingSubID::SPELL_POWER_VISITING_BONUS ||
|
||||||
subId == BuildingSubID::KNOWLEDGE_VISITING_BONUS ||
|
subId == BuildingSubID::KNOWLEDGE_VISITING_BONUS ||
|
||||||
subId == BuildingSubID::EXPERIENCE_VISITING_BONUS;
|
subId == BuildingSubID::EXPERIENCE_VISITING_BONUS ||
|
||||||
|
subId == BuildingSubID::CUSTOM_VISITING_BONUS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// input: faction, bid; output: subId, height;
|
void addNewBonus(std::shared_ptr<Bonus> b, BonusList & bonusList);
|
||||||
void update792(const BuildingID & bid, BuildingSubID::EBuildingSubID & subId, ETowerHeight & height);
|
void update792();
|
||||||
|
void update794();
|
||||||
|
|
||||||
template <typename Handler> void serialize(Handler &h, const int version)
|
template <typename Handler> void serialize(Handler &h, const int version)
|
||||||
{
|
{
|
||||||
@ -123,9 +129,17 @@ public:
|
|||||||
h & height;
|
h & height;
|
||||||
}
|
}
|
||||||
if(!h.saving && version < 793)
|
if(!h.saving && version < 793)
|
||||||
|
update792(); //adjust height, subId
|
||||||
|
|
||||||
|
if(version >= 794)
|
||||||
{
|
{
|
||||||
update792(bid, subId, height);
|
h & overrideBids;
|
||||||
|
h & buildingBonuses;
|
||||||
|
h & onVisitBonuses;
|
||||||
}
|
}
|
||||||
|
else if(!h.saving)
|
||||||
|
update794(); //populate overrideBids, buildingBonuses, onVisitBonuses
|
||||||
|
|
||||||
if(!h.saving)
|
if(!h.saving)
|
||||||
deserializeFix();
|
deserializeFix();
|
||||||
}
|
}
|
||||||
@ -133,8 +147,8 @@ public:
|
|||||||
friend class CTownHandler;
|
friend class CTownHandler;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void deserializeFix();
|
void deserializeFix();
|
||||||
|
const JsonNode & getCurrentFactionForUpdateRoutine() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// This is structure used only by client
|
/// This is structure used only by client
|
||||||
@ -354,19 +368,27 @@ class DLL_LINKAGE CTownHandler : public IHandlerBase
|
|||||||
|
|
||||||
std::map<CTown *, JsonNode> warMachinesToLoad;
|
std::map<CTown *, JsonNode> warMachinesToLoad;
|
||||||
std::vector<BuildingRequirementsHelper> requirementsToLoad;
|
std::vector<BuildingRequirementsHelper> requirementsToLoad;
|
||||||
|
std::vector<BuildingRequirementsHelper> overriddenBidsToLoad; //list of buildings, which bonuses should be overridden.
|
||||||
|
|
||||||
const static ETerrainType::EETerrainType defaultGoodTerrain = ETerrainType::EETerrainType::GRASS;
|
const static ETerrainType::EETerrainType defaultGoodTerrain = ETerrainType::EETerrainType::GRASS;
|
||||||
const static ETerrainType::EETerrainType defaultEvilTerrain = ETerrainType::EETerrainType::LAVA;
|
const static ETerrainType::EETerrainType defaultEvilTerrain = ETerrainType::EETerrainType::LAVA;
|
||||||
const static ETerrainType::EETerrainType defaultNeutralTerrain = ETerrainType::EETerrainType::ROUGH;
|
const static ETerrainType::EETerrainType defaultNeutralTerrain = ETerrainType::EETerrainType::ROUGH;
|
||||||
|
|
||||||
|
static TPropagatorPtr emptyPropagator;
|
||||||
|
|
||||||
void initializeRequirements();
|
void initializeRequirements();
|
||||||
|
void initializeOverridden();
|
||||||
void initializeWarMachines();
|
void initializeWarMachines();
|
||||||
|
|
||||||
/// loads CBuilding's into town
|
/// loads CBuilding's into town
|
||||||
void loadBuildingRequirements(CBuilding * building, const JsonNode & source);
|
void loadBuildingRequirements(CBuilding * building, const JsonNode & source, std::vector<BuildingRequirementsHelper> & bidsToLoad);
|
||||||
void loadBuilding(CTown * town, const std::string & stringID, const JsonNode & source);
|
void loadBuilding(CTown * town, const std::string & stringID, const JsonNode & source);
|
||||||
void loadBuildings(CTown * town, const JsonNode & source);
|
void loadBuildings(CTown * town, const JsonNode & source);
|
||||||
|
|
||||||
|
std::shared_ptr<Bonus> createBonus(CBuilding * build, Bonus::BonusType type, int val, int subtype = -1);
|
||||||
|
std::shared_ptr<Bonus> createBonus(CBuilding * build, Bonus::BonusType type, int val, TPropagatorPtr & prop, int subtype = -1);
|
||||||
|
std::shared_ptr<Bonus> createBonusImpl(BuildingID building, Bonus::BonusType type, int val, TPropagatorPtr & prop, const std::string & description, int subtype = -1);
|
||||||
|
|
||||||
/// loads CStructure's into town
|
/// loads CStructure's into town
|
||||||
void loadStructure(CTown &town, const std::string & stringID, const JsonNode & source);
|
void loadStructure(CTown &town, const std::string & stringID, const JsonNode & source);
|
||||||
void loadStructures(CTown &town, const JsonNode & source);
|
void loadStructures(CTown &town, const JsonNode & source);
|
||||||
@ -383,7 +405,7 @@ class DLL_LINKAGE CTownHandler : public IHandlerBase
|
|||||||
|
|
||||||
ETerrainType::EETerrainType getDefaultTerrainForAlignment(EAlignment::EAlignment aligment) const;
|
ETerrainType::EETerrainType getDefaultTerrainForAlignment(EAlignment::EAlignment aligment) const;
|
||||||
|
|
||||||
CFaction * loadFromJson(const JsonNode & data, const std::string & identifier);
|
CFaction * loadFromJson(const JsonNode & data, const std::string & identifier, TFaction index);
|
||||||
|
|
||||||
void loadRandomFaction();
|
void loadRandomFaction();
|
||||||
|
|
||||||
@ -404,6 +426,7 @@ public:
|
|||||||
|
|
||||||
void loadObject(std::string scope, std::string name, const JsonNode & data) 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 loadObject(std::string scope, std::string name, const JsonNode & data, size_t index) override;
|
||||||
|
void addBonusesForVanilaBuilding(CBuilding * building);
|
||||||
|
|
||||||
void loadCustom() override;
|
void loadCustom() override;
|
||||||
void afterLoadFinalization() override;
|
void afterLoadFinalization() override;
|
||||||
@ -416,6 +439,7 @@ public:
|
|||||||
|
|
||||||
//json serialization helper
|
//json serialization helper
|
||||||
static std::string encodeFaction(const si32 index);
|
static std::string encodeFaction(const si32 index);
|
||||||
|
static void loadSpecialBuildingBonuses(const JsonNode & source, BonusList & bonusList, CBuilding * building);
|
||||||
|
|
||||||
template <typename Handler> void serialize(Handler &h, const int version)
|
template <typename Handler> void serialize(Handler &h, const int version)
|
||||||
{
|
{
|
||||||
|
@ -297,7 +297,7 @@ class TeleportChannelID : public BaseForID<TeleportChannelID, si32>
|
|||||||
// Enum declarations
|
// Enum declarations
|
||||||
namespace PrimarySkill
|
namespace PrimarySkill
|
||||||
{
|
{
|
||||||
enum PrimarySkill { ATTACK, DEFENSE, SPELL_POWER, KNOWLEDGE,
|
enum PrimarySkill { NONE = -1, ATTACK, DEFENSE, SPELL_POWER, KNOWLEDGE,
|
||||||
EXPERIENCE = 4}; //for some reason changePrimSkill uses it
|
EXPERIENCE = 4}; //for some reason changePrimSkill uses it
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -452,7 +452,8 @@ namespace BuildingSubID
|
|||||||
KNOWLEDGE_VISITING_BONUS,
|
KNOWLEDGE_VISITING_BONUS,
|
||||||
EXPERIENCE_VISITING_BONUS,
|
EXPERIENCE_VISITING_BONUS,
|
||||||
LIGHTHOUSE,
|
LIGHTHOUSE,
|
||||||
TREASURY
|
TREASURY,
|
||||||
|
CUSTOM_VISITING_BONUS
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,7 +71,8 @@ const std::map<std::string, TLimiterPtr> bonusLimiterMap =
|
|||||||
{"SHOOTER_ONLY", std::make_shared<HasAnotherBonusLimiter>(Bonus::SHOOTER)},
|
{"SHOOTER_ONLY", std::make_shared<HasAnotherBonusLimiter>(Bonus::SHOOTER)},
|
||||||
{"DRAGON_NATURE", std::make_shared<HasAnotherBonusLimiter>(Bonus::DRAGON_NATURE)},
|
{"DRAGON_NATURE", std::make_shared<HasAnotherBonusLimiter>(Bonus::DRAGON_NATURE)},
|
||||||
{"IS_UNDEAD", std::make_shared<HasAnotherBonusLimiter>(Bonus::UNDEAD)},
|
{"IS_UNDEAD", std::make_shared<HasAnotherBonusLimiter>(Bonus::UNDEAD)},
|
||||||
{"CREATURE_NATIVE_TERRAIN", std::make_shared<CreatureTerrainLimiter>()}
|
{"CREATURE_NATIVE_TERRAIN", std::make_shared<CreatureTerrainLimiter>()},
|
||||||
|
{"CREATURE_FACTION", std::make_shared<CreatureFactionLimiter>()}
|
||||||
};
|
};
|
||||||
|
|
||||||
const std::map<std::string, TPropagatorPtr> bonusPropagatorMap =
|
const std::map<std::string, TPropagatorPtr> bonusPropagatorMap =
|
||||||
@ -81,7 +82,8 @@ const std::map<std::string, TPropagatorPtr> bonusPropagatorMap =
|
|||||||
{"PLAYER_PROPAGATOR", std::make_shared<CPropagatorNodeType>(CBonusSystemNode::PLAYER)},
|
{"PLAYER_PROPAGATOR", std::make_shared<CPropagatorNodeType>(CBonusSystemNode::PLAYER)},
|
||||||
{"HERO", std::make_shared<CPropagatorNodeType>(CBonusSystemNode::HERO)},
|
{"HERO", std::make_shared<CPropagatorNodeType>(CBonusSystemNode::HERO)},
|
||||||
{"TEAM_PROPAGATOR", std::make_shared<CPropagatorNodeType>(CBonusSystemNode::TEAM)}, //untested
|
{"TEAM_PROPAGATOR", std::make_shared<CPropagatorNodeType>(CBonusSystemNode::TEAM)}, //untested
|
||||||
{"GLOBAL_EFFECT", std::make_shared<CPropagatorNodeType>(CBonusSystemNode::GLOBAL_EFFECTS)}
|
{"GLOBAL_EFFECT", std::make_shared<CPropagatorNodeType>(CBonusSystemNode::GLOBAL_EFFECTS)},
|
||||||
|
{"ALL_CREATURES", std::make_shared<CPropagatorNodeType>(CBonusSystemNode::ALL_CREATURES)}
|
||||||
}; //untested
|
}; //untested
|
||||||
|
|
||||||
const std::map<std::string, TUpdaterPtr> bonusUpdaterMap =
|
const std::map<std::string, TUpdaterPtr> bonusUpdaterMap =
|
||||||
@ -1570,8 +1572,8 @@ std::string Bonus::nameForBonus() const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Bonus::Bonus(ui16 Dur, BonusType Type, BonusSource Src, si32 Val, ui32 ID, std::string Desc, si32 Subtype)
|
Bonus::Bonus(Bonus::BonusDuration Duration, BonusType Type, BonusSource Src, si32 Val, ui32 ID, std::string Desc, si32 Subtype)
|
||||||
: duration(Dur), type(Type), subtype(Subtype), source(Src), val(Val), sid(ID), description(Desc)
|
: duration((ui16)Duration), type(Type), subtype(Subtype), source(Src), val(Val), sid(ID), description(Desc)
|
||||||
{
|
{
|
||||||
turnsRemain = 0;
|
turnsRemain = 0;
|
||||||
valType = ADDITIVE_VALUE;
|
valType = ADDITIVE_VALUE;
|
||||||
@ -1579,8 +1581,8 @@ Bonus::Bonus(ui16 Dur, BonusType Type, BonusSource Src, si32 Val, ui32 ID, std::
|
|||||||
boost::algorithm::trim(description);
|
boost::algorithm::trim(description);
|
||||||
}
|
}
|
||||||
|
|
||||||
Bonus::Bonus(ui16 Dur, BonusType Type, BonusSource Src, si32 Val, ui32 ID, si32 Subtype, ValueType ValType)
|
Bonus::Bonus(Bonus::BonusDuration Duration, BonusType Type, BonusSource Src, si32 Val, ui32 ID, si32 Subtype, ValueType ValType)
|
||||||
: duration(Dur), type(Type), subtype(Subtype), source(Src), val(Val), sid(ID), valType(ValType)
|
: duration((ui16)Duration), type(Type), subtype(Subtype), source(Src), val(Val), sid(ID), valType(ValType)
|
||||||
{
|
{
|
||||||
turnsRemain = 0;
|
turnsRemain = 0;
|
||||||
effectRange = NO_LIMIT;
|
effectRange = NO_LIMIT;
|
||||||
@ -1922,17 +1924,27 @@ bool IPropagator::shouldBeAttached(CBonusSystemNode *dest)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CBonusSystemNode::ENodeTypes IPropagator::getPropagatorType() const
|
||||||
|
{
|
||||||
|
return CBonusSystemNode::ENodeTypes::NONE;
|
||||||
|
}
|
||||||
|
|
||||||
CPropagatorNodeType::CPropagatorNodeType()
|
CPropagatorNodeType::CPropagatorNodeType()
|
||||||
:nodeType(0)
|
:nodeType(CBonusSystemNode::ENodeTypes::UNKNOWN)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CPropagatorNodeType::CPropagatorNodeType(int NodeType)
|
CPropagatorNodeType::CPropagatorNodeType(CBonusSystemNode::ENodeTypes NodeType)
|
||||||
: nodeType(NodeType)
|
: nodeType(NodeType)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CBonusSystemNode::ENodeTypes CPropagatorNodeType::getPropagatorType() const
|
||||||
|
{
|
||||||
|
return nodeType;
|
||||||
|
}
|
||||||
|
|
||||||
bool CPropagatorNodeType::shouldBeAttached(CBonusSystemNode *dest)
|
bool CPropagatorNodeType::shouldBeAttached(CBonusSystemNode *dest)
|
||||||
{
|
{
|
||||||
return nodeType == dest->getNodeType();
|
return nodeType == dest->getNodeType();
|
||||||
|
@ -418,8 +418,8 @@ struct DLL_LINKAGE Bonus : public std::enable_shared_from_this<Bonus>
|
|||||||
|
|
||||||
std::string description;
|
std::string description;
|
||||||
|
|
||||||
Bonus(ui16 Dur, BonusType Type, BonusSource Src, si32 Val, ui32 ID, std::string Desc, si32 Subtype=-1);
|
Bonus(BonusDuration Duration, BonusType Type, BonusSource Src, si32 Val, ui32 ID, std::string Desc, si32 Subtype=-1);
|
||||||
Bonus(ui16 Dur, BonusType Type, BonusSource Src, si32 Val, ui32 ID, si32 Subtype=-1, ValueType ValType = ADDITIVE_VALUE);
|
Bonus(BonusDuration Duration, BonusType Type, BonusSource Src, si32 Val, ui32 ID, si32 Subtype=-1, ValueType ValType = ADDITIVE_VALUE);
|
||||||
Bonus();
|
Bonus();
|
||||||
|
|
||||||
template <typename Handler> void serialize(Handler &h, const int version)
|
template <typename Handler> void serialize(Handler &h, const int version)
|
||||||
@ -508,6 +508,10 @@ struct DLL_LINKAGE Bonus : public std::enable_shared_from_this<Bonus>
|
|||||||
{
|
{
|
||||||
val += Val;
|
val += Val;
|
||||||
}
|
}
|
||||||
|
STRONG_INLINE static ui32 getSid32(ui32 high, ui32 low)
|
||||||
|
{
|
||||||
|
return (high << 16) + low;
|
||||||
|
}
|
||||||
|
|
||||||
std::string Description() const;
|
std::string Description() const;
|
||||||
JsonNode toJsonNode() const;
|
JsonNode toJsonNode() const;
|
||||||
@ -639,30 +643,6 @@ inline BonusList::const_iterator range_end(BonusList const &x)
|
|||||||
|
|
||||||
DLL_LINKAGE std::ostream & operator<<(std::ostream &out, const BonusList &bonusList);
|
DLL_LINKAGE std::ostream & operator<<(std::ostream &out, const BonusList &bonusList);
|
||||||
|
|
||||||
class DLL_LINKAGE IPropagator
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
virtual ~IPropagator();
|
|
||||||
virtual bool shouldBeAttached(CBonusSystemNode *dest);
|
|
||||||
|
|
||||||
template <typename Handler> void serialize(Handler &h, const int version)
|
|
||||||
{}
|
|
||||||
};
|
|
||||||
|
|
||||||
class DLL_LINKAGE CPropagatorNodeType : public IPropagator
|
|
||||||
{
|
|
||||||
int nodeType; //CBonusSystemNode::ENodeTypes
|
|
||||||
public:
|
|
||||||
CPropagatorNodeType();
|
|
||||||
CPropagatorNodeType(int NodeType);
|
|
||||||
bool shouldBeAttached(CBonusSystemNode *dest) override;
|
|
||||||
|
|
||||||
template <typename Handler> void serialize(Handler &h, const int version)
|
|
||||||
{
|
|
||||||
h & nodeType;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct BonusLimitationContext
|
struct BonusLimitationContext
|
||||||
{
|
{
|
||||||
std::shared_ptr<const Bonus> b;
|
std::shared_ptr<const Bonus> b;
|
||||||
@ -756,6 +736,7 @@ class DLL_LINKAGE CBonusSystemNode : public virtual IBonusBearer, public boost::
|
|||||||
public:
|
public:
|
||||||
enum ENodeTypes
|
enum ENodeTypes
|
||||||
{
|
{
|
||||||
|
NONE = -1,
|
||||||
UNKNOWN, STACK_INSTANCE, STACK_BATTLE, SPECIALTY, ARTIFACT, CREATURE, ARTIFACT_INSTANCE, HERO, PLAYER, TEAM,
|
UNKNOWN, STACK_INSTANCE, STACK_BATTLE, SPECIALTY, ARTIFACT, CREATURE, ARTIFACT_INSTANCE, HERO, PLAYER, TEAM,
|
||||||
TOWN_AND_VISITOR, BATTLE, COMMANDER, GLOBAL_EFFECTS, ALL_CREATURES
|
TOWN_AND_VISITOR, BATTLE, COMMANDER, GLOBAL_EFFECTS, ALL_CREATURES
|
||||||
};
|
};
|
||||||
@ -857,6 +838,33 @@ public:
|
|||||||
friend class CBonusProxy;
|
friend class CBonusProxy;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class DLL_LINKAGE IPropagator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~IPropagator();
|
||||||
|
virtual bool shouldBeAttached(CBonusSystemNode *dest);
|
||||||
|
virtual CBonusSystemNode::ENodeTypes getPropagatorType() const;
|
||||||
|
|
||||||
|
template <typename Handler> void serialize(Handler &h, const int version)
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
class DLL_LINKAGE CPropagatorNodeType : public IPropagator
|
||||||
|
{
|
||||||
|
CBonusSystemNode::ENodeTypes nodeType;
|
||||||
|
|
||||||
|
public:
|
||||||
|
CPropagatorNodeType();
|
||||||
|
CPropagatorNodeType(CBonusSystemNode::ENodeTypes NodeType);
|
||||||
|
bool shouldBeAttached(CBonusSystemNode *dest) override;
|
||||||
|
CBonusSystemNode::ENodeTypes getPropagatorType() const override;
|
||||||
|
|
||||||
|
template <typename Handler> void serialize(Handler &h, const int version)
|
||||||
|
{
|
||||||
|
h & nodeType;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
namespace NBonus
|
namespace NBonus
|
||||||
{
|
{
|
||||||
//set of methods that may be safely called with nullptr objs
|
//set of methods that may be safely called with nullptr objs
|
||||||
|
@ -697,6 +697,19 @@ std::shared_ptr<Bonus> JsonUtils::parseBonus(const JsonNode &ability)
|
|||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<Bonus> JsonUtils::parseBuildingBonus(const JsonNode &ability, BuildingID building, std::string description)
|
||||||
|
{
|
||||||
|
/* duration = Bonus::PERMANENT
|
||||||
|
source = Bonus::TOWN_STRUCTURE
|
||||||
|
bonusType, val, subtype - get from json
|
||||||
|
*/
|
||||||
|
auto b = std::make_shared<Bonus>(Bonus::PERMANENT, Bonus::NONE, Bonus::TOWN_STRUCTURE, 0, building, description, -1);
|
||||||
|
|
||||||
|
if(!parseBonus(ability, b.get()))
|
||||||
|
return nullptr;
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
bool JsonUtils::parseBonus(const JsonNode &ability, Bonus *b)
|
bool JsonUtils::parseBonus(const JsonNode &ability, Bonus *b)
|
||||||
{
|
{
|
||||||
const JsonNode *value;
|
const JsonNode *value;
|
||||||
@ -726,7 +739,8 @@ bool JsonUtils::parseBonus(const JsonNode &ability, Bonus *b)
|
|||||||
|
|
||||||
b->sid = static_cast<si32>(ability["sourceID"].Float());
|
b->sid = static_cast<si32>(ability["sourceID"].Float());
|
||||||
|
|
||||||
b->description = ability["description"].String();
|
if(!ability["description"].isNull())
|
||||||
|
b->description = ability["description"].String();
|
||||||
|
|
||||||
value = &ability["effectRange"];
|
value = &ability["effectRange"];
|
||||||
if (!value->isNull())
|
if (!value->isNull())
|
||||||
@ -738,7 +752,7 @@ bool JsonUtils::parseBonus(const JsonNode &ability, Bonus *b)
|
|||||||
switch (value->getType())
|
switch (value->getType())
|
||||||
{
|
{
|
||||||
case JsonNode::JsonType::DATA_STRING:
|
case JsonNode::JsonType::DATA_STRING:
|
||||||
b->duration = parseByMap(bonusDurationMap, value, "duration type ");
|
b->duration = (Bonus::BonusDuration)parseByMap(bonusDurationMap, value, "duration type ");
|
||||||
break;
|
break;
|
||||||
case JsonNode::JsonType::DATA_VECTOR:
|
case JsonNode::JsonType::DATA_VECTOR:
|
||||||
{
|
{
|
||||||
@ -747,7 +761,7 @@ bool JsonUtils::parseBonus(const JsonNode &ability, Bonus *b)
|
|||||||
{
|
{
|
||||||
dur |= parseByMap(bonusDurationMap, &d, "duration type ");
|
dur |= parseByMap(bonusDurationMap, &d, "duration type ");
|
||||||
}
|
}
|
||||||
b->duration = dur;
|
b->duration = (Bonus::BonusDuration)dur;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
#include "GameConstants.h"
|
||||||
|
|
||||||
class JsonNode;
|
class JsonNode;
|
||||||
typedef std::map <std::string, JsonNode> JsonMap;
|
typedef std::map <std::string, JsonNode> JsonMap;
|
||||||
@ -168,6 +169,7 @@ namespace JsonUtils
|
|||||||
///
|
///
|
||||||
DLL_LINKAGE std::shared_ptr<Bonus> parseBonus(const JsonVector &ability_vec);
|
DLL_LINKAGE std::shared_ptr<Bonus> parseBonus(const JsonVector &ability_vec);
|
||||||
DLL_LINKAGE std::shared_ptr<Bonus> parseBonus(const JsonNode &ability);
|
DLL_LINKAGE std::shared_ptr<Bonus> parseBonus(const JsonNode &ability);
|
||||||
|
DLL_LINKAGE std::shared_ptr<Bonus> parseBuildingBonus(const JsonNode &ability, BuildingID building, std::string description);
|
||||||
DLL_LINKAGE bool parseBonus(const JsonNode &ability, Bonus *placement);
|
DLL_LINKAGE bool parseBonus(const JsonNode &ability, Bonus *placement);
|
||||||
DLL_LINKAGE std::shared_ptr<ILimiter> parseLimiter(const JsonNode & limiter);
|
DLL_LINKAGE std::shared_ptr<ILimiter> parseLimiter(const JsonNode & limiter);
|
||||||
DLL_LINKAGE void resolveIdentifier(si32 &var, const JsonNode &node, std::string name);
|
DLL_LINKAGE void resolveIdentifier(si32 &var, const JsonNode &node, std::string name);
|
||||||
|
@ -245,10 +245,21 @@ DLL_LINKAGE void GiveBonus::applyGs(CGameState *gs)
|
|||||||
std::string &descr = b->description;
|
std::string &descr = b->description;
|
||||||
|
|
||||||
if(!bdescr.message.size()
|
if(!bdescr.message.size()
|
||||||
&& bonus.source == Bonus::OBJECT
|
|
||||||
&& (bonus.type == Bonus::LUCK || bonus.type == Bonus::MORALE))
|
&& (bonus.type == Bonus::LUCK || bonus.type == Bonus::MORALE))
|
||||||
{
|
{
|
||||||
descr = VLC->generaltexth->arraytxt[bonus.val > 0 ? 110 : 109]; //+/-%d Temporary until next battle"
|
if (bonus.source == Bonus::OBJECT)
|
||||||
|
{
|
||||||
|
descr = VLC->generaltexth->arraytxt[bonus.val > 0 ? 110 : 109]; //+/-%d Temporary until next battle"
|
||||||
|
}
|
||||||
|
else if(bonus.source == Bonus::TOWN_STRUCTURE)
|
||||||
|
{
|
||||||
|
descr = bonus.description;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bdescr.toString(descr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -556,16 +567,27 @@ void TryMoveHero::applyGs(CGameState *gs)
|
|||||||
DLL_LINKAGE void NewStructures::applyGs(CGameState *gs)
|
DLL_LINKAGE void NewStructures::applyGs(CGameState *gs)
|
||||||
{
|
{
|
||||||
CGTownInstance *t = gs->getTown(tid);
|
CGTownInstance *t = gs->getTown(tid);
|
||||||
|
|
||||||
for(const auto & id : bid)
|
for(const auto & id : bid)
|
||||||
{
|
{
|
||||||
assert(t->town->buildings.at(id) != nullptr);
|
assert(t->town->buildings.at(id) != nullptr);
|
||||||
t->builtBuildings.insert(id);
|
t->builtBuildings.insert(id);
|
||||||
|
|
||||||
t->updateAppearance();
|
t->updateAppearance();
|
||||||
|
auto currentBuilding = t->town->buildings.at(id);
|
||||||
|
|
||||||
|
if(currentBuilding->overrideBids.empty())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for(auto overrideBid : currentBuilding->overrideBids)
|
||||||
|
{
|
||||||
|
t->overriddenBuildings.insert(overrideBid);
|
||||||
|
t->deleteTownBonus(overrideBid);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
t->builded = builded;
|
t->builded = builded;
|
||||||
t->recreateBuildingsBonuses();
|
t->recreateBuildingsBonuses();
|
||||||
}
|
}
|
||||||
|
|
||||||
DLL_LINKAGE void RazeStructures::applyGs(CGameState *gs)
|
DLL_LINKAGE void RazeStructures::applyGs(CGameState *gs)
|
||||||
{
|
{
|
||||||
CGTownInstance *t = gs->getTown(tid);
|
CGTownInstance *t = gs->getTown(tid);
|
||||||
|
@ -196,3 +196,8 @@ void LibClasses::setContent(std::shared_ptr<CContentHandler> content)
|
|||||||
{
|
{
|
||||||
modh->content = content;
|
modh->content = content;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LibClasses::restoreAllCreaturesNodeType794()
|
||||||
|
{
|
||||||
|
creh->restoreAllCreaturesNodeType794();
|
||||||
|
}
|
||||||
|
@ -36,6 +36,7 @@ class DLL_LINKAGE LibClasses
|
|||||||
void makeNull(); //sets all handler pointers to null
|
void makeNull(); //sets all handler pointers to null
|
||||||
std::shared_ptr<CContentHandler> getContent() const;
|
std::shared_ptr<CContentHandler> getContent() const;
|
||||||
void setContent(std::shared_ptr<CContentHandler> content);
|
void setContent(std::shared_ptr<CContentHandler> content);
|
||||||
|
void restoreAllCreaturesNodeType794();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
bool IS_AI_ENABLED; //unused?
|
bool IS_AI_ENABLED; //unused?
|
||||||
@ -69,6 +70,9 @@ public:
|
|||||||
h & heroh;
|
h & heroh;
|
||||||
h & arth;
|
h & arth;
|
||||||
h & creh;
|
h & creh;
|
||||||
|
if(!h.saving && version < 794)
|
||||||
|
restoreAllCreaturesNodeType794();
|
||||||
|
|
||||||
h & townh;
|
h & townh;
|
||||||
h & objh;
|
h & objh;
|
||||||
h & objtypeh;
|
h & objtypeh;
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
#include "../mapping/CMap.h"
|
#include "../mapping/CMap.h"
|
||||||
#include "../CPlayerState.h"
|
#include "../CPlayerState.h"
|
||||||
#include "../serializer/JsonSerializeFormat.h"
|
#include "../serializer/JsonSerializeFormat.h"
|
||||||
|
#include "../HeroBonus.h"
|
||||||
|
|
||||||
std::vector<const CArtifact *> CGTownInstance::merchantArtifacts;
|
std::vector<const CArtifact *> CGTownInstance::merchantArtifacts;
|
||||||
std::vector<int> CGTownInstance::universitySkills;
|
std::vector<int> CGTownInstance::universitySkills;
|
||||||
@ -435,8 +436,6 @@ void CGDwelling::serializeJsonOptions(JsonSerializeFormat & handler)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TPropagatorPtr CGTownInstance::emptyPropagator = TPropagatorPtr();
|
|
||||||
|
|
||||||
int CGTownInstance::getSightRadius() const //returns sight distance
|
int CGTownInstance::getSightRadius() const //returns sight distance
|
||||||
{
|
{
|
||||||
auto ret = CBuilding::HEIGHT_NO_TOWER;
|
auto ret = CBuilding::HEIGHT_NO_TOWER;
|
||||||
@ -753,6 +752,17 @@ void CGTownInstance::tryAddOnePerWeekBonus(BuildingSubID::EBuildingSubID subID)
|
|||||||
bonusingBuildings.push_back(new COPWBonus(bid, subID, this));
|
bonusingBuildings.push_back(new COPWBonus(bid, subID, this));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CGTownInstance::initOverriddenBids()
|
||||||
|
{
|
||||||
|
for(const auto & bid : builtBuildings)
|
||||||
|
{
|
||||||
|
auto & overrideThem = town->buildings.at(bid)->overrideBids;
|
||||||
|
|
||||||
|
for(auto & overrideIt : overrideThem)
|
||||||
|
overriddenBuildings.insert(overrideIt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void CGTownInstance::tryAddVisitingBonus(BuildingSubID::EBuildingSubID subID)
|
void CGTownInstance::tryAddVisitingBonus(BuildingSubID::EBuildingSubID subID)
|
||||||
{
|
{
|
||||||
auto bid = town->getBuildingType(subID);
|
auto bid = town->getBuildingType(subID);
|
||||||
@ -765,6 +775,9 @@ void CGTownInstance::addTownBonuses()
|
|||||||
{
|
{
|
||||||
for(const auto & kvp : town->buildings)
|
for(const auto & kvp : town->buildings)
|
||||||
{
|
{
|
||||||
|
if(vstd::contains(overriddenBuildings, kvp.first))
|
||||||
|
continue;
|
||||||
|
|
||||||
if(kvp.second->IsVisitingBonus())
|
if(kvp.second->IsVisitingBonus())
|
||||||
bonusingBuildings.push_back(new CTownBonus(kvp.second->bid, kvp.second->subId, this));
|
bonusingBuildings.push_back(new CTownBonus(kvp.second->bid, kvp.second->subId, this));
|
||||||
|
|
||||||
@ -773,6 +786,36 @@ void CGTownInstance::addTownBonuses()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CGTownInstance::deleteTownBonus(BuildingID::EBuildingID bid)
|
||||||
|
{
|
||||||
|
size_t i = 0;
|
||||||
|
CGTownBuilding * freeIt = nullptr;
|
||||||
|
|
||||||
|
for(i = 0; i != bonusingBuildings.size(); i++)
|
||||||
|
{
|
||||||
|
if(bonusingBuildings[i]->getBuildingType() == bid)
|
||||||
|
{
|
||||||
|
freeIt = bonusingBuildings[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(freeIt == nullptr)
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto building = town->buildings.at(bid);
|
||||||
|
auto isVisitingBonus = building->IsVisitingBonus();
|
||||||
|
auto isWeekBonus = building->IsWeekBonus();
|
||||||
|
|
||||||
|
if(!isVisitingBonus && !isWeekBonus)
|
||||||
|
return;
|
||||||
|
|
||||||
|
bonusingBuildings.erase(bonusingBuildings.begin() + i);
|
||||||
|
|
||||||
|
if(isVisitingBonus)
|
||||||
|
delete (CTownBonus *)freeIt;
|
||||||
|
else if(isWeekBonus)
|
||||||
|
delete (COPWBonus *)freeIt;
|
||||||
|
}
|
||||||
|
|
||||||
void CGTownInstance::initObj(CRandomGenerator & rand) ///initialize town structures
|
void CGTownInstance::initObj(CRandomGenerator & rand) ///initialize town structures
|
||||||
{
|
{
|
||||||
@ -794,17 +837,18 @@ void CGTownInstance::initObj(CRandomGenerator & rand) ///initialize town structu
|
|||||||
creatures[level].second.push_back(town->creatures[level][upgradeNum]);
|
creatures[level].second.push_back(town->creatures[level][upgradeNum]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
initOverriddenBids();
|
||||||
addTownBonuses(); //add special bonuses from buildings to the bonusingBuildings vector.
|
addTownBonuses(); //add special bonuses from buildings to the bonusingBuildings vector.
|
||||||
recreateBuildingsBonuses();
|
recreateBuildingsBonuses();
|
||||||
updateAppearance();
|
updateAppearance();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CGTownInstance::updateBonusingBuildings()
|
void CGTownInstance::updateBonusingBuildings() //update to version 792
|
||||||
{
|
{
|
||||||
if (this->town->faction != nullptr)
|
if(this->town->faction != nullptr)
|
||||||
{
|
{
|
||||||
//firstly, update subtype for the Bonusing objects, which are already stored in the bonusing list
|
//firstly, update subtype for the Bonusing objects, which are already stored in the bonusing list
|
||||||
for (auto building : bonusingBuildings) //no garrison bonuses here, only week and visiting bonuses
|
for(auto building : bonusingBuildings) //no garrison bonuses here, only week and visiting bonuses
|
||||||
{
|
{
|
||||||
switch (this->town->faction->index)
|
switch (this->town->faction->index)
|
||||||
{
|
{
|
||||||
@ -838,7 +882,7 @@ void CGTownInstance::updateBonusingBuildings()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
//secondly, supplement bonusing buildings list and active bonuses; subtypes for these objects are already set in update792
|
//secondly, supplement bonusing buildings list and active bonuses; subtypes for these objects are already set in update792
|
||||||
for (auto & kvp : town->buildings)
|
for(auto & kvp : town->buildings)
|
||||||
{
|
{
|
||||||
auto & building = kvp.second;
|
auto & building = kvp.second;
|
||||||
|
|
||||||
@ -864,6 +908,25 @@ void CGTownInstance::updateBonusingBuildings()
|
|||||||
recreateBuildingsBonuses(); ///Clear all bonuses and recreate
|
recreateBuildingsBonuses(); ///Clear all bonuses and recreate
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CGTownInstance::updateTown794()
|
||||||
|
{
|
||||||
|
for(auto builtBuilding : builtBuildings)
|
||||||
|
{
|
||||||
|
auto building = town->buildings.at(builtBuilding);
|
||||||
|
|
||||||
|
for(auto overriddenBid : building->overrideBids)
|
||||||
|
overriddenBuildings.insert(overriddenBid);
|
||||||
|
}
|
||||||
|
for(auto & kvp : town->buildings)
|
||||||
|
{
|
||||||
|
auto & building = kvp.second;
|
||||||
|
//The building acts as a visiting bonus and it has not been overridden.
|
||||||
|
if(building->IsVisitingBonus() && overriddenBuildings.find(kvp.first) == overriddenBuildings.end())
|
||||||
|
tryAddVisitingBonus(building->subId);
|
||||||
|
}
|
||||||
|
recreateBuildingsBonuses();
|
||||||
|
}
|
||||||
|
|
||||||
bool CGTownInstance::hasBuiltInOldWay(ETownType::ETownType type, BuildingID bid) const
|
bool CGTownInstance::hasBuiltInOldWay(ETownType::ETownType type, BuildingID bid) const
|
||||||
{
|
{
|
||||||
return (this->town->faction != nullptr && this->town->faction->index == type && hasBuilt(bid));
|
return (this->town->faction != nullptr && this->town->faction->index == type && hasBuilt(bid));
|
||||||
@ -1184,112 +1247,30 @@ void CGTownInstance::updateMoraleBonusFromArmy()
|
|||||||
|
|
||||||
void CGTownInstance::recreateBuildingsBonuses()
|
void CGTownInstance::recreateBuildingsBonuses()
|
||||||
{
|
{
|
||||||
static TPropagatorPtr playerProp(new CPropagatorNodeType(PLAYER));
|
|
||||||
|
|
||||||
BonusList bl;
|
BonusList bl;
|
||||||
getExportedBonusList().getBonuses(bl, Selector::sourceType()(Bonus::TOWN_STRUCTURE));
|
getExportedBonusList().getBonuses(bl, Selector::sourceType()(Bonus::TOWN_STRUCTURE));
|
||||||
|
|
||||||
for(auto b : bl)
|
for(auto b : bl)
|
||||||
removeBonus(b);
|
removeBonus(b);
|
||||||
|
|
||||||
//tricky! -> checks tavern only if no bratherhood of sword or not a castle
|
for(auto bid : builtBuildings)
|
||||||
if(!addBonusIfBuilt(BuildingSubID::BROTHERHOOD_OF_SWORD, Bonus::MORALE, +2))
|
{
|
||||||
addBonusIfBuilt(BuildingID::TAVERN, Bonus::MORALE, +1);
|
if(vstd::contains(overriddenBuildings, bid)) //tricky! -> checks tavern only if no bratherhood of sword
|
||||||
|
continue;
|
||||||
|
|
||||||
addBonusIfBuilt(BuildingSubID::FOUNTAIN_OF_FORTUNE, Bonus::LUCK, +2); //fountain of fortune
|
auto building = town->buildings.at(bid);
|
||||||
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(BuildingSubID::LIGHTHOUSE, Bonus::SEA_MOVEMENT, +500, playerProp);
|
|
||||||
|
|
||||||
if(subID == ETownType::CASTLE) //castle
|
if(building->buildingBonuses.empty())
|
||||||
{
|
continue;
|
||||||
addBonusIfBuilt(BuildingID::GRAIL, Bonus::MORALE, +2, playerProp); //colossus
|
|
||||||
}
|
|
||||||
else if(subID == ETownType::RAMPART) //rampart
|
|
||||||
{
|
|
||||||
addBonusIfBuilt(BuildingID::GRAIL, Bonus::LUCK, +2, playerProp); //guardian spirit
|
|
||||||
}
|
|
||||||
else if(subID == ETownType::TOWER) //tower
|
|
||||||
{
|
|
||||||
addBonusIfBuilt(BuildingID::GRAIL, Bonus::PRIMARY_SKILL, +15, PrimarySkill::KNOWLEDGE); //grail
|
|
||||||
}
|
|
||||||
else if(subID == ETownType::NECROPOLIS) //necropolis
|
|
||||||
{
|
|
||||||
addBonusIfBuilt(BuildingID::COVER_OF_DARKNESS, Bonus::DARKNESS, +20);
|
|
||||||
addBonusIfBuilt(BuildingID::NECROMANCY_AMPLIFIER, Bonus::SECONDARY_SKILL_PREMY, +10, playerProp, SecondarySkill::NECROMANCY); //necromancy amplifier
|
|
||||||
addBonusIfBuilt(BuildingID::GRAIL, Bonus::SECONDARY_SKILL_PREMY, +20, playerProp, SecondarySkill::NECROMANCY); //Soul prison
|
|
||||||
}
|
|
||||||
else if(subID == ETownType::DUNGEON) //Dungeon
|
|
||||||
{
|
|
||||||
addBonusIfBuilt(BuildingID::GRAIL, Bonus::PRIMARY_SKILL, +12, PrimarySkill::SPELL_POWER); //grail
|
|
||||||
}
|
|
||||||
else if(subID == ETownType::STRONGHOLD) //Stronghold
|
|
||||||
{
|
|
||||||
addBonusIfBuilt(BuildingID::GRAIL, Bonus::PRIMARY_SKILL, +20, PrimarySkill::ATTACK); //grail
|
|
||||||
}
|
|
||||||
else if(subID == ETownType::FORTRESS) //Fortress
|
|
||||||
{
|
|
||||||
addBonusIfBuilt(BuildingID::GRAIL, Bonus::PRIMARY_SKILL, +10, PrimarySkill::ATTACK); //grail
|
|
||||||
addBonusIfBuilt(BuildingID::GRAIL, Bonus::PRIMARY_SKILL, +10, PrimarySkill::DEFENSE); //grail
|
|
||||||
}
|
|
||||||
else if(boost::algorithm::ends_with(this->town->faction->identifier, ":cove") && hasBuilt(BuildingID::GRAIL))
|
|
||||||
{
|
|
||||||
static TPropagatorPtr lsProp(new CPropagatorNodeType(ALL_CREATURES));
|
|
||||||
static auto factionLimiter = std::make_shared<CreatureFactionLimiter>(this->town->faction->index);
|
|
||||||
auto b = std::make_shared<Bonus>(Bonus::PERMANENT, Bonus::NO_TERRAIN_PENALTY, Bonus::TOWN_STRUCTURE, 0, BuildingID::GRAIL, "", -1);
|
|
||||||
|
|
||||||
b->addLimiter(factionLimiter);
|
for(auto bonus : building->buildingBonuses)
|
||||||
b->addPropagator(lsProp);
|
|
||||||
VLC->creh->addBonusForAllCreatures(b);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CGTownInstance::addBonusIfBuilt(BuildingSubID::EBuildingSubID subId, Bonus::BonusType type, int val, TPropagatorPtr & prop, int subtype)
|
|
||||||
{
|
|
||||||
BuildingID currentBid = BuildingID::NONE;
|
|
||||||
std::ostringstream descr;
|
|
||||||
|
|
||||||
for(const auto & bid : builtBuildings)
|
|
||||||
{
|
|
||||||
if(town->buildings.at(bid)->subId == subId)
|
|
||||||
{
|
{
|
||||||
descr << town->buildings.at(bid)->Name();
|
if(bonus->propagator != nullptr && bonus->propagator->getPropagatorType() == ALL_CREATURES)
|
||||||
currentBid = bid;
|
VLC->creh->addBonusForAllCreatures(bonus);
|
||||||
break;
|
else
|
||||||
|
addNewBonus(bonus);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return currentBid == BuildingID::NONE ? false
|
|
||||||
: addBonusImpl(currentBid, type, val, prop, descr.str(), subtype);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CGTownInstance::addBonusIfBuilt(BuildingSubID::EBuildingSubID subId, Bonus::BonusType type, int val, int subtype)
|
|
||||||
{
|
|
||||||
return addBonusIfBuilt(subId, type, val, emptyPropagator, subtype);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CGTownInstance::addBonusIfBuilt(BuildingID building, Bonus::BonusType type, int val, TPropagatorPtr & prop, int subtype)
|
|
||||||
{
|
|
||||||
if(!hasBuilt(building))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
std::ostringstream descr;
|
|
||||||
descr << town->buildings.at(building)->Name();
|
|
||||||
return addBonusImpl(building, type, val, prop, descr.str(), subtype);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CGTownInstance::addBonusIfBuilt(BuildingID building, Bonus::BonusType type, int val, int subtype)
|
|
||||||
{
|
|
||||||
return addBonusIfBuilt(building, type, val, emptyPropagator, subtype);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CGTownInstance::addBonusImpl(BuildingID building, Bonus::BonusType type, int val, TPropagatorPtr & prop, const std::string & description, int subtype)
|
|
||||||
{
|
|
||||||
auto b = std::make_shared<Bonus>(Bonus::PERMANENT, type, Bonus::TOWN_STRUCTURE, val, building, description, subtype);
|
|
||||||
|
|
||||||
if(prop)
|
|
||||||
b->addPropagator(prop);
|
|
||||||
addNewBonus(b);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CGTownInstance::setVisitingHero(CGHeroInstance *h)
|
void CGTownInstance::setVisitingHero(CGHeroInstance *h)
|
||||||
@ -1738,11 +1719,11 @@ void CTownBonus::setProperty (ui8 what, ui32 val)
|
|||||||
void CTownBonus::onHeroVisit(const CGHeroInstance * h) const
|
void CTownBonus::onHeroVisit(const CGHeroInstance * h) const
|
||||||
{
|
{
|
||||||
ObjectInstanceID heroID = h->id;
|
ObjectInstanceID heroID = h->id;
|
||||||
if (town->hasBuilt(bID) && visitors.find(heroID) == visitors.end())
|
if(town->hasBuilt(bID) && visitors.find(heroID) == visitors.end())
|
||||||
{
|
{
|
||||||
si64 val = 0;
|
si64 val = 0;
|
||||||
InfoWindow iw;
|
InfoWindow iw;
|
||||||
PrimarySkill::PrimarySkill what = PrimarySkill::ATTACK;
|
PrimarySkill::PrimarySkill what = PrimarySkill::NONE;
|
||||||
|
|
||||||
switch (bType)
|
switch (bType)
|
||||||
{
|
{
|
||||||
@ -1775,15 +1756,51 @@ void CTownBonus::onHeroVisit(const CGHeroInstance * h) const
|
|||||||
val = 1;
|
val = 1;
|
||||||
iw.components.push_back(Component(Component::PRIM_SKILL, 1, 1, 0));
|
iw.components.push_back(Component(Component::PRIM_SKILL, 1, 1, 0));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case BuildingSubID::CUSTOM_VISITING_BONUS:
|
||||||
|
const auto building = town->town->buildings.at(bID);
|
||||||
|
if(!h->hasBonusFrom(Bonus::TOWN_STRUCTURE, Bonus::getSid32(building->town->faction->index, building->bid)))
|
||||||
|
{
|
||||||
|
const auto & bonuses = building->onVisitBonuses;
|
||||||
|
applyBonuses(const_cast<CGHeroInstance *>(h), bonuses);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(what != PrimarySkill::NONE)
|
||||||
|
{
|
||||||
|
iw.player = cb->getOwner(heroID);
|
||||||
|
iw.text << getVisitingBonusGreeting();
|
||||||
|
cb->showInfoDialog(&iw);
|
||||||
|
cb->changePrimSkill(cb->getHero(heroID), what, val);
|
||||||
|
town->addHeroToStructureVisitors(h, indexOnTV);
|
||||||
}
|
}
|
||||||
iw.player = cb->getOwner(heroID);
|
|
||||||
iw.text << getVisitingBonusGreeting();
|
|
||||||
cb->showInfoDialog(&iw);
|
|
||||||
cb->changePrimSkill(cb->getHero(heroID), what, val);
|
|
||||||
town->addHeroToStructureVisitors(h, indexOnTV);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CTownBonus::applyBonuses(CGHeroInstance * h, const BonusList & bonuses) const
|
||||||
|
{
|
||||||
|
auto addToVisitors = false;
|
||||||
|
|
||||||
|
for(auto bonus : bonuses)
|
||||||
|
{
|
||||||
|
GiveBonus gb;
|
||||||
|
InfoWindow iw;
|
||||||
|
|
||||||
|
gb.bonus = * bonus;
|
||||||
|
gb.id = h->id.getNum();
|
||||||
|
cb->giveHeroBonus(&gb);
|
||||||
|
|
||||||
|
if(bonus->duration == Bonus::PERMANENT)
|
||||||
|
addToVisitors = true;
|
||||||
|
|
||||||
|
iw.player = cb->getOwner(h->id);
|
||||||
|
iw.text << getCustomBonusGreeting(gb.bonus);
|
||||||
|
cb->showInfoDialog(&iw);
|
||||||
|
}
|
||||||
|
if(addToVisitors)
|
||||||
|
town->addHeroToStructureVisitors(h, indexOnTV);
|
||||||
|
}
|
||||||
|
|
||||||
GrowthInfo::Entry::Entry(const std::string &format, int _count)
|
GrowthInfo::Entry::Entry(const std::string &format, int _count)
|
||||||
: count(_count)
|
: count(_count)
|
||||||
{
|
{
|
||||||
@ -1851,3 +1868,22 @@ const std::string CGTownBuilding::getVisitingBonusGreeting() const
|
|||||||
town->town->setGreeting(bType, bonusGreeting);
|
town->town->setGreeting(bType, bonusGreeting);
|
||||||
return bonusGreeting;
|
return bonusGreeting;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const std::string CGTownBuilding::getCustomBonusGreeting(const Bonus & bonus)
|
||||||
|
{
|
||||||
|
auto bonusGreeting = std::string(VLC->generaltexth->localizedTexts["townHall"]["greetingCustomBonus"].String()); //"%s gives you +%d %s%s"
|
||||||
|
std::string param = "";
|
||||||
|
std::string until = "";
|
||||||
|
|
||||||
|
if(bonus.type == Bonus::MORALE)
|
||||||
|
param = VLC->generaltexth->allTexts[384];
|
||||||
|
else if(bonus.type == Bonus::LUCK)
|
||||||
|
param = VLC->generaltexth->allTexts[385];
|
||||||
|
|
||||||
|
until = bonus.duration == (ui16)Bonus::ONE_BATTLE
|
||||||
|
? VLC->generaltexth->localizedTexts["townHall"]["greetingCustomUntil"].String() : ".";
|
||||||
|
|
||||||
|
boost::format fmt = boost::format(bonusGreeting) % bonus.description % bonus.val % param % until;
|
||||||
|
std::string greeting = fmt.str();
|
||||||
|
return greeting;
|
||||||
|
}
|
||||||
|
@ -133,6 +133,7 @@ protected:
|
|||||||
BuildingSubID::EBuildingSubID bType;
|
BuildingSubID::EBuildingSubID bType;
|
||||||
|
|
||||||
const std::string getVisitingBonusGreeting() const;
|
const std::string getVisitingBonusGreeting() const;
|
||||||
|
static const std::string getCustomBonusGreeting(const Bonus & bonus);
|
||||||
};
|
};
|
||||||
|
|
||||||
class DLL_LINKAGE COPWBonus : public CGTownBuilding
|
class DLL_LINKAGE COPWBonus : public CGTownBuilding
|
||||||
@ -169,6 +170,9 @@ public:
|
|||||||
h & static_cast<CGTownBuilding&>(*this);
|
h & static_cast<CGTownBuilding&>(*this);
|
||||||
h & visitors;
|
h & visitors;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void applyBonuses(CGHeroInstance * h, const BonusList & bonuses) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
class DLL_LINKAGE CTownAndVisitingHero : public CBonusSystemNode
|
class DLL_LINKAGE CTownAndVisitingHero : public CBonusSystemNode
|
||||||
@ -205,7 +209,9 @@ public:
|
|||||||
ConstTransitivePtr<CGHeroInstance> garrisonHero, visitingHero;
|
ConstTransitivePtr<CGHeroInstance> garrisonHero, visitingHero;
|
||||||
ui32 identifier; //special identifier from h3m (only > RoE maps)
|
ui32 identifier; //special identifier from h3m (only > RoE maps)
|
||||||
si32 alignment;
|
si32 alignment;
|
||||||
std::set<BuildingID> forbiddenBuildings, builtBuildings;
|
std::set<BuildingID> forbiddenBuildings;
|
||||||
|
std::set<BuildingID> builtBuildings;
|
||||||
|
std::set<BuildingID> overriddenBuildings; ///buildings which bonuses are overridden and should not be applied
|
||||||
std::vector<CGTownBuilding*> bonusingBuildings;
|
std::vector<CGTownBuilding*> bonusingBuildings;
|
||||||
std::vector<SpellID> possibleSpells, obligatorySpells;
|
std::vector<SpellID> possibleSpells, obligatorySpells;
|
||||||
std::vector<std::vector<SpellID> > spells; //spells[level] -> vector of spells, first will be available in guild
|
std::vector<std::vector<SpellID> > spells; //spells[level] -> vector of spells, first will be available in guild
|
||||||
@ -237,8 +243,8 @@ public:
|
|||||||
h & events;
|
h & events;
|
||||||
h & bonusingBuildings;
|
h & bonusingBuildings;
|
||||||
|
|
||||||
for (std::vector<CGTownBuilding*>::iterator i = bonusingBuildings.begin(); i!=bonusingBuildings.end(); i++)
|
for(auto * bonusingBuilding : bonusingBuildings)
|
||||||
(*i)->town = this;
|
bonusingBuilding->town = this;
|
||||||
|
|
||||||
h & town;
|
h & town;
|
||||||
h & townAndVis;
|
h & townAndVis;
|
||||||
@ -256,6 +262,11 @@ public:
|
|||||||
|
|
||||||
if(!h.saving && version < 793)
|
if(!h.saving && version < 793)
|
||||||
updateBonusingBuildings();
|
updateBonusingBuildings();
|
||||||
|
|
||||||
|
if(version >= 794)
|
||||||
|
h & overriddenBuildings;
|
||||||
|
else if(!h.saving)
|
||||||
|
updateTown794();
|
||||||
}
|
}
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
@ -264,11 +275,6 @@ public:
|
|||||||
void updateMoraleBonusFromArmy() override;
|
void updateMoraleBonusFromArmy() override;
|
||||||
void deserializationFix();
|
void deserializationFix();
|
||||||
void recreateBuildingsBonuses();
|
void recreateBuildingsBonuses();
|
||||||
///bid: param to bind a building with a bonus, subId: param to check if already built
|
|
||||||
bool addBonusIfBuilt(BuildingSubID::EBuildingSubID subId, Bonus::BonusType type, int val, TPropagatorPtr & prop, int subtype = -1);
|
|
||||||
bool addBonusIfBuilt(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);
|
void setVisitingHero(CGHeroInstance *h);
|
||||||
void setGarrisonedHero(CGHeroInstance *h);
|
void setGarrisonedHero(CGHeroInstance *h);
|
||||||
const CArmedInstance *getUpperArmy() const; //garrisoned hero if present or the town itself
|
const CArmedInstance *getUpperArmy() const; //garrisoned hero if present or the town itself
|
||||||
@ -318,6 +324,7 @@ public:
|
|||||||
void removeCapitols (PlayerColor owner) const;
|
void removeCapitols (PlayerColor owner) const;
|
||||||
void clearArmy() const;
|
void clearArmy() const;
|
||||||
void addHeroToStructureVisitors(const CGHeroInstance *h, si64 structureInstanceID) const; //hero must be visiting or garrisoned in town
|
void addHeroToStructureVisitors(const CGHeroInstance *h, si64 structureInstanceID) const; //hero must be visiting or garrisoned in town
|
||||||
|
void deleteTownBonus(BuildingID::EBuildingID bid);
|
||||||
|
|
||||||
const CTown * getTown() const ;
|
const CTown * getTown() const ;
|
||||||
|
|
||||||
@ -336,7 +343,6 @@ public:
|
|||||||
static void reset();
|
static void reset();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
static TPropagatorPtr emptyPropagator;
|
|
||||||
void setPropertyDer(ui8 what, ui32 val) override;
|
void setPropertyDer(ui8 what, ui32 val) override;
|
||||||
void serializeJsonOptions(JsonSerializeFormat & handler) override;
|
void serializeJsonOptions(JsonSerializeFormat & handler) override;
|
||||||
|
|
||||||
@ -344,9 +350,10 @@ private:
|
|||||||
int getDwellingBonus(const std::vector<CreatureID>& creatureIds, const std::vector<ConstTransitivePtr<CGDwelling> >& dwellings) const;
|
int getDwellingBonus(const std::vector<CreatureID>& creatureIds, const std::vector<ConstTransitivePtr<CGDwelling> >& dwellings) const;
|
||||||
void updateBonusingBuildings();
|
void updateBonusingBuildings();
|
||||||
bool hasBuiltInOldWay(ETownType::ETownType type, BuildingID bid) const;
|
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);
|
|
||||||
bool townEnvisagesBuilding(BuildingSubID::EBuildingSubID bid) const;
|
bool townEnvisagesBuilding(BuildingSubID::EBuildingSubID bid) const;
|
||||||
void tryAddOnePerWeekBonus(BuildingSubID::EBuildingSubID subID);
|
void tryAddOnePerWeekBonus(BuildingSubID::EBuildingSubID subID);
|
||||||
void tryAddVisitingBonus(BuildingSubID::EBuildingSubID subID);
|
void tryAddVisitingBonus(BuildingSubID::EBuildingSubID subID);
|
||||||
|
void initOverriddenBids();
|
||||||
void addTownBonuses();
|
void addTownBonuses();
|
||||||
|
void updateTown794(); //populate overriddenBuildings and vanila bonuses for old saves
|
||||||
};
|
};
|
||||||
|
@ -260,7 +260,7 @@ void CGObjectInstance::giveDummyBonus(ObjectInstanceID heroID, ui8 duration) con
|
|||||||
GiveBonus gbonus;
|
GiveBonus gbonus;
|
||||||
gbonus.bonus.type = Bonus::NONE;
|
gbonus.bonus.type = Bonus::NONE;
|
||||||
gbonus.id = heroID.getNum();
|
gbonus.id = heroID.getNum();
|
||||||
gbonus.bonus.duration = duration;
|
gbonus.bonus.duration = (Bonus::BonusDuration)duration;
|
||||||
gbonus.bonus.source = Bonus::OBJECT;
|
gbonus.bonus.source = Bonus::OBJECT;
|
||||||
gbonus.bonus.sid = ID;
|
gbonus.bonus.sid = ID;
|
||||||
cb->giveHeroBonus(&gbonus);
|
cb->giveHeroBonus(&gbonus);
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
#include "../ConstTransitivePtr.h"
|
#include "../ConstTransitivePtr.h"
|
||||||
#include "../GameConstants.h"
|
#include "../GameConstants.h"
|
||||||
|
|
||||||
const ui32 SERIALIZATION_VERSION = 793;
|
const ui32 SERIALIZATION_VERSION = 794;
|
||||||
const ui32 MINIMAL_SERIALIZATION_VERSION = 753;
|
const ui32 MINIMAL_SERIALIZATION_VERSION = 753;
|
||||||
const std::string SAVEGAME_MAGIC = "VCMISVG";
|
const std::string SAVEGAME_MAGIC = "VCMISVG";
|
||||||
|
|
||||||
|
@ -3147,16 +3147,14 @@ bool CGameHandler::buildStructure(ObjectInstanceID tid, BuildingID requestedID,
|
|||||||
processBeforeBuiltStructure(builtID);
|
processBeforeBuiltStructure(builtID);
|
||||||
|
|
||||||
//Take cost
|
//Take cost
|
||||||
if (!force)
|
if(!force)
|
||||||
{
|
|
||||||
giveResources(t->tempOwner, -requestedBuilding->resources);
|
giveResources(t->tempOwner, -requestedBuilding->resources);
|
||||||
}
|
|
||||||
|
|
||||||
//We know what has been built, appluy changes. Do this as final step to properly update town window
|
//We know what has been built, apply changes. Do this as final step to properly update town window
|
||||||
sendAndApply(&ns);
|
sendAndApply(&ns);
|
||||||
|
|
||||||
//Other post-built events. To some logic like giving spells to work gamestate changes for new building must be already in place!
|
//Other post-built events. To some logic like giving spells to work gamestate changes for new building must be already in place!
|
||||||
for (auto builtID : ns.bid)
|
for(auto builtID : ns.bid)
|
||||||
processAfterBuiltStructure(builtID);
|
processAfterBuiltStructure(builtID);
|
||||||
|
|
||||||
// now when everything is built - reveal tiles for lookout tower
|
// now when everything is built - reveal tiles for lookout tower
|
||||||
@ -3166,14 +3164,15 @@ bool CGameHandler::buildStructure(ObjectInstanceID tid, BuildingID requestedID,
|
|||||||
getTilesInRange(fw.tiles, t->getSightCenter(), t->getSightRadius(), t->tempOwner, 1);
|
getTilesInRange(fw.tiles, t->getSightCenter(), t->getSightRadius(), t->tempOwner, 1);
|
||||||
sendAndApply(&fw);
|
sendAndApply(&fw);
|
||||||
|
|
||||||
if (t->visitingHero)
|
if(t->visitingHero)
|
||||||
visitCastleObjects(t, t->visitingHero);
|
visitCastleObjects(t, t->visitingHero);
|
||||||
if (t->garrisonHero)
|
if(t->garrisonHero)
|
||||||
visitCastleObjects(t, t->garrisonHero);
|
visitCastleObjects(t, t->garrisonHero);
|
||||||
|
|
||||||
checkVictoryLossConditionsForPlayer(t->tempOwner);
|
checkVictoryLossConditionsForPlayer(t->tempOwner);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CGameHandler::razeStructure (ObjectInstanceID tid, BuildingID bid)
|
bool CGameHandler::razeStructure (ObjectInstanceID tid, BuildingID bid)
|
||||||
{
|
{
|
||||||
///incomplete, simply erases target building
|
///incomplete, simply erases target building
|
||||||
|
Loading…
Reference in New Issue
Block a user