1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-26 22:57:00 +02:00

Merge pull request #659 from ShubusCorporation/shc_special_buildings_2

Mod system improvement: Special buildings should work in modders towns. Part II.
This commit is contained in:
Alexander Shishkin 2020-10-20 17:29:15 +03:00 committed by GitHub
commit c0a5d1ccf0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 189 additions and 111 deletions

View File

@ -170,7 +170,7 @@
"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" : [ "shipyard" ] }, "special1": { "type" : "lighthouse", "requires" : [ "shipyard" ] },
"horde1": { "id" : 18, "upgrades" : "dwellingLvl3" }, "horde1": { "id" : 18, "upgrades" : "dwellingLvl3" },
"horde1Upgr": { "id" : 19, "upgrades" : "dwellingUpLvl3", "requires" : [ "horde1" ], "mode" : "auto" }, "horde1Upgr": { "id" : 19, "upgrades" : "dwellingUpLvl3", "requires" : [ "horde1" ], "mode" : "auto" },
"ship": { "id" : 20, "upgrades" : "shipyard" }, "ship": { "id" : 20, "upgrades" : "shipyard" },

View File

@ -174,7 +174,7 @@
"horde1Upgr": { "id" : 19, "upgrades" : "dwellingUpLvl1", "requires" : [ "horde1" ], "mode" : "auto" }, "horde1Upgr": { "id" : 19, "upgrades" : "dwellingUpLvl1", "requires" : [ "horde1" ], "mode" : "auto" },
"special2": { "type" : "manaVortex", "requires" : [ "mageGuild1" ] }, "special2": { "type" : "manaVortex", "requires" : [ "mageGuild1" ] },
"special3": { "type" : "portalOfSummoning" }, "special3": { "type" : "portalOfSummoning" },
"special4": { }, "special4": { "type" : "experienceVisitingBonus" },
"grail": { "id" : 26, "mode" : "grail", "produce": { "gold": 5000 }}, "grail": { "id" : 26, "mode" : "grail", "produce": { "gold": 5000 }},
"dwellingLvl1": { "id" : 30, "requires" : [ "fort" ] }, "dwellingLvl1": { "id" : 30, "requires" : [ "fort" ] },

View File

@ -169,7 +169,7 @@
"resourceSilo": { "id" : 15, "requires" : [ "marketplace" ], "produce": { "wood": 1, "ore": 1 } }, "resourceSilo": { "id" : 15, "requires" : [ "marketplace" ], "produce": { "wood": 1, "ore": 1 } },
"blacksmith": { "id" : 16 }, "blacksmith": { "id" : 16 },
"special1": { "requires" : [ "allOf", [ "townHall" ], [ "special2" ] ] }, "special1": { "type" : "defenceVisitingBonus", "requires" : [ "allOf", [ "townHall" ], [ "special2" ] ] },
"horde1": { "id" : 18, "upgrades" : "dwellingLvl1" }, "horde1": { "id" : 18, "upgrades" : "dwellingLvl1" },
"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" },

View File

@ -174,7 +174,7 @@
"horde1Upgr": { "id" : 19, "upgrades" : "dwellingUpLvl1", "requires" : [ "horde1" ], "mode" : "auto" }, "horde1Upgr": { "id" : 19, "upgrades" : "dwellingUpLvl1", "requires" : [ "horde1" ], "mode" : "auto" },
"special2": { "type" : "spellPowerGarrisonBonus", "requires" : [ "fort" ] }, "special2": { "type" : "spellPowerGarrisonBonus", "requires" : [ "fort" ] },
"special3": { "type" : "castleGate", "requires" : [ "citadel" ] }, "special3": { "type" : "castleGate", "requires" : [ "citadel" ] },
"special4": { "requires" : [ "mageGuild1" ] }, "special4": { "type" : "spellPowerVisitingBonus", "requires" : [ "mageGuild1" ] },
"horde2": { "id" : 24, "upgrades" : "dwellingLvl3" }, "horde2": { "id" : 24, "upgrades" : "dwellingLvl3" },
"horde2Upgr": { "id" : 25, "upgrades" : "dwellingUpLvl3", "requires" : [ "horde2" ], "mode" : "auto" }, "horde2Upgr": { "id" : 25, "upgrades" : "dwellingUpLvl3", "requires" : [ "horde2" ], "mode" : "auto" },
"grail": { "id" : 26, "mode" : "grail", "produce": { "gold": 5000 }}, "grail": { "id" : 26, "mode" : "grail", "produce": { "gold": 5000 }},

