mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-24 22:14:36 +02:00
Mod system improvement Part I : Old saves support & MSVS build fix
This commit is contained in:
parent
6a7296fbe9
commit
bf07cd0ad9
@ -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<std::string, CBuilding::EBuildMode> CBuilding::MODES =
|
||||
{
|
||||
{ "normal", CBuilding::BUILD_NORMAL },
|
||||
{ "auto", CBuilding::BUILD_AUTO },
|
||||
{ "special", CBuilding::BUILD_SPECIAL },
|
||||
{ "grail", CBuilding::BUILD_GRAIL }
|
||||
};
|
||||
|
||||
}
|
||||
const std::map<std::string, CBuilding::ETowerHeight> 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<std::string, BuildingID>(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<BuildingSubID::EBuildingSubID>(currentBuilding["type"], BuildingSubID::NONE, MappedKeys::SPECIAL_BUILDINGS);
|
||||
height = CBuilding::HEIGHT_NO_TOWER;
|
||||
|
||||
if (subId == BuildingSubID::LOOKOUT_TOWER || bid == BuildingID::GRAIL)
|
||||
height = CTownHandler::getMappedValue<CBuilding::ETowerHeight>(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<typename R>
|
||||
R CTownHandler::getMappedValue(const std::string key, const R defval, const std::map<std::string, R> & map, bool required) const
|
||||
template<typename R, typename K>
|
||||
R CTownHandler::getMappedValue(const K key, const R defval, const std::map<K, R> & 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<typename R>
|
||||
R CTownHandler::getMappedValue(const JsonNode & node, const R defval, const std::map<std::string, R> & map, bool required) const
|
||||
R CTownHandler::getMappedValue(const JsonNode & node, const R defval, const std::map<std::string, R> & map, bool required)
|
||||
{
|
||||
if(!node.isNull() && node.getType() == JsonNode::JsonType::DATA_STRING)
|
||||
return getMappedValue<R>(node.String(), defval, map, required);
|
||||
return getMappedValue<R, std::string>(node.String(), defval, map, required);
|
||||
return defval;
|
||||
}
|
||||
|
||||
void CTownHandler::loadBuilding(CTown * town, const std::string & stringID, const JsonNode & source)
|
||||
{
|
||||
static const std::map<std::string, CBuilding::EBuildMode> MODES =
|
||||
{
|
||||
{ "normal", CBuilding::BUILD_NORMAL },
|
||||
{ "auto", CBuilding::BUILD_AUTO },
|
||||
{ "special", CBuilding::BUILD_SPECIAL },
|
||||
{ "grail", CBuilding::BUILD_GRAIL }
|
||||
};
|
||||
|
||||
static const std::map<std::string, BuildingID> 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<std::string, CBuilding::ETowerHeight> LOOKOUT_TYPES =
|
||||
{
|
||||
{ "low", CBuilding::HEIGHT_LOW },
|
||||
{ "average", CBuilding::HEIGHT_AVERAGE },
|
||||
{ "high", CBuilding::HEIGHT_HIGH },
|
||||
{ "skyship", CBuilding::HEIGHT_SKYSHIP }
|
||||
};
|
||||
|
||||
static const std::map<std::string, BuildingSubID::EBuildingSubID> 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<BuildingID>(stringID, BuildingID::NONE, BUILDING_TYPES, false);
|
||||
ret->bid = getMappedValue<BuildingID, std::string>(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<CBuilding::EBuildMode>(source["mode"], CBuilding::BUILD_NORMAL, MODES);
|
||||
: getMappedValue<CBuilding::EBuildMode>(source["mode"], CBuilding::BUILD_NORMAL, CBuilding::MODES);
|
||||
|
||||
ret->subId = getMappedValue<BuildingSubID::EBuildingSubID>(source["type"], BuildingSubID::NONE, SPECIAL_BUILDINGS);
|
||||
ret->subId = getMappedValue<BuildingSubID::EBuildingSubID>(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<CBuilding::ETowerHeight>(source["height"], CBuilding::HEIGHT_NO_TOWER, LOOKOUT_TYPES);
|
||||
ret->height = getMappedValue<CBuilding::ETowerHeight>(source["height"], CBuilding::HEIGHT_NO_TOWER, CBuilding::TOWER_TYPES);
|
||||
|
||||
ret->identifier = stringID;
|
||||
ret->town = town;
|
||||
|
@ -65,7 +65,10 @@ public:
|
||||
HEIGHT_SKYSHIP = std::numeric_limits<int>::max() // grail, open entire map
|
||||
} height;
|
||||
|
||||
CBuilding();
|
||||
static const std::map<std::string, CBuilding::EBuildMode> MODES;
|
||||
static const std::map<std::string, CBuilding::ETowerHeight> 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 <typename Handler> 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<typename R>
|
||||
R getMappedValue(const std::string key, const R defval, const std::map<std::string, R> & map, bool required = true) const;
|
||||
template<typename R>
|
||||
R getMappedValue(const JsonNode& node, const R defval, const std::map<std::string, R> & map, bool required = true) const;
|
||||
|
||||
public:
|
||||
template<typename R, typename K>
|
||||
static R getMappedValue(const K key, const R defval, const std::map<K, R> & map, bool required = true);
|
||||
template<typename R>
|
||||
static R getMappedValue(const JsonNode & node, const R defval, const std::map<std::string, R> & map, bool required = true);
|
||||
|
||||
std::vector<ConstTransitivePtr<CFaction> > factions;
|
||||
|
||||
CTown * randomTown;
|
||||
|
@ -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<std::string, BuildingID> 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<BuildingID, std::string> 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<std::string, BuildingSubID::EBuildingSubID> 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
|
||||
{
|
||||
|
@ -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 <typename Handler> 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)
|
||||
{
|
||||
}
|
||||
|
@ -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>(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>(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>(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))
|
||||
|
@ -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 <typename Handler> 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<CreatureID>& creatureIds, const std::vector<ConstTransitivePtr<CGDwelling> >& 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);
|
||||
};
|
||||
|
@ -214,7 +214,7 @@ CObjectClassesHandler::ObjectContainter * CObjectClassesHandler::loadFromJson(co
|
||||
if(json["defaultAiValue"].isNull())
|
||||
obj->groupDefaultAiValue = boost::none;
|
||||
else
|
||||
obj->groupDefaultAiValue = static_cast<si32>(json["defaultAiValue"].Integer());
|
||||
obj->groupDefaultAiValue = static_cast<boost::optional<si32>>(json["defaultAiValue"].Integer());
|
||||
|
||||
for (auto entry : json["types"].Struct())
|
||||
{
|
||||
@ -475,7 +475,7 @@ void AObjectTypeHandler::init(const JsonNode & input, boost::optional<std::strin
|
||||
if(input["aiValue"].isNull())
|
||||
aiValue = boost::none;
|
||||
else
|
||||
aiValue = static_cast<si32>(input["aiValue"].Integer());
|
||||
aiValue = static_cast<boost::optional<si32>>(input["aiValue"].Integer());
|
||||
|
||||
initTypeData(input);
|
||||
}
|
||||
|
@ -2521,9 +2521,8 @@ void CGameHandler::heroVisitCastle(const CGTownInstance * obj, const CGHeroInsta
|
||||
|
||||
void CGameHandler::visitCastleObjects(const CGTownInstance * t, const CGHeroInstance * h)
|
||||
{
|
||||
std::vector<CGTownBuilding*>::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)
|
||||
|
Loading…
Reference in New Issue
Block a user