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

Special buildings support : Patch 1

This commit is contained in:
Dmitry Orlov 2020-10-15 15:03:01 +03:00
parent 12a4cee092
commit 934c4e511d
8 changed files with 116 additions and 91 deletions

View File

@ -115,7 +115,7 @@ void CBuildingRect::clickLeft(tribool down, bool previousState)
if (!CSDL_Ext::isTransparent(area, GH.current->motion.x - pos.x, GH.current->motion.y - pos.y)) //inside building image if (!CSDL_Ext::isTransparent(area, GH.current->motion.x - pos.x, GH.current->motion.y - pos.y)) //inside building image
{ {
auto building = getBuilding(); auto building = getBuilding();
parent->buildingClicked(building->bid, building->subId); parent->buildingClicked(building->bid, building->subId, building->upgrade);
} }
} }
@ -653,7 +653,7 @@ const CGHeroInstance * CCastleBuildings::getHero()
return town->garrisonHero; return town->garrisonHero;
} }
void CCastleBuildings::buildingClicked(BuildingID building, BuildingSubID::EBuildingSubID subID) void CCastleBuildings::buildingClicked(BuildingID building, BuildingSubID::EBuildingSubID subID, BuildingID::EBuildingID upgrades)
{ {
logGlobal->trace("You've clicked on %d", (int)building.toEnum()); logGlobal->trace("You've clicked on %d", (int)building.toEnum());
const CBuilding *b = town->town->buildings.find(building)->second; const CBuilding *b = town->town->buildings.find(building)->second;
@ -719,7 +719,7 @@ void CCastleBuildings::buildingClicked(BuildingID building, BuildingSubID::EBuil
break; break;
case BuildingSubID::MYSTIC_POND: case BuildingSubID::MYSTIC_POND:
enterFountain(building); enterFountain(building, subID, upgrades);
break; break;
case BuildingSubID::ARTIFACT_MERCHANT: case BuildingSubID::ARTIFACT_MERCHANT:
@ -730,7 +730,7 @@ void CCastleBuildings::buildingClicked(BuildingID building, BuildingSubID::EBuil
break; break;
case BuildingSubID::FOUNTAIN_OF_FORTUNE: case BuildingSubID::FOUNTAIN_OF_FORTUNE:
enterFountain(building); enterFountain(building, subID, upgrades);
break; break;
case BuildingSubID::FREELANCERS_GUILD: case BuildingSubID::FREELANCERS_GUILD:
@ -748,7 +748,10 @@ void CCastleBuildings::buildingClicked(BuildingID building, BuildingSubID::EBuil
break; break;
case BuildingSubID::BROTHERHOOD_OF_SWORD: case BuildingSubID::BROTHERHOOD_OF_SWORD:
LOCPLINT->showTavernWindow(town); if(upgrades == BuildingID::TAVERN)
LOCPLINT->showTavernWindow(town);
else
enterBuilding(building);
break; break;
case BuildingSubID::CASTLE_GATE: case BuildingSubID::CASTLE_GATE:
@ -839,22 +842,28 @@ void CCastleBuildings::enterToTheQuickRecruitmentWindow()
GH.pushIntT<QuickRecruitmentWindow>(town, pos); GH.pushIntT<QuickRecruitmentWindow>(town, pos);
} }
void CCastleBuildings::enterFountain(BuildingID building) void CCastleBuildings::enterFountain(const BuildingID & building, BuildingSubID::EBuildingSubID subID, BuildingID::EBuildingID upgrades)
{ {
std::vector<std::shared_ptr<CComponent>> comps(1, std::make_shared<CComponent>(CComponent::building,town->subID,building)); std::vector<std::shared_ptr<CComponent>> comps(1, std::make_shared<CComponent>(CComponent::building,town->subID, building));
std::string descr = town->town->buildings.find(building)->second->Description(); std::string descr = town->town->buildings.find(building)->second->Description();
if ( building == BuildingID::FOUNTAIN_OF_FORTUNE) bool isMysticPondOrItsUpgrade = subID == BuildingSubID::MYSTIC_POND
descr += "\n\n"+town->town->buildings.find(BuildingID::MYSTIC_POND)->second->Description(); || (upgrades != BuildingID::NONE
&& town->town->buildings.find(BuildingID(upgrades))->second->subId == BuildingSubID::MYSTIC_POND);
if (town->bonusValue.first == 0)//fountain was builded this week if(upgrades != BuildingID::NONE)
descr += "\n\n"+ CGI->generaltexth->allTexts[677]; descr += "\n\n"+town->town->buildings.find(BuildingID(upgrades))->second->Description();
else//fountain produced something;
if(isMysticPondOrItsUpgrade) //for vanila Rampart like towns
{ {
descr+= "\n\n"+ CGI->generaltexth->allTexts[678]; if(town->bonusValue.first == 0) //Mystic Pond produced nothing;
boost::algorithm::replace_first(descr,"%s",CGI->generaltexth->restypes[town->bonusValue.first]); descr += "\n\n" + CGI->generaltexth->allTexts[677];
boost::algorithm::replace_first(descr,"%d",boost::lexical_cast<std::string>(town->bonusValue.second)); else //Mystic Pond produced something;
{
descr += "\n\n" + CGI->generaltexth->allTexts[678];
boost::algorithm::replace_first(descr, "%s", CGI->generaltexth->restypes[town->bonusValue.first]);
boost::algorithm::replace_first(descr, "%d", boost::lexical_cast<std::string>(town->bonusValue.second));
}
} }
LOCPLINT->showInfoDialog(descr, comps); LOCPLINT->showInfoDialog(descr, comps);
} }
@ -1627,7 +1636,7 @@ const CBuilding * CFortScreen::RecruitArea::getMyBuilding()
BuildingID myID = BuildingID(BuildingID::DWELL_FIRST).advance(level); BuildingID myID = BuildingID(BuildingID::DWELL_FIRST).advance(level);
if (level == GameConstants::CREATURES_PER_TOWN) if (level == GameConstants::CREATURES_PER_TOWN)
return town->town->buildings.at(BuildingID::PORTAL_OF_SUMMON); return town->town->getSpecialBuilding(BuildingSubID::PORTAL_OF_SUMMONING);
if (!town->town->buildings.count(myID)) if (!town->town->buildings.count(myID))
return nullptr; return nullptr;

View File

@ -136,7 +136,7 @@ class CCastleBuildings : public CIntObject
void enterBlacksmith(ArtifactID artifactID);//support for blacksmith + ballista yard void enterBlacksmith(ArtifactID artifactID);//support for blacksmith + ballista yard
void enterBuilding(BuildingID building);//for buildings with simple description + pic left-click messages void enterBuilding(BuildingID building);//for buildings with simple description + pic left-click messages
void enterCastleGate(); void enterCastleGate();
void enterFountain(BuildingID building);//Rampart's fountains void enterFountain(const BuildingID & building, BuildingSubID::EBuildingSubID subID, BuildingID::EBuildingID upgrades);//Rampart's fountains
void enterMagesGuild(); void enterMagesGuild();
void enterTownHall(); void enterTownHall();
@ -153,7 +153,7 @@ public:
void enterDwelling(int level); void enterDwelling(int level);
void enterToTheQuickRecruitmentWindow(); void enterToTheQuickRecruitmentWindow();
void buildingClicked(BuildingID building, BuildingSubID::EBuildingSubID subID = BuildingSubID::NONE); void buildingClicked(BuildingID building, BuildingSubID::EBuildingSubID subID = BuildingSubID::NONE, BuildingID::EBuildingID upgrades = BuildingID::NONE);
void addBuilding(BuildingID building); void addBuilding(BuildingID building);
void removeBuilding(BuildingID building);//FIXME: not tested!!! void removeBuilding(BuildingID building);//FIXME: not tested!!!
}; };

View File

@ -177,7 +177,7 @@
"special1": { "type" : "mysticPond" }, "special1": { "type" : "mysticPond" },
"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", "requires" : [ "special1" ] }, "special2": { "type" : "fountainOfFortune", "upgrades" : "special1" },
"special3": { "requires" : [ "horde1" ] }, "special3": { "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" },