View File

@ -178,7 +178,7 @@
"horde1": { "id" : 18, "upgrades" : "dwellingLvl2" }, "horde1": { "id" : 18, "upgrades" : "dwellingLvl2" },
"horde1Upgr": { "id" : 19, "upgrades" : "dwellingUpLvl2", "requires" : [ "horde1" ], "mode" : "auto" }, "horde1Upgr": { "id" : 19, "upgrades" : "dwellingUpLvl2", "requires" : [ "horde1" ], "mode" : "auto" },
"special2": { "type" : "fountainOfFortune", "upgrades" : "special1" }, "special2": { "type" : "fountainOfFortune", "upgrades" : "special1" },
"special3": { "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 }},

View File

@ -171,7 +171,7 @@
"horde1Upgr": { "id" : 19, "upgrades" : "dwellingUpLvl1", "requires" : [ "horde1" ], "mode" : "auto" }, "horde1Upgr": { "id" : 19, "upgrades" : "dwellingUpLvl1", "requires" : [ "horde1" ], "mode" : "auto" },
"special2": { "type" : "freelancersGuild", "requires" : [ "marketplace" ] }, "special2": { "type" : "freelancersGuild", "requires" : [ "marketplace" ] },
"special3": { "type" : "ballistaYard", "requires" : [ "blacksmith" ] }, "special3": { "type" : "ballistaYard", "requires" : [ "blacksmith" ] },
"special4": { "requires" : [ "fort" ] }, "special4": { "type" : "attackVisitingBonus", "requires" : [ "fort" ] },
"grail": { "id" : 26, "mode" : "grail", "produce": { "gold": 5000 }}, "grail": { "id" : 26, "mode" : "grail", "produce": { "gold": 5000 }},
"dwellingLvl1": { "id" : 30, "requires" : [ "fort" ] }, "dwellingLvl1": { "id" : 30, "requires" : [ "fort" ] },

View File

@ -174,7 +174,7 @@
"horde1Upgr": { "id" : 19, "upgrades" : "dwellingUpLvl2", "requires" : [ "horde1" ], "mode" : "auto" }, "horde1Upgr": { "id" : 19, "upgrades" : "dwellingUpLvl2", "requires" : [ "horde1" ], "mode" : "auto" },
"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": { "requires" : [ "mageGuild1" ] }, "special4": { "type" : "knowledgeVisitingBonus", "requires" : [ "mageGuild1" ] },
"grail": { "height" : "skyship", "produce" : { "gold": 5000 } }, "grail": { "height" : "skyship", "produce" : { "gold": 5000 } },
"dwellingLvl1": { "id" : 30, "requires" : [ "fort" ] }, "dwellingLvl1": { "id" : 30, "requires" : [ "fort" ] },

View File

@ -195,6 +195,13 @@ public:
h & imageBattleFemale; h & imageBattleFemale;
h & imageMapMale; h & imageMapMale;
h & imageMapFemale; h & imageMapFemale;
if(!h.saving)
{
for(auto i = 0; i < secSkillProbability.size(); i++)
if(secSkillProbability[i] < 0)
secSkillProbability[i] = 0;
}
} }
EAlignment::EAlignment getAlignment() const; EAlignment::EAlignment getAlignment() const;
}; };

View File

