mirror of
https://github.com/vcmi/vcmi.git
synced 2025-01-26 03:52:01 +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:
parent
dca8e9fa6f
commit
1c7aad6a50
@ -2356,18 +2356,27 @@ bool CGameHandler::disbandCreature( ObjectInstanceID id, SlotID pos )
|
||||
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);
|
||||
CBuilding * b = t->town->buildings[bid];
|
||||
const CGTownInstance * t = getTown(tid);
|
||||
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)
|
||||
{
|
||||
switch (b->mode)
|
||||
switch (requestedBuilding->mode)
|
||||
{
|
||||
case CBuilding::BUILD_NORMAL :
|
||||
case CBuilding::BUILD_AUTO :
|
||||
if (gs->canBuildStructure(t,bid) != EBuildingState::ALLOWED)
|
||||
if (gs->canBuildStructure(t, requestedID) != EBuildingState::ALLOWED)
|
||||
COMPLAIN_RET("Cannot build that building!");
|
||||
break;
|
||||
|
||||
@ -2376,68 +2385,105 @@ bool CGameHandler::buildStructure( ObjectInstanceID tid, BuildingID bid, bool fo
|
||||
break;
|
||||
|
||||
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!")
|
||||
else
|
||||
removeArtifact(ArtifactLocation(t->visitingHero, t->visitingHero->getArtPos(2, false)));
|
||||
removeArtifact(ArtifactLocation(t->visitingHero, t->visitingHero->getArtPos(ArtifactID::GRAIL, false)));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
NewStructures ns;
|
||||
ns.tid = tid;
|
||||
|
||||
if(bid >= BuildingID::DWELL_FIRST) //dwelling
|
||||
//Performs stuff that has to be done after new building is built
|
||||
auto processBuiltStructure = [t, this](const BuildingID buildingID)
|
||||
{
|
||||
int level = (bid - BuildingID::DWELL_FIRST) % GameConstants::CREATURES_PER_TOWN;
|
||||
int upgradeNumber = (bid - BuildingID::DWELL_FIRST) / GameConstants::CREATURES_PER_TOWN;
|
||||
if(buildingID >= BuildingID::DWELL_FIRST) //dwelling
|
||||
{
|
||||
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())
|
||||
COMPLAIN_RET("Cannot build dwelling: no creature found!");
|
||||
if (upgradeNumber >= t->town->creatures[level].size())
|
||||
{
|
||||
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;
|
||||
ssi.tid = tid;
|
||||
ssi.creatures = t->creatures;
|
||||
if (bid <= BuildingID::DWELL_LAST)
|
||||
ssi.creatures[level].first = crea->growth;
|
||||
ssi.creatures[level].second.push_back(crea->idNumber);
|
||||
sendAndApply(&ssi);
|
||||
}
|
||||
else if ( t->subID == ETownType::DUNGEON && bid == BuildingID::PORTAL_OF_SUMMON )
|
||||
SetAvailableCreatures ssi;
|
||||
ssi.tid = t->id;
|
||||
ssi.creatures = t->creatures;
|
||||
if (buildingID <= BuildingID::DWELL_LAST)
|
||||
ssi.creatures[level].first = crea->growth;
|
||||
ssi.creatures[level].second.push_back(crea->idNumber);
|
||||
sendAndApply(&ssi);
|
||||
}
|
||||
else if ( t->subID == ETownType::DUNGEON && buildingID == BuildingID::PORTAL_OF_SUMMON )
|
||||
{
|
||||
setPortalDwelling(t);
|
||||
}
|
||||
|
||||
if(buildingID <= BuildingID::MAGES_GUILD_5) //it's mage guild
|
||||
{
|
||||
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)
|
||||
{
|
||||
setPortalDwelling(t);
|
||||
}
|
||||
BOOST_FOREACH(auto requirementID, b->requirements)
|
||||
if(!vstd::contains(buildingsThatWillBe, t->town->buildings[requirementID]))
|
||||
return false;
|
||||
|
||||
ns.bid.insert(bid);
|
||||
ns.builded = force?t->builded:(t->builded+1);
|
||||
return true;
|
||||
};
|
||||
|
||||
|
||||
|
||||
//Init the vectors
|
||||
BOOST_FOREACH(auto & build, t->town->buildings)
|
||||
{
|
||||
if (build.second->mode == CBuilding::BUILD_AUTO
|
||||
&& !vstd::contains(t->builtBuildings, build.second->bid))
|
||||
if(t->hasBuilt(build.first))
|
||||
buildingsThatWillBe.push_back(build.second);
|
||||
else if(build.second->mode == CBuilding::BUILD_AUTO) //not built auto building
|
||||
remainingAutoBuildings.push_back(build.second);
|
||||
}
|
||||
|
||||
//Prepare structure (list of building ids will be filled later)
|
||||
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)
|
||||
{
|
||||
bool canBuild = true;
|
||||
BOOST_FOREACH(int requires, build.second->requirements)
|
||||
{
|
||||
if (!vstd::contains(t->builtBuildings, requires)
|
||||
&& !vstd::contains(ns.bid, requires))
|
||||
{
|
||||
canBuild = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (canBuild)
|
||||
ns.bid.insert(build.second->bid);
|
||||
if(allRequirementsFullfilled(autoBuilding))
|
||||
buildingsToAdd.push(autoBuilding);
|
||||
}
|
||||
}
|
||||
|
||||
//We know what has been built, appluy changes
|
||||
sendAndApply(&ns);
|
||||
|
||||
|
||||
//reveal ground for lookout tower
|
||||
FoWChange fw;
|
||||
fw.player = t->tempOwner;
|
||||
@ -2445,21 +2491,20 @@ bool CGameHandler::buildStructure( ObjectInstanceID tid, BuildingID bid, bool fo
|
||||
t->getSightTiles(fw.tiles);
|
||||
sendAndApply(&fw);
|
||||
|
||||
//Other post-built events
|
||||
BOOST_FOREACH(auto builtID, ns.bid)
|
||||
processBuiltStructure(builtID);
|
||||
|
||||
//Take cost
|
||||
if (!force)
|
||||
{
|
||||
SetResources sr;
|
||||
sr.player = t->tempOwner;
|
||||
sr.res = gs->getPlayer(t->tempOwner)->resources - b->resources;
|
||||
sr.res = gs->getPlayer(t->tempOwner)->resources - requestedBuilding->resources;
|
||||
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)
|
||||
vistiCastleObjects (t, t->visitingHero);
|
||||
if(t->garrisonHero)
|
||||
|
Loading…
x
Reference in New Issue
Block a user