Bläddra i källkod

Merge pull request #196 from vcmi/feature/armiesMerging

Feature/armies merging
ArseniyShestakov 9 år sedan
förälder
incheckning
7f1ddc4a98
3 ändrade filer med 73 tillägg och 1 borttagningar
  1. 67 1
      lib/mapObjects/CGTownInstance.cpp
  2. 2 0
      lib/mapObjects/CGTownInstance.h
  3. 4 0
      server/CGameHandler.cpp

+ 67 - 1
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<int3> &offsets ) const
 	offsets = {int3(-1,2,0), int3(-3,2,0)};
 }
 
+void CGTownInstance::mergeGarrisonOnSiege() const
+{
+	auto getWeakestStackSlot = [&](int powerLimit)
+	{
+		std::vector<SlotID> weakSlots;
+		auto stacksList = visitingHero->stacks;
+		std::pair<SlotID, CStackInstance *> pair;
+		while(stacksList.size())
+		{
+			pair = *vstd::minElementByFun(stacksList, [&](std::pair<SlotID, CStackInstance *> 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<SlotID, CStackInstance *> 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
@@ -745,6 +802,14 @@ void CGTownInstance::removeCapitols (PlayerColor owner) const
 	}
 }
 
+void CGTownInstance::clearArmy() const
+{
+	while(!stacks.empty())
+	{
+		cb->eraseStack(StackLocation(this, stacks.begin()->first));
+	}
+}
+
 int CGTownInstance::getBoatType() const
 {
 	switch (town->faction->alignment)
@@ -1105,6 +1170,7 @@ void CGTownInstance::battleFinished(const CGHeroInstance *hero, const BattleResu
 {
 	if(result.winner == 0)
 	{
+		clearArmy();
 		removeCapitols(hero->getOwner());
 		cb->setOwner (this, hero->tempOwner); //give control after checkout is done
 		FoWChange fw;

+ 2 - 0
lib/mapObjects/CGTownInstance.h

@@ -237,7 +237,9 @@ 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 clearArmy() const;
 	void addHeroToStructureVisitors(const CGHeroInstance *h, si32 structureInstanceID) const; //hero must be visiting or garrisoned in town
 
 	CGTownInstance();

+ 4 - 0
server/CGameHandler.cpp

@@ -673,8 +673,12 @@ void CGameHandler::endBattle(int3 tile, const CGHeroInstance *hero1, const CGHer
 	}
 	if(battleResult.data->winner!=1 && hero2)
 	{
+		auto town = hero2->visitedTown;
 		RemoveObject ro(hero2->id);
 		sendAndApply(&ro);
+
+		if(town && !town->garrisonHero) // TODO: that must be called from CGHeroInstance or CGTownInstance
+			town->battleFinished(hero1, *battleResult.get());
 	}
 
 	//give exp