@ -34,6 +34,7 @@ CSkill::LevelInfo::~LevelInfo()
CSkill::CSkill(SecondarySkill id, std::string identifier) CSkill::CSkill(SecondarySkill id, std::string identifier)
: id(id), identifier(identifier) : id(id), identifier(identifier)
{ {
gainChance[0] = gainChance[1] = 0; //affects CHeroClassHandler::afterLoadFinalization()
levels.resize(NSecondarySkill::levels.size() - 1); levels.resize(NSecondarySkill::levels.size() - 1);
} }

View File

@ -85,6 +85,22 @@ public:
return bid == BuildingID::MARKETPLACE || subId == BuildingSubID::ARTIFACT_MERCHANT || subId == BuildingSubID::FREELANCERS_GUILD; return bid == BuildingID::MARKETPLACE || subId == BuildingSubID::ARTIFACT_MERCHANT || subId == BuildingSubID::FREELANCERS_GUILD;
} }
STRONG_INLINE
bool IsWeekBonus() const
{
return subId == BuildingSubID::STABLES || subId == BuildingSubID::MANA_VORTEX;
}
STRONG_INLINE
bool IsVisitingBonus() const
{
return subId == BuildingSubID::ATTACK_VISITING_BONUS ||
subId == BuildingSubID::DEFENSE_VISITING_BONUS ||
subId == BuildingSubID::SPELL_POWER_VISITING_BONUS ||
subId == BuildingSubID::KNOWLEDGE_VISITING_BONUS ||
subId == BuildingSubID::EXPERIENCE_VISITING_BONUS;
}
/// input: faction, bid; output: subId, height; /// input: faction, bid; output: subId, height;
void update792(const BuildingID & bid, BuildingSubID::EBuildingSubID & subId, ETowerHeight & height); void update792(const BuildingID & bid, BuildingSubID::EBuildingSubID & subId, ETowerHeight & height);

View File

@ -442,11 +442,17 @@ namespace BuildingSubID
ESCAPE_TUNNEL, ESCAPE_TUNNEL,
FREELANCERS_GUILD, FREELANCERS_GUILD,
BALLISTA_YARD, BALLISTA_YARD,
HALL_OF_VALHALLA, ATTACK_VISITING_BONUS,
MAGIC_UNIVERSITY, MAGIC_UNIVERSITY,
SPELL_POWER_GARRISON_BONUS, SPELL_POWER_GARRISON_BONUS,
ATTACK_GARRISON_BONUS, ATTACK_GARRISON_BONUS,
DEFENSE_GARRISON_BONUS DEFENSE_GARRISON_BONUS,
DEFENSE_VISITING_BONUS,
SPELL_POWER_VISITING_BONUS,
KNOWLEDGE_VISITING_BONUS,
EXPERIENCE_VISITING_BONUS,
LIGHTHOUSE,
TREASURY
}; };
} }
@ -490,7 +496,14 @@ namespace MappedKeys
{ "spellPowerGarrisonBonus", BuildingSubID::SPELL_POWER_GARRISON_BONUS },//such as 'stormclouds', but this name is not ok for good towns { "spellPowerGarrisonBonus", BuildingSubID::SPELL_POWER_GARRISON_BONUS },//such as 'stormclouds', but this name is not ok for good towns
{ "attackGarrisonBonus", BuildingSubID::ATTACK_GARRISON_BONUS }, { "attackGarrisonBonus", BuildingSubID::ATTACK_GARRISON_BONUS },
{ "defenseGarrisonBonus", BuildingSubID::DEFENSE_GARRISON_BONUS }, { "defenseGarrisonBonus", BuildingSubID::DEFENSE_GARRISON_BONUS },
{ "escapeTunnel", BuildingSubID::ESCAPE_TUNNEL } { "escapeTunnel", BuildingSubID::ESCAPE_TUNNEL },
{ "attackVisitingBonus", BuildingSubID::ATTACK_VISITING_BONUS },
{ "defenceVisitingBonus", BuildingSubID::DEFENSE_VISITING_BONUS },
{ "spellPowerVisitingBonus", BuildingSubID::SPELL_POWER_VISITING_BONUS },
{ "knowledgeVisitingBonus", BuildingSubID::KNOWLEDGE_VISITING_BONUS },
{ "experienceVisitingBonus", BuildingSubID::EXPERIENCE_VISITING_BONUS },
{ "lighthouse", BuildingSubID::LIGHTHOUSE },
{ "treasury", BuildingSubID::TREASURY }
}; };
} }

