Browse Source

Removed ConstTransitivePtr from StackLocation

Ivan Savenko 8 months ago
parent
commit
82506d5eff

+ 6 - 6
lib/mapObjects/CGCreature.cpp

@@ -476,13 +476,13 @@ void CGCreature::fight( const CGHeroInstance *h ) const
 	for (int slotID = 1; slotID < a; ++slotID)
 	{
 		int stackSize = m + 1;
-		cb->moveStack(StackLocation(this, sourceSlot), StackLocation(this, SlotID(slotID)), stackSize);
+		cb->moveStack(StackLocation(id, sourceSlot), StackLocation(id, SlotID(slotID)), stackSize);
 	}
 	for (int slotID = a; slotID < stacksCount; ++slotID)
 	{
 		int stackSize = m;
 		if (slotID) //don't do this when a = 0 -> stack is single
-			cb->moveStack(StackLocation(this, sourceSlot), StackLocation(this, SlotID(slotID)), stackSize);
+			cb->moveStack(StackLocation(id, sourceSlot), StackLocation(id, SlotID(slotID)), stackSize);
 	}
 	if (stacksCount > 1)
 	{
@@ -493,7 +493,7 @@ void CGCreature::fight( const CGHeroInstance *h ) const
 			if(!upgrades.empty())
 			{
 				auto it = RandomGeneratorUtil::nextItem(upgrades, cb->gameState()->getRandomGenerator());
-				cb->changeStackType(StackLocation(this, slotID), it->toCreature());
+				cb->changeStackType(StackLocation(id, slotID), it->toCreature());
 			}
 		}
 	}
@@ -532,13 +532,13 @@ void CGCreature::battleFinished(const CGHeroInstance *hero, const BattleResult &
 		{
 			if(cre->isMyUpgrade(i->second->getCreature()))
 			{
-				cb->changeStackType(StackLocation(this, i->first), cre); //un-upgrade creatures
+				cb->changeStackType(StackLocation(id, i->first), cre); //un-upgrade creatures
 			}
 		}
 
 		//first stack has to be at slot 0 -> if original one got killed, move there first remaining stack
 		if(!hasStackAtSlot(SlotID(0)))
-			cb->moveStack(StackLocation(this, stacks.begin()->first), StackLocation(this, SlotID(0)), stacks.begin()->second->count);
+			cb->moveStack(StackLocation(id, stacks.begin()->first), StackLocation(id, SlotID(0)), stacks.begin()->second->count);
 
 		while(stacks.size() > 1) //hopefully that's enough
 		{
@@ -549,7 +549,7 @@ void CGCreature::battleFinished(const CGHeroInstance *hero, const BattleResult &
 			if(slot == i->first) //no reason to move stack to its own slot
 				break;
 			else
-				cb->moveStack(StackLocation(this, i->first), StackLocation(this, slot), i->second->count);
+				cb->moveStack(StackLocation(id, i->first), StackLocation(id, slot), i->second->count);
 		}
 
 		cb->setObjPropertyValue(id, ObjProperty::MONSTER_POWER, stacks.begin()->second->count * 1000); //remember casualties

+ 2 - 2
lib/mapObjects/CGDwelling.cpp

@@ -420,7 +420,7 @@ void CGDwelling::heroAcceptsCreatures( const CGHeroInstance *h) const
 					std::pair<SlotID, SlotID> toMerge;
 					if (h->mergeableStacks(toMerge))
 					{
-						cb->moveStack(StackLocation(h, toMerge.first), StackLocation(h, toMerge.second), -1); //merge toMerge.first into toMerge.second
+						cb->moveStack(StackLocation(h->id, toMerge.first), StackLocation(h->id, toMerge.second), -1); //merge toMerge.first into toMerge.second
 						assert(!h->hasStackAtSlot(toMerge.first)); //we have now a new free slot
 					}
 				}
@@ -453,7 +453,7 @@ void CGDwelling::heroAcceptsCreatures( const CGHeroInstance *h) const
 
 				cb->showInfoDialog(&iw);
 				cb->sendAndApply(sac);
-				cb->addToSlot(StackLocation(h, slot), crs, count);
+				cb->addToSlot(StackLocation(h->id, slot), crs, count);
 			}
 		}
 		else //there no creatures

+ 3 - 3
lib/mapObjects/CGTownInstance.cpp

