diff --git a/lib/mapObjects/CGTownInstance.cpp b/lib/mapObjects/CGTownInstance.cpp index c8ed78dd2..5300f115c 100644 --- a/lib/mapObjects/CGTownInstance.cpp +++ b/lib/mapObjects/CGTownInstance.cpp @@ -535,8 +535,12 @@ void CGTownInstance::onHeroVisit(const CGHeroInstance * h) const bool outsideTown = (defendingHero == visitingHero && garrisonHero); - //TODO //"borrowing" army from garrison to visiting hero + if(!outsideTown && armedGarrison() && + visitingHero && defendingHero == visitingHero) + { + mergeGarrisonOnSiege(); + } cb->startBattlePrimary(h, defendingArmy, getSightCenter(), h, defendingHero, false, (outsideTown ? nullptr : this)); } @@ -725,6 +729,59 @@ void CGTownInstance::getOutOffsets( std::vector &offsets ) const offsets = {int3(-1,2,0), int3(-3,2,0)}; } +void CGTownInstance::mergeGarrisonOnSiege() const +{ + auto getWeakestStackSlot = [&](int powerLimit) + { + std::vector weakSlots; + auto stacksList = visitingHero->stacks; + std::pair pair; + while(stacksList.size()) + { + pair = *vstd::minElementByFun(stacksList, [&](std::pair elem) + { + return elem.second->getPower(); + }); + if(powerLimit > pair.second->getPower() && + (weakSlots.empty() || pair.second->getPower() == visitingHero->getStack(weakSlots.front()).getPower())) + { + weakSlots.push_back(pair.first); + stacksList.erase(pair.first); + } + else + break; + } + + if(weakSlots.size()) + return *std::max_element(weakSlots.begin(), weakSlots.end()); + + return SlotID(); + }; + + int count = stacks.size(); + for(int i = 0; i < count; i++) + { + auto pair = *vstd::maxElementByFun(stacks, [&](std::pair elem) + { + ui64 power = elem.second->getPower(); + auto dst = visitingHero->getSlotFor(elem.second->getCreatureID()); + if(dst.validSlot() && visitingHero->hasStackAtSlot(dst)) + power += visitingHero->getStack(dst).getPower(); + + return power; + }); + auto dst = visitingHero->getSlotFor(pair.second->getCreatureID()); + if(dst.validSlot()) + cb->moveStack(StackLocation(this, pair.first), StackLocation(visitingHero, dst), -1); + else + { + dst = getWeakestStackSlot(pair.second->getPower()); + if(dst.validSlot()) + cb->swapStacks(StackLocation(this, pair.first), StackLocation(visitingHero, dst)); + } + } +} + void CGTownInstance::removeCapitols (PlayerColor owner) const { if (hasCapitol()) // search if there's an older capitol diff --git a/lib/mapObjects/CGTownInstance.h b/lib/mapObjects/CGTownInstance.h index d29ea968e..f1ab95dd0 100644 --- a/lib/mapObjects/CGTownInstance.h +++ b/lib/mapObjects/CGTownInstance.h @@ -237,6 +237,7 @@ public: CBuilding::TRequired genBuildingRequirements(BuildingID build, bool includeUpgrade=true) const; + void mergeGarrisonOnSiege() const; // merge garrison into army of visiting hero void removeCapitols (PlayerColor owner) const; void addHeroToStructureVisitors(const CGHeroInstance *h, si32 structureInstanceID) const; //hero must be visiting or garrisoned in town