View File

@ -744,18 +744,36 @@ bool CGTownInstance::townEnvisagesBuilding(BuildingSubID::EBuildingSubID subId)
return town->getBuildingType(subId) != BuildingID::NONE; return town->getBuildingType(subId) != BuildingID::NONE;
} }
//it does not check hasBuilt(...) because this check is in the OnHeroVisit handler //it does not check hasBuilt because this check is in the OnHeroVisit handler
bool CGTownInstance::tryAddOnePerWeekBonus(BuildingSubID::EBuildingSubID subID) void CGTownInstance::tryAddOnePerWeekBonus(BuildingSubID::EBuildingSubID subID)
{ {
auto bid = town->getBuildingType(subID); auto bid = town->getBuildingType(subID);
if(bid == BuildingID::NONE) if(bid != BuildingID::NONE)
return false; bonusingBuildings.push_back(new COPWBonus(bid, subID, this));
bonusingBuildings.push_back(new COPWBonus(bid, subID, this));
return true;
} }
void CGTownInstance::tryAddVisitingBonus(BuildingSubID::EBuildingSubID subID)
{
auto bid = town->getBuildingType(subID);
if(bid != BuildingID::NONE)
bonusingBuildings.push_back(new CTownBonus(bid, subID, this));
}
void CGTownInstance::addTownBonuses()
{
for(const auto & kvp : town->buildings)
{
if(kvp.second->IsVisitingBonus())
bonusingBuildings.push_back(new CTownBonus(kvp.second->bid, kvp.second->subId, this));
if(kvp.second->IsWeekBonus())
bonusingBuildings.push_back(new COPWBonus(kvp.second->bid, kvp.second->subId, this));
}
}
void CGTownInstance::initObj(CRandomGenerator & rand) ///initialize town structures void CGTownInstance::initObj(CRandomGenerator & rand) ///initialize town structures
{ {
blockVisit = true; blockVisit = true;
@ -776,24 +794,7 @@ 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]);
} }
} }
tryAddOnePerWeekBonus(BuildingSubID::STABLES); addTownBonuses(); //add special bonuses from buildings to the bonusingBuildings vector.
tryAddOnePerWeekBonus(BuildingSubID::MANA_VORTEX);
switch (subID)
{
//add new visitable objects
case ETownType::DUNGEON:
case ETownType::TOWER:
case ETownType::INFERNO:
case ETownType::STRONGHOLD:
bonusingBuildings.push_back (new CTownBonus(BuildingID::SPECIAL_4, this));
break;
case ETownType::FORTRESS:
bonusingBuildings.push_back (new CTownBonus(BuildingID::SPECIAL_1, this));
break;
}
//add special bonuses from buildings
recreateBuildingsBonuses(); recreateBuildingsBonuses();
updateAppearance(); updateAppearance();
} }
@ -803,18 +804,35 @@ void CGTownInstance::updateBonusingBuildings()
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) for (auto building : bonusingBuildings) //no garrison bonuses here, only week and visiting bonuses
{ {
switch (this->town->faction->index) switch (this->town->faction->index)
{ {
case ETownType::CASTLE: case ETownType::CASTLE:
if (building->getBuildingType() == BuildingID::SPECIAL_2) building->setBuildingSubtype(BuildingSubID::STABLES);
building->setBuildingSubtype(BuildingSubID::STABLES);
break; break;
case ETownType::DUNGEON: case ETownType::DUNGEON:
if(building->getBuildingType() == BuildingID::SPECIAL_2) if(building->getBuildingType() == BuildingID::SPECIAL_2)
building->setBuildingSubtype(BuildingSubID::MANA_VORTEX); building->setBuildingSubtype(BuildingSubID::MANA_VORTEX);
else if(building->getBuildingType() == BuildingID::SPECIAL_4)
building->setBuildingSubtype(BuildingSubID::EXPERIENCE_VISITING_BONUS);
break;
case ETownType::TOWER:
building->setBuildingSubtype(BuildingSubID::KNOWLEDGE_VISITING_BONUS);
break;
case ETownType::STRONGHOLD:
building->setBuildingSubtype(BuildingSubID::ATTACK_VISITING_BONUS);
break;
case ETownType::INFERNO:
building->setBuildingSubtype(BuildingSubID::SPELL_POWER_VISITING_BONUS);
break;
case ETownType::FORTRESS:
building->setBuildingSubtype(BuildingSubID::DEFENSE_VISITING_BONUS);
break; break;
} }
} }
@ -824,23 +842,24 @@ void CGTownInstance::updateBonusingBuildings()
{ {
auto & building = kvp.second; auto & building = kvp.second;
switch (building->subId) if(building->subId == BuildingSubID::PORTAL_OF_SUMMONING)
{ {
case BuildingSubID::PORTAL_OF_SUMMONING:
if(!hasBuiltInOldWay(ETownType::DUNGEON, BuildingID::PORTAL_OF_SUMMON)) if(!hasBuiltInOldWay(ETownType::DUNGEON, BuildingID::PORTAL_OF_SUMMON))
creatures.resize(GameConstants::CREATURES_PER_TOWN + 1); creatures.resize(GameConstants::CREATURES_PER_TOWN + 1);
break; continue;
///'hasBuilt' checking for COPW bonuses is in the COPWBonus::onHeroVisit
case BuildingSubID::STABLES:
if(getBonusingBuilding(building->subId) == nullptr)
tryAddOnePerWeekBonus(BuildingSubID::STABLES);
break;
case BuildingSubID::MANA_VORTEX:
if(getBonusingBuilding(building->subId) == nullptr)
tryAddOnePerWeekBonus(BuildingSubID::MANA_VORTEX);
break;
} }
if(!building->IsVisitingBonus() && !building->IsWeekBonus()) //it's not bonusing => nothing to handle
continue;
if(getBonusingBuilding(building->subId) != nullptr) //it's already added => already handled
continue;
///'hasBuilt' checking for bonuses is in the onHeroVisit handler
if(building->IsWeekBonus())
tryAddOnePerWeekBonus(building->subId);
if(building->IsVisitingBonus())
tryAddVisitingBonus(building->subId);
} }
recreateBuildingsBonuses(); ///Clear all bonuses and recreate recreateBuildingsBonuses(); ///Clear all bonuses and recreate
} }
@ -1180,11 +1199,11 @@ void CGTownInstance::recreateBuildingsBonuses()
addBonusIfBuilt(BuildingSubID::SPELL_POWER_GARRISON_BONUS, Bonus::PRIMARY_SKILL, +2, PrimarySkill::SPELL_POWER);//works as Brimstone Clouds 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::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::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(subID == ETownType::CASTLE) //castle
{ {
addBonusIfBuilt(BuildingID::LIGHTHOUSE, Bonus::SEA_MOVEMENT, +500, playerProp); addBonusIfBuilt(BuildingID::GRAIL, Bonus::MORALE, +2, playerProp); //colossus
addBonusIfBuilt(BuildingID::GRAIL, Bonus::MORALE, +2, playerProp); //colossus
} }
else if(subID == ETownType::RAMPART) //rampart else if(subID == ETownType::RAMPART) //rampart
{ {
@ -1215,14 +1234,14 @@ void CGTownInstance::recreateBuildingsBonuses()
} }
} }
bool CGTownInstance::addBonusIfBuilt(BuildingSubID::EBuildingSubID subId, Bonus::BonusType type, int val, int subtype) bool CGTownInstance::addBonusIfBuilt(BuildingSubID::EBuildingSubID subId, Bonus::BonusType type, int val, TPropagatorPtr & prop, int subtype)
{ {
BuildingID currentBid = BuildingID::NONE; BuildingID currentBid = BuildingID::NONE;
std::ostringstream descr; std::ostringstream descr;
for(const auto & bid : builtBuildings) for(const auto & bid : builtBuildings)
{ {
if (town->buildings.at(bid)->subId == subId) if(town->buildings.at(bid)->subId == subId)
{ {
descr << town->buildings.at(bid)->Name(); descr << town->buildings.at(bid)->Name();
currentBid = bid; currentBid = bid;
@ -1230,12 +1249,12 @@ bool CGTownInstance::addBonusIfBuilt(BuildingSubID::EBuildingSubID subId, Bonus:
} }
} }
return currentBid == BuildingID::NONE ? false return currentBid == BuildingID::NONE ? false
: addBonusImpl(currentBid, type, val, emptyPropagator, descr.str(), subtype); : addBonusImpl(currentBid, type, val, prop, descr.str(), subtype);
} }
bool CGTownInstance::addBonusIfBuilt(BuildingID building, Bonus::BonusType type, int val, int subtype) bool CGTownInstance::addBonusIfBuilt(BuildingSubID::EBuildingSubID subId, Bonus::BonusType type, int val, int subtype)
{ {
return addBonusIfBuilt(building, type, val, emptyPropagator, subtype); return addBonusIfBuilt(subId, type, val, emptyPropagator, subtype);
} }
bool CGTownInstance::addBonusIfBuilt(BuildingID building, Bonus::BonusType type, int val, TPropagatorPtr & prop, int subtype) bool CGTownInstance::addBonusIfBuilt(BuildingID building, Bonus::BonusType type, int val, TPropagatorPtr & prop, int subtype)
@ -1248,6 +1267,11 @@ bool CGTownInstance::addBonusIfBuilt(BuildingID building, Bonus::BonusType type,
return addBonusImpl(building, type, val, prop, descr.str(), subtype); 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) 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); auto b = std::make_shared<Bonus>(Bonus::PERMANENT, type, Bonus::TOWN_STRUCTURE, val, building, description, subtype);
@ -1686,9 +1710,10 @@ void COPWBonus::onHeroVisit(const CGHeroInstance * h) const
} }
} }
} }
CTownBonus::CTownBonus (BuildingID index, CGTownInstance *TOWN) CTownBonus::CTownBonus (BuildingID index, BuildingSubID::EBuildingSubID subId, CGTownInstance *TOWN)
{ {
bID = index; bID = index;
bType = subId;
town = TOWN; town = TOWN;
indexOnTV = static_cast<si32>(town->bonusingBuildings.size()); indexOnTV = static_cast<si32>(town->bonusingBuildings.size());
} }
@ -1699,64 +1724,58 @@ void CTownBonus::setProperty (ui8 what, ui32 val)
visitors.insert(ObjectInstanceID(val)); visitors.insert(ObjectInstanceID(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())
{ {
si32 mid=0; si32 mid = 0;
si64 val = 0; si64 val = 0;
InfoWindow iw; InfoWindow iw;
PrimarySkill::PrimarySkill what = PrimarySkill::ATTACK; PrimarySkill::PrimarySkill what = PrimarySkill::ATTACK;
switch (bID) switch (bType)
{ {
case BuildingID::SPECIAL_4: case BuildingSubID::KNOWLEDGE_VISITING_BONUS: //wall of knowledge
switch(town->subID) what = PrimarySkill::KNOWLEDGE;
{ val = 1;
case ETownType::TOWER: //wall mid = 581;
what = PrimarySkill::KNOWLEDGE; iw.components.push_back(Component(Component::PRIM_SKILL, 3, 1, 0));
val = 1; break;
mid = 581;
iw.components.push_back (Component(Component::PRIM_SKILL, 3, 1, 0)); case BuildingSubID::SPELL_POWER_VISITING_BONUS: //order of fire
break; what = PrimarySkill::SPELL_POWER;
case ETownType::INFERNO: //order of fire val = 1;
what = PrimarySkill::SPELL_POWER; mid = 582;
val = 1; iw.components.push_back(Component(Component::PRIM_SKILL, 2, 1, 0));
mid = 582; break;
iw.components.push_back (Component(Component::PRIM_SKILL, 2, 1, 0));
break; case BuildingSubID::ATTACK_VISITING_BONUS: //hall of Valhalla
case ETownType::STRONGHOLD://hall of Valhalla what = PrimarySkill::ATTACK;
what = PrimarySkill::ATTACK; val = 1;
val = 1; mid = 584;
mid = 584; iw.components.push_back(Component(Component::PRIM_SKILL, 0, 1, 0));
iw.components.push_back (Component(Component::PRIM_SKILL, 0, 1, 0)); break;
break;
case ETownType::DUNGEON://academy of battle scholars case BuildingSubID::EXPERIENCE_VISITING_BONUS: //academy of battle scholars
what = PrimarySkill::EXPERIENCE; what = PrimarySkill::EXPERIENCE;
val = static_cast<int>(h->calculateXp(1000)); val = static_cast<int>(h->calculateXp(1000));
mid = 583; mid = 583;
iw.components.push_back (Component(Component::EXPERIENCE, 0, val, 0)); iw.components.push_back(Component(Component::EXPERIENCE, 0, val, 0));
break; break;
}
break; case BuildingSubID::DEFENSE_VISITING_BONUS: //cage of warlords
case BuildingID::SPECIAL_1: what = PrimarySkill::DEFENSE;
switch(town->subID) val = 1;
{ mid = 585;
case ETownType::FORTRESS: //cage of warlords iw.components.push_back(Component(Component::PRIM_SKILL, 1, 1, 0));
what = PrimarySkill::DEFENSE; break;
val = 1;
mid = 585;
iw.components.push_back (Component(Component::PRIM_SKILL, 1, 1, 0));
break;
}
break;
} }
assert(mid); assert(mid);
iw.player = cb->getOwner(heroID); iw.player = cb->getOwner(heroID);
iw.text << VLC->generaltexth->allTexts[mid]; iw.text << VLC->generaltexth->allTexts[mid];
cb->showInfoDialog(&iw); cb->showInfoDialog(&iw);
cb->changePrimSkill (cb->getHero(heroID), what, val); cb->changePrimSkill(cb->getHero(heroID), what, val);
town->addHeroToStructureVisitors(h, indexOnTV); town->addHeroToStructureVisitors(h, indexOnTV);
} }
} }