@@ -620,12 +620,12 @@ void CGTownInstance::mergeGarrisonOnSiege() const
 		});
 		auto dst = visitingHero->getSlotFor(pair.second->getCreatureID());
 		if(dst.validSlot())
-			cb->moveStack(StackLocation(this, pair.first), StackLocation(visitingHero, dst), -1);
+			cb->moveStack(StackLocation(id, pair.first), StackLocation(visitingHero->id, dst), -1);
 		else
 		{
 			dst = getWeakestStackSlot(static_cast<int>(pair.second->getPower()));
 			if(dst.validSlot())
-				cb->swapStacks(StackLocation(this, pair.first), StackLocation(visitingHero, dst));
+				cb->swapStacks(StackLocation(id, pair.first), StackLocation(visitingHero->id, dst));
 		}
 	}
 }
@@ -654,7 +654,7 @@ void CGTownInstance::clearArmy() const
 {
 	while(!stacks.empty())
 	{
-		cb->eraseStack(StackLocation(this, stacks.begin()->first));
+		cb->eraseStack(StackLocation(id, stacks.begin()->first));
 	}
 }
 

+ 2 - 2
lib/mapObjects/MiscObjects.cpp

@@ -573,7 +573,7 @@ void CGWhirlpool::onHeroVisit( const CGHeroInstance * h ) const
 		iw.text.appendLocalString(EMetaText::ADVOB_TXT, 168);
 		iw.components.emplace_back(ComponentType::CREATURE, h->getCreature(targetstack)->getId(), -countToTake);
 		cb->showInfoDialog(&iw);
-		cb->changeStackCount(StackLocation(h, targetstack), -countToTake);
+		cb->changeStackCount(StackLocation(h->id, targetstack), -countToTake);
 	}
 	else
 	{
@@ -1043,7 +1043,7 @@ void CGSirens::onHeroVisit( const CGHeroInstance * h ) const
 
 			if(drown)
 			{
-				cb->changeStackCount(StackLocation(h, i->first), -drown);
+				cb->changeStackCount(StackLocation(h->id, i->first), -drown);
 				xp += drown * i->second->getType()->getMaxHealth();
 			}
 		}

+ 27 - 37
lib/networkPacks/NetPacksLib.cpp

@@ -1520,16 +1520,6 @@ void NewArtifact::applyGs(CGameState *gs)
 	pa.applyGs(gs);
 }
 