View File

@ -201,6 +201,21 @@ std::set<si32> CTown::getAllBuildings() const
return res; return res;
} }
const CBuilding * CTown::getSpecialBuilding(BuildingSubID::EBuildingSubID subID) const
{
for(const auto & kvp : buildings)
{
if(kvp.second->subId == subID)
return buildings.at(kvp.first);
}
return nullptr;
}
BuildingID::EBuildingID CTown::getBuildingType(BuildingSubID::EBuildingSubID subID) const
{
auto building = getSpecialBuilding(subID);
return building == nullptr ? BuildingID::NONE : building->bid.num;
}
CTownHandler::CTownHandler() CTownHandler::CTownHandler()
{ {

View File

@ -78,6 +78,13 @@ public:
// returns how many times build has to be upgraded to become build // returns how many times build has to be upgraded to become build
si32 getDistance(BuildingID build) const; si32 getDistance(BuildingID build) const;
STRONG_INLINE
bool IsTradeBuilding() const
{
return bid == BuildingID::MARKETPLACE || subId == BuildingSubID::ARTIFACT_MERCHANT || subId == BuildingSubID::FREELANCERS_GUILD;
}
/// 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);
@ -204,6 +211,8 @@ public:
std::string getFactionName() const; std::string getFactionName() const;
std::string getBuildingScope() const; std::string getBuildingScope() const;
std::set<si32> getAllBuildings() const; std::set<si32> getAllBuildings() const;
const CBuilding * getSpecialBuilding(BuildingSubID::EBuildingSubID subID) const;
BuildingID::EBuildingID getBuildingType(BuildingSubID::EBuildingSubID subID) const;
CFaction * faction; CFaction * faction;

View File

@ -739,23 +739,29 @@ std::string CGTownInstance::getObjectName() const
return name + ", " + town->faction->name; return name + ", " + town->faction->name;
} }
bool CGTownInstance::townEnvisagesSpecialBuilding(BuildingSubID::EBuildingSubID bid) const bool CGTownInstance::townEnvisagesBuilding(BuildingSubID::EBuildingSubID subId) const
{ {
for(const auto & it : town->buildings) return town->getBuildingType(subId) != BuildingID::NONE;
{
if(it.second->subId == bid)
return true;
}
return false;
} }
void CGTownInstance::initObj(CRandomGenerator & rand) //it does not check hasBuilt(...) because this check is in the OnHeroVisit handler
///initialize town structures bool CGTownInstance::tryAddOnePerWeekBonus(BuildingSubID::EBuildingSubID subID)
{
auto bid = town->getBuildingType(subID);
if(bid == BuildingID::NONE)
return false;
bonusingBuildings.push_back(new COPWBonus(bid, subID, this));
return true;
}
void CGTownInstance::initObj(CRandomGenerator & rand) ///initialize town structures
{ {
blockVisit = true; blockVisit = true;
if(townEnvisagesSpecialBuilding(BuildingSubID::PORTAL_OF_SUMMONING)) //Dungeon for example if(townEnvisagesBuilding(BuildingSubID::PORTAL_OF_SUMMONING)) //Dungeon for example
creatures.resize(GameConstants::CREATURES_PER_TOWN+1); creatures.resize(GameConstants::CREATURES_PER_TOWN + 1);
else else
creatures.resize(GameConstants::CREATURES_PER_TOWN); creatures.resize(GameConstants::CREATURES_PER_TOWN);
@ -770,11 +776,8 @@ void CGTownInstance::initObj(CRandomGenerator & rand)
creatures[level].second.push_back(town->creatures[level][upgradeNum]); creatures[level].second.push_back(town->creatures[level][upgradeNum]);
} }
} }
if(townEnvisagesSpecialBuilding(BuildingSubID::STABLES)) tryAddOnePerWeekBonus(BuildingSubID::STABLES);
bonusingBuildings.push_back(new COPWBonus(BuildingID::STABLES, BuildingSubID::STABLES, this)); tryAddOnePerWeekBonus(BuildingSubID::MANA_VORTEX);
if(townEnvisagesSpecialBuilding(BuildingSubID::MANA_VORTEX))
bonusingBuildings.push_back(new COPWBonus(BuildingID::MANA_VORTEX, BuildingSubID::MANA_VORTEX, this));
switch (subID) switch (subID)
{ {
@ -824,45 +827,22 @@ void CGTownInstance::updateBonusingBuildings()
switch (building->subId) switch (building->subId)
{ {
case BuildingSubID::PORTAL_OF_SUMMONING: case BuildingSubID::PORTAL_OF_SUMMONING:
creatures.resize(GameConstants::CREATURES_PER_TOWN + 1); if(!hasBuiltInOldWay(ETownType::DUNGEON, BuildingID::PORTAL_OF_SUMMON))
creatures.resize(GameConstants::CREATURES_PER_TOWN + 1);
break; break;
///'hasBuilt' checking for COPW bonuses is in the COPWBonus::onHeroVisit ///'hasBuilt' checking for COPW bonuses is in the COPWBonus::onHeroVisit
case BuildingSubID::STABLES: case BuildingSubID::STABLES:
if(getBonusingBuilding(building->subId) == nullptr) if(getBonusingBuilding(building->subId) == nullptr)
bonusingBuildings.push_back(new COPWBonus(BuildingID::STABLES, BuildingSubID::STABLES, this)); tryAddOnePerWeekBonus(BuildingSubID::STABLES);
break; break;
case BuildingSubID::MANA_VORTEX: case BuildingSubID::MANA_VORTEX:
if(getBonusingBuilding(building->subId) == nullptr) if(getBonusingBuilding(building->subId) == nullptr)
bonusingBuildings.push_back(new COPWBonus(BuildingID::MANA_VORTEX, BuildingSubID::MANA_VORTEX, this)); tryAddOnePerWeekBonus(BuildingSubID::MANA_VORTEX);
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; break;
} }
} }
recreateBuildingsBonuses(); ///Clear all bonuses and recreate
} }
bool CGTownInstance::hasBuiltInOldWay(ETownType::ETownType type, BuildingID bid) const bool CGTownInstance::hasBuiltInOldWay(ETownType::ETownType type, BuildingID bid) const
@ -1071,7 +1051,7 @@ int CGTownInstance::getBoatType() const
int CGTownInstance::getMarketEfficiency() const int CGTownInstance::getMarketEfficiency() const
{ {
if (!hasBuilt(BuildingID::MARKETPLACE)) if(!hasBuiltSomeTradeBuilding())
return 0; return 0;
const PlayerState *p = cb->getPlayer(tempOwner); const PlayerState *p = cb->getPlayer(tempOwner);
@ -1079,7 +1059,7 @@ int CGTownInstance::getMarketEfficiency() const
int marketCount = 0; int marketCount = 0;
for(const CGTownInstance *t : p->towns) for(const CGTownInstance *t : p->towns)
if(t->hasBuilt(BuildingID::MARKETPLACE)) if(t->hasBuiltSomeTradeBuilding())
marketCount++; marketCount++;
return marketCount; return marketCount;
@ -1095,18 +1075,16 @@ bool CGTownInstance::allowsTrade(EMarketMode::EMarketMode mode) const
case EMarketMode::ARTIFACT_RESOURCE: case EMarketMode::ARTIFACT_RESOURCE:
case EMarketMode::RESOURCE_ARTIFACT: case EMarketMode::RESOURCE_ARTIFACT:
return hasBuilt(BuildingID::ARTIFACT_MERCHANT, ETownType::TOWER) return hasBuilt(BuildingSubID::ARTIFACT_MERCHANT);
|| hasBuilt(BuildingID::ARTIFACT_MERCHANT, ETownType::DUNGEON)
|| hasBuilt(BuildingID::ARTIFACT_MERCHANT, ETownType::CONFLUX);
case EMarketMode::CREATURE_RESOURCE: case EMarketMode::CREATURE_RESOURCE:
return hasBuilt(BuildingID::FREELANCERS_GUILD, ETownType::STRONGHOLD); return hasBuilt(BuildingSubID::FREELANCERS_GUILD);
case EMarketMode::CREATURE_UNDEAD: case EMarketMode::CREATURE_UNDEAD:
return hasBuilt(BuildingID::SKELETON_TRANSFORMER, ETownType::NECROPOLIS); return hasBuilt(BuildingSubID::CREATURE_TRANSFORMER);
case EMarketMode::RESOURCE_SKILL: case EMarketMode::RESOURCE_SKILL:
return hasBuilt(BuildingID::MAGIC_UNIVERSITY, ETownType::CONFLUX); return hasBuilt(BuildingSubID::MAGIC_UNIVERSITY);
default: default:
assert(0); assert(0);
return false; return false;
@ -1195,13 +1173,13 @@ void CGTownInstance::recreateBuildingsBonuses()
removeBonus(b); removeBonus(b);
//tricky! -> checks tavern only if no bratherhood of sword or not a castle //tricky! -> checks tavern only if no bratherhood of sword or not a castle
if(!addBonusIfBuilt(BuildingID::BROTHERHOOD, BuildingSubID::BROTHERHOOD_OF_SWORD, Bonus::MORALE, +2)) if(!addBonusIfBuilt(BuildingSubID::BROTHERHOOD_OF_SWORD, Bonus::MORALE, +2))
addBonusIfBuilt(BuildingID::TAVERN, Bonus::MORALE, +1); addBonusIfBuilt(BuildingID::TAVERN, Bonus::MORALE, +1);
addBonusIfBuilt(BuildingID::FOUNTAIN_OF_FORTUNE, BuildingSubID::FOUNTAIN_OF_FORTUNE, Bonus::LUCK, +2); //fountain of fortune addBonusIfBuilt(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(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(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 addBonusIfBuilt(BuildingSubID::DEFENSE_GARRISON_BONUS, Bonus::PRIMARY_SKILL, +2, PrimarySkill::DEFENSE);//works as Glyphs of Fear
if(subID == ETownType::CASTLE) //castle if(subID == ETownType::CASTLE) //castle
{ {
@ -1237,23 +1215,22 @@ void CGTownInstance::recreateBuildingsBonuses()
} }
} }
bool CGTownInstance::addBonusIfBuilt(BuildingID bid, BuildingSubID::EBuildingSubID subId, Bonus::BonusType type, int val, int subtype) bool CGTownInstance::addBonusIfBuilt(BuildingSubID::EBuildingSubID subId, Bonus::BonusType type, int val, int subtype)
{ {
bool hasBuilt = false; 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();
hasBuilt = true; currentBid = bid;
break; break;
} }
} }
if(hasBuilt) return currentBid == BuildingID::NONE ? false
hasBuilt = addBonusImpl(bid, type, val, emptyPropagator, descr.str(), subtype); : addBonusImpl(currentBid, type, val, emptyPropagator, descr.str(), subtype);
return hasBuilt;
} }
bool CGTownInstance::addBonusIfBuilt(BuildingID building, Bonus::BonusType type, int val, int subtype) bool CGTownInstance::addBonusIfBuilt(BuildingID building, Bonus::BonusType type, int val, int subtype)
@ -1390,6 +1367,17 @@ const CGTownBuilding * CGTownInstance::getBonusingBuilding(BuildingSubID::EBuild
return nullptr; return nullptr;
} }
bool CGTownInstance::hasBuiltSomeTradeBuilding() const
{
for (const auto & bid : builtBuildings)
{
if(town->buildings.at(bid)->IsTradeBuilding())
return true;
}
return false;
}
bool CGTownInstance::hasBuilt(BuildingSubID::EBuildingSubID buildingID) const bool CGTownInstance::hasBuilt(BuildingSubID::EBuildingSubID buildingID) const
{ {
for(const auto & bid : builtBuildings) for(const auto & bid : builtBuildings)

View File

@ -262,7 +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(BuildingID bid, 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
void setVisitingHero(CGHeroInstance *h); void setVisitingHero(CGHeroInstance *h);
@ -295,6 +295,7 @@ public:
bool hasFort() const; bool hasFort() const;
bool hasCapitol() const; bool hasCapitol() const;
const CGTownBuilding * getBonusingBuilding(BuildingSubID::EBuildingSubID subId) const; const CGTownBuilding * getBonusingBuilding(BuildingSubID::EBuildingSubID subId) const;
bool hasBuiltSomeTradeBuilding() const;
//checks if special building with type buildingID is constructed //checks if special building with type buildingID is constructed
bool hasBuilt(BuildingSubID::EBuildingSubID buildingID) const; bool hasBuilt(BuildingSubID::EBuildingSubID buildingID) const;
//checks if building is constructed and town has same subID //checks if building is constructed and town has same subID
@ -313,7 +314,6 @@ 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
bool townEnvisagesSpecialBuilding(BuildingSubID::EBuildingSubID bid) const;
const CTown * getTown() const ; const CTown * getTown() const ;
@ -330,13 +330,17 @@ public:
void afterAddToMap(CMap * map) override; void afterAddToMap(CMap * map) override;
static void reset(); static void reset();
protected: protected:
static TPropagatorPtr emptyPropagator; 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;
private: 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 addBonusImpl(BuildingID building, Bonus::BonusType type, int val, TPropagatorPtr & prop, const std::string & description, int subtype = -1);
bool townEnvisagesBuilding(BuildingSubID::EBuildingSubID bid) const;
bool tryAddOnePerWeekBonus(BuildingSubID::EBuildingSubID subID);
}; };

View File

@ -1808,7 +1808,7 @@ void CGameHandler::newTurn()
handleTownEvents(t, n); handleTownEvents(t, n);
if (newWeek) //first day of week if (newWeek) //first day of week
{ {
if (t->hasBuilt(BuildingID::PORTAL_OF_SUMMON, ETownType::DUNGEON)) if (t->hasBuilt(BuildingSubID::PORTAL_OF_SUMMONING))
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)
@ -2391,7 +2391,7 @@ void CGameHandler::setOwner(const CGObjectInstance * obj, PlayerColor owner)
{ {
if (owner < PlayerColor::PLAYER_LIMIT) //new owner is real player if (owner < PlayerColor::PLAYER_LIMIT) //new owner is real player
{ {
if (town->hasBuilt(BuildingID::PORTAL_OF_SUMMON, ETownType::DUNGEON)) if (town->hasBuilt(BuildingSubID::PORTAL_OF_SUMMONING))
setPortalDwelling(town, true, false); setPortalDwelling(town, true, false);
} }
@ -2414,7 +2414,7 @@ void CGameHandler::setOwner(const CGObjectInstance * obj, PlayerColor owner)
{ {
for (const CGTownInstance * t : getPlayer(owner)->towns) for (const CGTownInstance * t : getPlayer(owner)->towns)
{ {
if (t->hasBuilt(BuildingID::PORTAL_OF_SUMMON, ETownType::DUNGEON)) if (t->hasBuilt(BuildingSubID::PORTAL_OF_SUMMONING))
setPortalDwelling(t);//set initial creatures for all portals of summoning setPortalDwelling(t);//set initial creatures for all portals of summoning
} }
} }
@ -3076,7 +3076,7 @@ bool CGameHandler::buildStructure(ObjectInstanceID tid, BuildingID requestedID,
ssi.creatures[level].second.push_back(crea->idNumber); ssi.creatures[level].second.push_back(crea->idNumber);
sendAndApply(&ssi); sendAndApply(&ssi);
} }
if (t->subID == ETownType::DUNGEON && buildingID == BuildingID::PORTAL_OF_SUMMON) if (t->town->buildings.at(buildingID)->subId == BuildingSubID::PORTAL_OF_SUMMONING)
{ {
setPortalDwelling(t); setPortalDwelling(t);
} }
@ -3541,7 +3541,7 @@ bool CGameHandler::buyArtifact(ObjectInstanceID hid, ArtifactID aid)
COMPLAIN_RET_FALSE_IF(getPlayer(hero->getOwner())->resources.at(Res::GOLD) < price, "Not enough gold!"); COMPLAIN_RET_FALSE_IF(getPlayer(hero->getOwner())->resources.at(Res::GOLD) < price, "Not enough gold!");
if ((town->hasBuilt(BuildingID::BLACKSMITH) && town->town->warMachine == aid) if ((town->hasBuilt(BuildingID::BLACKSMITH) && town->town->warMachine == aid)
|| ((town->hasBuilt(BuildingID::BALLISTA_YARD, ETownType::STRONGHOLD)) && aid == ArtifactID::BALLISTA)) || (town->hasBuilt(BuildingSubID::BALLISTA_YARD) && aid == ArtifactID::BALLISTA))
{ {
giveResource(hero->getOwner(),Res::GOLD,-price); giveResource(hero->getOwner(),Res::GOLD,-price);
return giveHeroNewArtifact(hero, art); return giveHeroNewArtifact(hero, art);