View File

@ -158,7 +158,7 @@ public:
void setProperty(ui8 what, ui32 val) override; void setProperty(ui8 what, ui32 val) override;
void onHeroVisit (const CGHeroInstance * h) const override; void onHeroVisit (const CGHeroInstance * h) const override;
CTownBonus (BuildingID index, CGTownInstance *TOWN); CTownBonus (BuildingID index, BuildingSubID::EBuildingSubID subId, CGTownInstance *TOWN);
CTownBonus () {}; CTownBonus () {};
template <typename Handler> void serialize(Handler &h, const int version) template <typename Handler> void serialize(Handler &h, const int version)
@ -262,6 +262,7 @@ public:
void deserializationFix(); void deserializationFix();
void recreateBuildingsBonuses(); void recreateBuildingsBonuses();
///bid: param to bind a building with a bonus, subId: param to check if already built ///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(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, 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 bool addBonusIfBuilt(BuildingID building, Bonus::BonusType type, int val, int subtype = -1); //convienence version of above
@ -342,5 +343,7 @@ private:
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 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;
bool tryAddOnePerWeekBonus(BuildingSubID::EBuildingSubID subID); void tryAddOnePerWeekBonus(BuildingSubID::EBuildingSubID subID);
void tryAddVisitingBonus(BuildingSubID::EBuildingSubID subID);
void addTownBonuses();
}; };