-const CStackInstance * StackLocation::getStack()
-{
-	if(!army->hasStackAtSlot(slot))
-	{
-		logNetwork->warn("%s don't have a stack at slot %d", army->nodeName(), slot.getNum());
-		return nullptr;
-	}
-	return &army->getStack(slot);
-}
-
 struct ObjectRetriever
 {
 	const CArmedInstance * operator()(const ConstTransitivePtr<CGHeroInstance> &h) const
@@ -1616,25 +1606,25 @@ void RebalanceStacks::applyGs(CGameState *gs)
 	if(!dstObj)
 		throw std::runtime_error("RebalanceStacks: invalid army object " + std::to_string(dstArmy.getNum()) + ", possible game state corruption.");
 
-	StackLocation src(srcObj, srcSlot);
-	StackLocation dst(dstObj, dstSlot);
+	StackLocation src(srcObj->id, srcSlot);
+	StackLocation dst(dstObj->id, dstSlot);
 
-	const CCreature * srcType = src.army->getCreature(src.slot);
-	TQuantity srcCount = src.army->getStackCount(src.slot);
+	const CCreature * srcType = srcObj->getCreature(src.slot);
+	TQuantity srcCount = srcObj->getStackCount(src.slot);
 	bool stackExp = gs->getSettings().getBoolean(EGameSettings::MODULE_STACK_EXPERIENCE);
 
 	if(srcCount == count) //moving whole stack
 	{
-		const auto c = dst.army->getCreature(dst.slot);
+		const auto c = dstObj->getCreature(dst.slot);
 
 		if(c) //stack at dest -> merge
 		{
 			assert(c == srcType);
 			
-			const auto srcHero = dynamic_cast<CGHeroInstance*>(src.army.get());
-			const auto dstHero = dynamic_cast<CGHeroInstance*>(dst.army.get());
-			auto srcStack = const_cast<CStackInstance*>(src.getStack());
-			auto dstStack = const_cast<CStackInstance*>(dst.getStack());
+			const auto srcHero = dynamic_cast<CGHeroInstance*>(srcObj);
+			const auto dstHero = dynamic_cast<CGHeroInstance*>(dstObj);
+			auto srcStack = const_cast<CStackInstance*>(srcObj->getStackPtr(src.slot));
+			auto dstStack = const_cast<CStackInstance*>(dstObj->getStackPtr(dst.slot));
 			if(srcStack->getArt(ArtifactPosition::CREATURE_SLOT))
 			{
 				if(auto dstArt = dstStack->getArt(ArtifactPosition::CREATURE_SLOT))
@@ -1664,48 +1654,48 @@ void RebalanceStacks::applyGs(CGameState *gs)
 			}
 			if (stackExp)
 			{
-				ui64 totalExp = srcCount * src.army->getStackExperience(src.slot) + dst.army->getStackCount(dst.slot) * dst.army->getStackExperience(dst.slot);
-				src.army->eraseStack(src.slot);
-				dst.army->changeStackCount(dst.slot, count);
-				dst.army->setStackExp(dst.slot, totalExp /(dst.army->getStackCount(dst.slot))); //mean
+				ui64 totalExp = srcCount * srcObj->getStackExperience(src.slot) + dstObj->getStackCount(dst.slot) * dstObj->getStackExperience(dst.slot);
+				srcObj->eraseStack(src.slot);
+				dstObj->changeStackCount(dst.slot, count);
+				dstObj->setStackExp(dst.slot, totalExp /(dstObj->getStackCount(dst.slot))); //mean
 			}
 			else
 			{
-				src.army->eraseStack(src.slot);
-				dst.army->changeStackCount(dst.slot, count);
+				srcObj->eraseStack(src.slot);
+				dstObj->changeStackCount(dst.slot, count);
 			}
 		}
 		else //move stack to an empty slot, no exp change needed
 		{
-			CStackInstance *stackDetached = src.army->detachStack(src.slot);
-			dst.army->putStack(dst.slot, stackDetached);
+			CStackInstance *stackDetached = srcObj->detachStack(src.slot);
+			dstObj->putStack(dst.slot, stackDetached);
 		}
 	}
 	else
 	{
-		[[maybe_unused]] const CCreature *c = dst.army->getCreature(dst.slot);
+		[[maybe_unused]] const CCreature *c = dstObj->getCreature(dst.slot);
 		if(c) //stack at dest -> rebalance
 		{
 			assert(c == srcType);
 			if (stackExp)
 			{
-				ui64 totalExp = srcCount * src.army->getStackExperience(src.slot) + dst.army->getStackCount(dst.slot) * dst.army->getStackExperience(dst.slot);
-				src.army->changeStackCount(src.slot, -count);
-				dst.army->changeStackCount(dst.slot, count);
-				dst.army->setStackExp(dst.slot, totalExp /(src.army->getStackCount(src.slot) + dst.army->getStackCount(dst.slot))); //mean
+				ui64 totalExp = srcCount * srcObj->getStackExperience(src.slot) + dstObj->getStackCount(dst.slot) * dstObj->getStackExperience(dst.slot);
+				srcObj->changeStackCount(src.slot, -count);
+				dstObj->changeStackCount(dst.slot, count);
+				dstObj->setStackExp(dst.slot, totalExp /(srcObj->getStackCount(src.slot) + dstObj->getStackCount(dst.slot))); //mean
 			}
 			else
 			{
-				src.army->changeStackCount(src.slot, -count);
-				dst.army->changeStackCount(dst.slot, count);
+				srcObj->changeStackCount(src.slot, -count);
+				dstObj->changeStackCount(dst.slot, count);
 			}
 		}
 		else //split stack to an empty slot
 		{
-			src.army->changeStackCount(src.slot, -count);
-			dst.army->addToSlot(dst.slot, srcType->getId(), count, false);
+			srcObj->changeStackCount(src.slot, -count);
+			dstObj->addToSlot(dst.slot, srcType->getId(), count, false);
 			if (stackExp)
-				dst.army->setStackExp(dst.slot, src.army->getStackExperience(src.slot));
+				dstObj->setStackExp(dst.slot, srcObj->getStackExperience(src.slot));
 		}
 	}
 

+ 7 - 11
lib/networkPacks/StackLocation.h

@@ -9,28 +9,24 @@
  */
 #pragma once
 
-#include "../ConstTransitivePtr.h"
-#include "../GameConstants.h"
+#include "../constants/EntityIdentifiers.h"
 
 VCMI_LIB_NAMESPACE_BEGIN
 
-class CArmedInstance;
-class CStackInstance;
-
 struct StackLocation
 {
-	ConstTransitivePtr<CArmedInstance> army;
+	ObjectInstanceID army;
 	SlotID slot;
 
 	StackLocation() = default;
-	StackLocation(const CArmedInstance * Army, const SlotID & Slot)
-		: army(const_cast<CArmedInstance *>(Army))  //we are allowed here to const cast -> change will go through one of our packages... do not abuse!
-		, slot(Slot)
+	StackLocation(const ObjectInstanceID & army, const SlotID & slot)
+		: army(army)
+		, slot(slot)
 	{
 	}
 
-	DLL_LINKAGE const CStackInstance * getStack();
-	template <typename Handler> void serialize(Handler & h)
+	template<typename Handler>
+	void serialize(Handler & h)
 	{
 		h & army;
 		h & slot;

+ 1 - 1
lib/rewardable/Interface.cpp

@@ -185,7 +185,7 @@ void Rewardable::Interface::grantRewardAfterLevelup(const Rewardable::VisitInfo
 			{
 				if (heroStack->getId() == change.first)
 				{
-					StackLocation location(hero, slot.first);
+					StackLocation location(hero->id, slot.first);
 					cb->changeStackType(location, change.second.toCreature());
 					break;
 				}

+ 62 - 46
server/CGameHandler.cpp

@@ -1142,7 +1142,7 @@ void CGameHandler::giveCreatures(const CArmedInstance *obj, const CGHeroInstance
 	//first we move creatures to give to make them army of object-source
 	for (auto & elem : creatures.Slots())
 	{
-		addToSlot(StackLocation(obj, obj->getSlotFor(elem.second->getCreature())), elem.second->getCreature(), elem.second->count);
+		addToSlot(StackLocation(obj->id, obj->getSlotFor(elem.second->getCreature())), elem.second->getCreature(), elem.second->count);
 	}
 
 	tryJoiningArmy(obj, h, remove, true);
@@ -1166,7 +1166,7 @@ void CGameHandler::takeCreatures(ObjectInstanceID objid, const std::vector<CStac
 				if (i->second->getType() == sbd.getType())
 				{
 					TQuantity take = std::min(sbd.count - collected, i->second->count); //collect as much cres as we can
-					changeStackCount(StackLocation(obj, i->first), -take, false);
+					changeStackCount(StackLocation(obj->id, i->first), -take, false);
 					collected += take;
 					foundSth = true;
 					break;
@@ -1879,8 +1879,8 @@ bool CGameHandler::arrangeStacks(ObjectInstanceID id1, ObjectInstanceID id2, ui8
 
 	const CCreatureSet & S1 = *s1;
 	const CCreatureSet & S2 = *s2;
-	StackLocation sl1(s1, p1);
-	StackLocation sl2(s2, p2);
+	StackLocation sl1(s1->id, p1);
+	StackLocation sl2(s2->id, p2);
 
 	if (!sl1.slot.validSlot()  ||  !sl2.slot.validSlot())
 	{
@@ -1926,12 +1926,12 @@ bool CGameHandler::arrangeStacks(ObjectInstanceID id1, ObjectInstanceID id2, ui8
 
 		if (!s1->slotEmpty(p1) && !s2->slotEmpty(p2))
 		{
-			if (notRemovable(sl1.army) || notRemovable(sl2.army))
+			if (notRemovable(s1) || notRemovable(s2))
 				return false;
 		}
-		if (s1->slotEmpty(p1) && notRemovable(sl2.army))
+		if (s1->slotEmpty(p1) && notRemovable(s2))
 			return false;
-		else if (s2->slotEmpty(p2) && notRemovable(sl1.army))
+		else if (s2->slotEmpty(p2) && notRemovable(s1))
 			return false;
 
 		swapStacks(sl1, sl2);
@@ -1947,7 +1947,7 @@ bool CGameHandler::arrangeStacks(ObjectInstanceID id1, ObjectInstanceID id2, ui8
 			complain("Cannot merge empty stack!");
 			return false;
 		}
-		else if (notRemovable(sl1.army))
+		else if (notRemovable(s1))
 			return false;
 
 		moveStack(sl1, sl2);
@@ -1982,12 +1982,12 @@ bool CGameHandler::arrangeStacks(ObjectInstanceID id1, ObjectInstanceID id2, ui8
 				return false;
 			}
 
-			if (notRemovable(sl1.army))
+			if (notRemovable(s1))
 			{
 				if (s1->getStackCount(p1) > countLeftOnSrc)
 					return false;
 			}
-			else if (notRemovable(sl2.army))
+			else if (notRemovable(s2))
 			{
 				if (s2->getStackCount(p1) < countLeftOnSrc)
 					return false;
@@ -2005,7 +2005,7 @@ bool CGameHandler::arrangeStacks(ObjectInstanceID id1, ObjectInstanceID id2, ui8
 				return false;
 			}
 
-			if (notRemovable(sl1.army))
+			if (notRemovable(s1))
 				return false;
 
 			moveStack(sl1, sl2, val);
@@ -2034,7 +2034,7 @@ bool CGameHandler::disbandCreature(ObjectInstanceID id, SlotID pos)
 		return false;
 	}
 
-	eraseStack(StackLocation(s1, pos));
+	eraseStack(StackLocation(s1->id, pos));
 	return true;
 }
 
@@ -2403,7 +2403,7 @@ bool CGameHandler::recruitCreatures(ObjectInstanceID objid, ObjectInstanceID dst
 	}
 	else
 	{
-		addToSlot(StackLocation(army, slot), c, cram);
+		addToSlot(StackLocation(army->id, slot), c, cram);
 	}
 	return true;
 }
@@ -2437,17 +2437,19 @@ bool CGameHandler::upgradeCreature(ObjectInstanceID objid, SlotID pos, CreatureI
 	gs->statistic.accumulatedValues[player].spentResourcesForArmy += totalCost;
 
 	//upgrade creature
-	changeStackType(StackLocation(obj, pos), upgID.toCreature());
+	changeStackType(StackLocation(obj->id, pos), upgID.toCreature());
 	return true;
 }
 
 bool CGameHandler::changeStackType(const StackLocation &sl, const CCreature *c)
 {
-	if (!sl.army->hasStackAtSlot(sl.slot))
+	const CArmedInstance * obj = static_cast<const CArmedInstance *>(getObjInstance(sl.army));
+
+	if (!obj->hasStackAtSlot(sl.slot))
 		COMPLAIN_RET("Cannot find a stack to change type");
 
 	SetStackType sst;
-	sst.army = sl.army->id;
+	sst.army = obj->id;
 	sst.slot = sl.slot;
 	sst.type = c->getId();
 	sendAndApply(sst);
@@ -2460,7 +2462,7 @@ void CGameHandler::moveArmy(const CArmedInstance *src, const CArmedInstance *dst
 	while(src->stacksCount())//while there are unmoved creatures
 	{
 		auto i = src->Slots().begin(); //iterator to stack to move
-		StackLocation sl(src, i->first); //location of stack to move
+		StackLocation sl(src->id, i->first); //location of stack to move
 
 		SlotID pos = dst->getSlotFor(i->second->getCreature());
 		if (!pos.validSlot())
@@ -2469,9 +2471,9 @@ void CGameHandler::moveArmy(const CArmedInstance *src, const CArmedInstance *dst
 			std::pair<SlotID, SlotID> toMerge;
 			if (dst->mergeableStacks(toMerge, i->first) && allowMerging)
 			{
-				moveStack(StackLocation(dst, toMerge.first), StackLocation(dst, toMerge.second)); //merge toMerge.first into toMerge.second
+				moveStack(StackLocation(dst->id, toMerge.first), StackLocation(dst->id, toMerge.second)); //merge toMerge.first into toMerge.second
 				assert(!dst->hasStackAtSlot(toMerge.first)); //we have now a new free slot
-				moveStack(sl, StackLocation(dst, toMerge.first)); //move stack to freed slot
+				moveStack(sl, StackLocation(dst->id, toMerge.first)); //move stack to freed slot
 			}
 			else
 			{
@@ -2481,7 +2483,7 @@ void CGameHandler::moveArmy(const CArmedInstance *src, const CArmedInstance *dst
 		}
 		else
 		{
-			moveStack(sl, StackLocation(dst, pos));
+			moveStack(sl, StackLocation(dst->id, pos));
 		}
 	}
 }
@@ -3170,7 +3172,7 @@ bool CGameHandler::sellCreatures(ui32 count, const IMarket *market, const CGHero
 		assert(0);
 	}
 
-	changeStackCount(StackLocation(hero, slot), -(TQuantity)count);
+	changeStackCount(StackLocation(hero->id, slot), -(TQuantity)count);
 
 	giveResource(hero->tempOwner, resourceID, b2 * units);
 
@@ -3201,7 +3203,7 @@ bool CGameHandler::transformInUndead(const IMarket *market, const CGHeroInstance
 			|| (s.getCreatureID() == CreatureID::HYDRA)
 			|| (s.getCreatureID() == CreatureID::CHAOS_HYDRA))
 		resCreature = CreatureID::BONE_DRAGON;
-	changeStackType(StackLocation(army, slot), resCreature.toCreature());
+	changeStackType(StackLocation(army->id, slot), resCreature.toCreature());
 	return true;
 }
 
@@ -3679,7 +3681,7 @@ bool CGameHandler::sacrificeCreatures(const IMarket * market, const CGHeroInstan
 
 		int crid = hero->getStack(slot[i]).getId();
 
-		changeStackCount(StackLocation(hero, slot[i]), -(TQuantity)count[i]);
+		changeStackCount(StackLocation(hero->id, slot[i]), -(TQuantity)count[i]);
 
 		int dump;
 		int exp;
@@ -3742,14 +3744,16 @@ bool CGameHandler::sacrificeArtifact(const IMarket * market, const CGHeroInstanc
 
 bool CGameHandler::insertNewStack(const StackLocation &sl, const CCreature *c, TQuantity count)
 {
-	if (sl.army->hasStackAtSlot(sl.slot))
+	auto army = dynamic_cast<const CArmedInstance*>(getObj(sl.army));
+
+	if (army->hasStackAtSlot(sl.slot))
 		COMPLAIN_RET("Slot is already taken!");
 
 	if (!sl.slot.validSlot())
 		COMPLAIN_RET("Cannot insert stack to that slot!");
 
 	InsertNewStack ins;
-	ins.army = sl.army->id;
+	ins.army = army->id;
 	ins.slot = sl.slot;
 	ins.type = c->getId();
 	ins.count = count;
@@ -3759,18 +3763,20 @@ bool CGameHandler::insertNewStack(const StackLocation &sl, const CCreature *c, T
 
 bool CGameHandler::eraseStack(const StackLocation &sl, bool forceRemoval)
 {
-	if (!sl.army->hasStackAtSlot(sl.slot))
+	auto army = dynamic_cast<const CArmedInstance*>(getObj(sl.army));
+
+	if (!army->hasStackAtSlot(sl.slot))
 		COMPLAIN_RET("Cannot find a stack to erase");
 
-	if (sl.army->stacksCount() == 1 //from the last stack
-		&& sl.army->needsLastStack() //that must be left
+	if (army->stacksCount() == 1 //from the last stack
+		&& army->needsLastStack() //that must be left
 		&& !forceRemoval) //ignore above conditions if we are forcing removal
 	{
 		COMPLAIN_RET("Cannot erase the last stack!");
 	}
 
 	EraseStack es;
-	es.army = sl.army->id;
+	es.army = army->id;
 	es.slot = sl.slot;
 	sendAndApply(es);
 	return true;
@@ -3778,7 +3784,9 @@ bool CGameHandler::eraseStack(const StackLocation &sl, bool forceRemoval)
 
 bool CGameHandler::changeStackCount(const StackLocation &sl, TQuantity count, bool absoluteValue)
 {
-	TQuantity currentCount = sl.army->getStackCount(sl.slot);
+	auto army = dynamic_cast<const CArmedInstance*>(getObj(sl.army));
+
+	TQuantity currentCount = army->getStackCount(sl.slot);
 	if ((absoluteValue && count < 0)
 		|| (!absoluteValue && -count > currentCount))
 	{
@@ -3793,7 +3801,7 @@ bool CGameHandler::changeStackCount(const StackLocation &sl, TQuantity count, bo
 	else
 	{
 		ChangeStackCount csc;
-		csc.army = sl.army->id;
+		csc.army = army->id;
 		csc.slot = sl.slot;
 		csc.count = count;
 		csc.absoluteValue = absoluteValue;
@@ -3804,7 +3812,9 @@ bool CGameHandler::changeStackCount(const StackLocation &sl, TQuantity count, bo
 
 bool CGameHandler::addToSlot(const StackLocation &sl, const CCreature *c, TQuantity count)
 {
-	const CCreature *slotC = sl.army->getCreature(sl.slot);
+	auto army = dynamic_cast<const CArmedInstance*>(getObj(sl.army));
+
+	const CCreature *slotC = army->getCreature(sl.slot);
 	if (!slotC) //slot is empty
 		insertNewStack(sl, c, count);
 	else if (c == slotC)
@@ -3833,7 +3843,7 @@ void CGameHandler::tryJoiningArmy(const CArmedInstance *src, const CArmedInstanc
 					SlotID pos = dst->getSlotFor(i->second->getCreature());
 					if (pos.validSlot())
 					{
-						moveStack(StackLocation(src, i->first), StackLocation(dst, pos));
+						moveStack(StackLocation(src->id, i->first), StackLocation(dst->id, pos));
 						cont = true;
 						break; //or iterator crashes
 					}
@@ -3851,10 +3861,13 @@ void CGameHandler::tryJoiningArmy(const CArmedInstance *src, const CArmedInstanc
 
 bool CGameHandler::moveStack(const StackLocation &src, const StackLocation &dst, TQuantity count)
 {
-	if (!src.army->hasStackAtSlot(src.slot))
+	auto srcArmy = dynamic_cast<const CArmedInstance*>(getObj(src.army));
+	auto dstArmy = dynamic_cast<const CArmedInstance*>(getObj(dst.army));
+
+	if (!srcArmy->hasStackAtSlot(src.slot))
 		COMPLAIN_RET("No stack to move!");
 
-	if (dst.army->hasStackAtSlot(dst.slot) && dst.army->getCreature(dst.slot) != src.army->getCreature(src.slot))
+	if (dstArmy->hasStackAtSlot(dst.slot) && dstArmy->getCreature(dst.slot) != srcArmy->getCreature(src.slot))
 		COMPLAIN_RET("Cannot move: stack of different type at destination pos!");
 
 	if (!dst.slot.validSlot())
@@ -3862,20 +3875,20 @@ bool CGameHandler::moveStack(const StackLocation &src, const StackLocation &dst,
 
 	if (count == -1)
 	{
-		count = src.army->getStackCount(src.slot);
+		count = srcArmy->getStackCount(src.slot);
 	}
 
-	if (src.army != dst.army  //moving away
-		&&  count == src.army->getStackCount(src.slot) //all creatures
-		&& src.army->stacksCount() == 1 //from the last stack
-		&& src.army->needsLastStack()) //that must be left
+	if (srcArmy != dstArmy  //moving away
+		&&  count == srcArmy->getStackCount(src.slot) //all creatures
+		&& srcArmy->stacksCount() == 1 //from the last stack
+		&& srcArmy->needsLastStack()) //that must be left
 	{
 		COMPLAIN_RET("Cannot move away the last creature!");
 	}
 
 	RebalanceStacks rs;
-	rs.srcArmy = src.army->id;
-	rs.dstArmy = dst.army->id;
+	rs.srcArmy = srcArmy->id;
+	rs.dstArmy = dstArmy->id;
 	rs.srcSlot = src.slot;
 	rs.dstSlot = dst.slot;
 	rs.count = count;
@@ -3898,19 +3911,22 @@ void CGameHandler::castSpell(const spells::Caster * caster, SpellID spellID, con
 
 bool CGameHandler::swapStacks(const StackLocation & sl1, const StackLocation & sl2)
 {
-	if(!sl1.army->hasStackAtSlot(sl1.slot))
+	auto army1 = dynamic_cast<const CArmedInstance*>(getObj(sl1.army));
+	auto army2 = dynamic_cast<const CArmedInstance*>(getObj(sl2.army));
+
+	if(!army1->hasStackAtSlot(sl1.slot))
 	{
 		return moveStack(sl2, sl1);
 	}
-	else if(!sl2.army->hasStackAtSlot(sl2.slot))
+	else if(!army2->hasStackAtSlot(sl2.slot))
 	{
 		return moveStack(sl1, sl2);
 	}
 	else
 	{
 		SwapStacks ss;
-		ss.srcArmy = sl1.army->id;
-		ss.dstArmy = sl2.army->id;
+		ss.srcArmy = army1->id;
+		ss.dstArmy = army2->id;
 		ss.srcSlot = sl1.slot;
 		ss.dstSlot = sl2.slot;
 		sendAndApply(ss);

+ 4 - 4
server/battles/BattleResultProcessor.cpp

@@ -124,13 +124,13 @@ CasualtiesAfterBattle::CasualtiesAfterBattle(const CBattleInfoCallback & battle,
 			if(st->getCount() == 0 || !st->alive())
 			{
 				logGlobal->debug("Stack has been destroyed.");
-				StackLocation sl(army, st->unitSlot());
+				StackLocation sl(army->id, st->unitSlot());
 				newStackCounts.push_back(TStackAndItsNewCount(sl, 0));
 			}
 			else if(st->getCount() != army->getStackCount(st->unitSlot()))
 			{
 				logGlobal->debug("Stack size changed: %d -> %d units.", army->getStackCount(st->unitSlot()), st->getCount());
-				StackLocation sl(army, st->unitSlot());
+				StackLocation sl(army->id, st->unitSlot());
 				newStackCounts.push_back(TStackAndItsNewCount(sl, st->getCount()));
 			}
 		}
@@ -158,7 +158,7 @@ void CasualtiesAfterBattle::updateArmy(CGameHandler *gh)
 		SlotID slot = army->getSlotFor(summoned_iter.first);
 		if (slot.validSlot())
 		{
-			StackLocation location(army, slot);
+			StackLocation location(army->id, slot);
 			gh->addToSlot(location, summoned_iter.first.toCreature(), summoned_iter.second);
 		}
 		else
@@ -561,7 +561,7 @@ void BattleResultProcessor::battleAfterLevelUp(const BattleID & battleID, const
 	if (necroSlot != SlotID() && !finishingBattle->isDraw())
 	{
 		finishingBattle->winnerHero->showNecromancyDialog(raisedStack, gameHandler->getRandomGenerator());
-		gameHandler->addToSlot(StackLocation(finishingBattle->winnerHero, necroSlot), raisedStack.getCreature(), raisedStack.count);
+		gameHandler->addToSlot(StackLocation(finishingBattle->winnerHero->id, necroSlot), raisedStack.getCreature(), raisedStack.count);
 	}
 
 	BattleResultsApplied resultsApplied;

+ 1 - 0
server/battles/BattleResultProcessor.h

@@ -19,6 +19,7 @@ struct SideInBattle;
 struct BattleResult;
 class CBattleInfoCallback;
 class CGHeroInstance;
+class CArmedInstance;
 VCMI_LIB_NAMESPACE_END
 
 class CBattleQuery;

+ 2 - 2
server/processors/NewTurnProcessor.cpp

@@ -385,7 +385,7 @@ void NewTurnProcessor::updateNeutralTownGarrison(const CGTownInstance * t, int c
 		if (creature->getLevel() != tierToGrow)
 			continue;
 
-		StackLocation stackLocation(t, slot.first);
+		StackLocation stackLocation(t->id, slot.first);
 		gameHandler->changeStackCount(stackLocation, creature->getGrowth(), false);
 		takeFromAvailable(creature->getGrowth());
 
@@ -410,7 +410,7 @@ void NewTurnProcessor::updateNeutralTownGarrison(const CGTownInstance * t, int c
 			if (baseCreature.toEntity(LIBRARY)->getLevel() != tierToGrow)
 				continue;
 
-			StackLocation stackLocation(t, freeSlotID);
+			StackLocation stackLocation(t->id, freeSlotID);
 
 			if (upgradeUnit && !baseCreature.toCreature()->upgrades.empty())
 			{

+ 2 - 2
server/processors/PlayerMessageProcessor.cpp

@@ -432,9 +432,9 @@ void PlayerMessageProcessor::cheatGiveArmy(PlayerColor player, const CGHeroInsta
 			if (!hero->hasStackAtSlot(SlotID(i)))
 			{
 				if (amountPerSlot.has_value())
-					gameHandler->insertNewStack(StackLocation(hero, SlotID(i)), creature, *amountPerSlot);
+					gameHandler->insertNewStack(StackLocation(hero->id, SlotID(i)), creature, *amountPerSlot);
 				else
-					gameHandler->insertNewStack(StackLocation(hero, SlotID(i)), creature, 5 * std::pow(10, i));
+					gameHandler->insertNewStack(StackLocation(hero->id, SlotID(i)), creature, 5 * std::pow(10, i));
 			}
 		}
 	}