1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-11-27 22:49:25 +02:00

Improved handling buildings with mode "auto":

* they will properly processed (new creatures will be added if dwelling, spells learned if mage guild, and so)
* transitive dependencies are handled (A makes B build, and B makes C and D)
This commit is contained in:
Michał W. Urbańczyk
2013-05-22 15:16:36 +00:00
parent dca8e9fa6f
commit 1c7aad6a50

View File

@@ -2356,18 +2356,27 @@ bool CGameHandler::disbandCreature( ObjectInstanceID id, SlotID pos )
return true; return true;
} }
bool CGameHandler::buildStructure( ObjectInstanceID tid, BuildingID bid, bool force /*=false*/ ) bool CGameHandler::buildStructure( ObjectInstanceID tid, BuildingID requestedID, bool force /*=false*/ )
{ {
CGTownInstance * t = gs->getTown(tid); const CGTownInstance * t = getTown(tid);
CBuilding * b = t->town->buildings[bid]; if(!t)
COMPLAIN_RETF("No such town (ID=%s)!", tid);
if(!t->town->buildings.count(requestedID))
COMPLAIN_RETF("Town of faction %s does not have info about building ID=%s!", t->town->faction->name % tid);
const CBuilding * requestedBuilding = t->town->buildings[requestedID];
//Vector with future list of built building and buildings in auto-mode that are not yet built.
std::vector<const CBuilding*> buildingsThatWillBe, remainingAutoBuildings;
//Check validity of request
if(!force) if(!force)
{ {
switch (b->mode) switch (requestedBuilding->mode)
{ {
case CBuilding::BUILD_NORMAL : case CBuilding::BUILD_NORMAL :
case CBuilding::BUILD_AUTO : case CBuilding::BUILD_AUTO :
if (gs->canBuildStructure(t,bid) != EBuildingState::ALLOWED) if (gs->canBuildStructure(t, requestedID) != EBuildingState::ALLOWED)
COMPLAIN_RET("Cannot build that building!"); COMPLAIN_RET("Cannot build that building!");
break; break;
@@ -2376,66 +2385,103 @@ bool CGameHandler::buildStructure( ObjectInstanceID tid, BuildingID bid, bool fo
break; break;
case CBuilding::BUILD_GRAIL : case CBuilding::BUILD_GRAIL :
if(b->mode == CBuilding::BUILD_GRAIL) //needs grail if(requestedBuilding->mode == CBuilding::BUILD_GRAIL) //needs grail
{ {
if(!t->visitingHero || !t->visitingHero->hasArt(2)) if(!t->visitingHero || !t->visitingHero->hasArt(ArtifactID::GRAIL))
COMPLAIN_RET("Cannot build this without grail!") COMPLAIN_RET("Cannot build this without grail!")
else else
removeArtifact(ArtifactLocation(t->visitingHero, t->visitingHero->getArtPos(2, false))); removeArtifact(ArtifactLocation(t->visitingHero, t->visitingHero->getArtPos(ArtifactID::GRAIL, false)));
} }
break; break;
} }
} }
NewStructures ns; //Performs stuff that has to be done after new building is built
ns.tid = tid; auto processBuiltStructure = [t, this](const BuildingID buildingID)
if(bid >= BuildingID::DWELL_FIRST) //dwelling
{ {
int level = (bid - BuildingID::DWELL_FIRST) % GameConstants::CREATURES_PER_TOWN; if(buildingID >= BuildingID::DWELL_FIRST) //dwelling
int upgradeNumber = (bid - BuildingID::DWELL_FIRST) / GameConstants::CREATURES_PER_TOWN; {
int level = (buildingID - BuildingID::DWELL_FIRST) % GameConstants::CREATURES_PER_TOWN;
int upgradeNumber = (buildingID - BuildingID::DWELL_FIRST) / GameConstants::CREATURES_PER_TOWN;
if (upgradeNumber >= t->town->creatures[level].size()) if (upgradeNumber >= t->town->creatures[level].size())
COMPLAIN_RET("Cannot build dwelling: no creature found!"); {
complain(boost::str(boost::format("Error ecountered when building dwelling (bid=%s):"
"no creature found (upgrade number %d, level %d!")
% buildingID % upgradeNumber % level));
return;
}
CCreature * crea = VLC->creh->creatures[t->town->creatures[level][upgradeNumber]]; CCreature * crea = VLC->creh->creatures[t->town->creatures[level][upgradeNumber]];
SetAvailableCreatures ssi; SetAvailableCreatures ssi;
ssi.tid = tid; ssi.tid = t->id;
ssi.creatures = t->creatures; ssi.creatures = t->creatures;
if (bid <= BuildingID::DWELL_LAST) if (buildingID <= BuildingID::DWELL_LAST)
ssi.creatures[level].first = crea->growth; ssi.creatures[level].first = crea->growth;
ssi.creatures[level].second.push_back(crea->idNumber); ssi.creatures[level].second.push_back(crea->idNumber);
sendAndApply(&ssi); sendAndApply(&ssi);
} }
else if ( t->subID == ETownType::DUNGEON && bid == BuildingID::PORTAL_OF_SUMMON ) else if ( t->subID == ETownType::DUNGEON && buildingID == BuildingID::PORTAL_OF_SUMMON )
{ {
setPortalDwelling(t); setPortalDwelling(t);
} }
ns.bid.insert(bid); if(buildingID <= BuildingID::MAGES_GUILD_5) //it's mage guild
ns.builded = force?t->builded:(t->builded+1); {
if(t->visitingHero)
giveSpells(t,t->visitingHero);
if(t->garrisonHero)
giveSpells(t,t->garrisonHero);
}
};
//Checks if all requirements will be met with expected building list "buildingsThatWillBe"
auto allRequirementsFullfilled = [&buildingsThatWillBe, t](const CBuilding *b)
{
BOOST_FOREACH(auto requirementID, b->requirements)
if(!vstd::contains(buildingsThatWillBe, t->town->buildings[requirementID]))
return false;
return true;
};
//Init the vectors
BOOST_FOREACH(auto & build, t->town->buildings) BOOST_FOREACH(auto & build, t->town->buildings)
{ {
if (build.second->mode == CBuilding::BUILD_AUTO if(t->hasBuilt(build.first))
&& !vstd::contains(t->builtBuildings, build.second->bid)) buildingsThatWillBe.push_back(build.second);
{ else if(build.second->mode == CBuilding::BUILD_AUTO) //not built auto building
bool canBuild = true; remainingAutoBuildings.push_back(build.second);
BOOST_FOREACH(int requires, build.second->requirements)
{
if (!vstd::contains(t->builtBuildings, requires)
&& !vstd::contains(ns.bid, requires))
{
canBuild = false;
break;
} }
}
if (canBuild) //Prepare structure (list of building ids will be filled later)
ns.bid.insert(build.second->bid); NewStructures ns;
ns.tid = tid;
ns.builded = force ? t->builded : (t->builded+1);
std::queue<const CBuilding*> buildingsToAdd;
buildingsToAdd.push(requestedBuilding);
while(buildingsToAdd.size())
{
auto b = buildingsToAdd.front();
buildingsToAdd.pop();
ns.bid.insert(b->bid);
buildingsThatWillBe.push_back(b);
remainingAutoBuildings -= b;
BOOST_FOREACH(auto autoBuilding, remainingAutoBuildings)
{
if(allRequirementsFullfilled(autoBuilding))
buildingsToAdd.push(autoBuilding);
} }
} }
//We know what has been built, appluy changes
sendAndApply(&ns); sendAndApply(&ns);
//reveal ground for lookout tower //reveal ground for lookout tower
@@ -2445,21 +2491,20 @@ bool CGameHandler::buildStructure( ObjectInstanceID tid, BuildingID bid, bool fo
t->getSightTiles(fw.tiles); t->getSightTiles(fw.tiles);
sendAndApply(&fw); sendAndApply(&fw);
//Other post-built events
BOOST_FOREACH(auto builtID, ns.bid)
processBuiltStructure(builtID);
//Take cost
if (!force) if (!force)
{ {
SetResources sr; SetResources sr;
sr.player = t->tempOwner; sr.player = t->tempOwner;
sr.res = gs->getPlayer(t->tempOwner)->resources - b->resources; sr.res = gs->getPlayer(t->tempOwner)->resources - requestedBuilding->resources;
sendAndApply(&sr); sendAndApply(&sr);
} }
if(bid<5) //it's mage guild
{
if(t->visitingHero)
giveSpells(t,t->visitingHero);
if(t->garrisonHero)
giveSpells(t,t->garrisonHero);
}
if(t->visitingHero) if(t->visitingHero)
vistiCastleObjects (t, t->visitingHero); vistiCastleObjects (t, t->visitingHero);
if(t->garrisonHero) if(t->garrisonHero)