View File

@ -1812,7 +1812,7 @@ void CGameHandler::newTurn()
setPortalDwelling(t, true, (n.specialWeek == NewTurn::PLAGUE ? true : false)); //set creatures for Portal of Summoning setPortalDwelling(t, true, (n.specialWeek == NewTurn::PLAGUE ? true : false)); //set creatures for Portal of Summoning
if (!firstTurn) if (!firstTurn)
if (t->hasBuilt(BuildingID::TREASURY, ETownType::RAMPART) && player < PlayerColor::PLAYER_LIMIT) if (t->hasBuilt(BuildingSubID::TREASURY) && player < PlayerColor::PLAYER_LIMIT)
n.res[player][Res::GOLD] += hadGold.at(player)/10; //give 10% of starting gold n.res[player][Res::GOLD] += hadGold.at(player)/10; //give 10% of starting gold
if (!vstd::contains(n.cres, t->id)) if (!vstd::contains(n.cres, t->id))
@ -3848,8 +3848,18 @@ bool CGameHandler::queryReply(QueryID qid, const JsonNode & answer, PlayerColor
logGlobal->trace(answer.toJson()); logGlobal->trace(answer.toJson());
auto topQuery = queries.topQuery(player); auto topQuery = queries.topQuery(player);
COMPLAIN_RET_FALSE_IF(!topQuery, "This player doesn't have any queries!"); COMPLAIN_RET_FALSE_IF(!topQuery, "This player doesn't have any queries!");
COMPLAIN_RET_FALSE_IF(topQuery->queryID != qid, "This player top query has different ID!");
if(topQuery->queryID != qid)
{
auto currentQuery = queries.getQuery(qid);
if(currentQuery != nullptr && currentQuery->endsByPlayerAnswer())
currentQuery->setReply(answer);
COMPLAIN_RET("This player top query has different ID!"); //topQuery->queryID != qid
}
COMPLAIN_RET_FALSE_IF(!topQuery->endsByPlayerAnswer(), "This query cannot be ended by player's answer!"); COMPLAIN_RET_FALSE_IF(!topQuery->endsByPlayerAnswer(), "This query cannot be ended by player's answer!");
topQuery->setReply(answer); topQuery->setReply(answer);

View File

@ -248,10 +248,10 @@ std::vector<std::shared_ptr<const CQuery>> Queries::allQueries() const
return ret; return ret;
} }
std::vector<std::shared_ptr<CQuery>> Queries::allQueries() std::vector<QueryPtr> Queries::allQueries()
{ {
//TODO code duplication with const function :( //TODO code duplication with const function :(
std::vector<std::shared_ptr<CQuery>> ret; std::vector<QueryPtr> ret;
for(auto & playerQueries : queries) for(auto & playerQueries : queries)
for(auto & query : playerQueries.second) for(auto & query : playerQueries.second)
ret.push_back(query); ret.push_back(query);
@ -259,6 +259,15 @@ std::vector<std::shared_ptr<CQuery>> Queries::allQueries()
return ret; return ret;
} }
QueryPtr Queries::getQuery(QueryID queryID)
{
for(auto & playerQueries : queries)
for(auto & query : playerQueries.second)
if(query->queryID == queryID)
return query;
return nullptr;
}
void CBattleQuery::notifyObjectAboutRemoval(const CObjectVisitQuery & objectVisit) const void CBattleQuery::notifyObjectAboutRemoval(const CObjectVisitQuery & objectVisit) const
{ {
assert(result); assert(result);

View File

@ -219,7 +219,7 @@ public:
QueryPtr topQuery(PlayerColor player); QueryPtr topQuery(PlayerColor player);
std::vector<std::shared_ptr<const CQuery>> allQueries() const; std::vector<std::shared_ptr<const CQuery>> allQueries() const;
std::vector<std::shared_ptr<CQuery>> allQueries(); std::vector<QueryPtr> allQueries();
QueryPtr getQuery(QueryID queryID);
//void removeQuery //void removeQuery
}; };