浏览代码

Fix regressions in combat

Ivan Savenko 6 月之前
父节点
当前提交
ce436bd63e
共有 7 个文件被更改,包括 22 次插入14 次删除
  1. 5 6
      lib/CStack.cpp
  2. 2 1
      lib/CStack.h
  3. 6 0
      lib/battle/BattleInfo.cpp
  4. 5 0
      lib/battle/BattleInfo.h
  5. 2 4
      server/CGameHandler.cpp
  6. 1 1
      server/CGameHandler.h
  7. 1 2
      server/queries/VisitQueries.cpp

+ 5 - 6
lib/CStack.cpp

@@ -405,9 +405,9 @@ void CStack::spendMana(ServerCallback * server, const int spellCost) const
 	server->apply(ssp);
 }
 
-void CStack::postDeserialize(const CArmedInstance * army, const SlotID & extSlot)
+void CStack::postDeserialize(const CArmedInstance * army)
 {
-	if(extSlot == SlotID::COMMANDER_SLOT_PLACEHOLDER)
+	if(slot == SlotID::COMMANDER_SLOT_PLACEHOLDER)
 	{
 		const auto * hero = dynamic_cast<const CGHeroInstance *>(army);
 		assert(hero);
@@ -418,14 +418,13 @@ void CStack::postDeserialize(const CArmedInstance * army, const SlotID & extSlot
 		//no external slot possible, so no base stack
 		base = nullptr;
 	}
-	else if(!army || extSlot == SlotID() || !army->hasStackAtSlot(extSlot))
+	else if(!army || slot == SlotID() || !army->hasStackAtSlot(slot))
 	{
-		base = nullptr;
-		logGlobal->warn("%s doesn't have a base stack!", typeID.toEntity(LIBRARY)->getNameSingularTranslated());
+		throw std::runtime_error(typeID.toEntity(LIBRARY)->getNameSingularTranslated() + " doesn't have a base stack!");
 	}
 	else
 	{
-		base = &army->getStack(extSlot);
+		base = &army->getStack(slot);
 	}
 
 	doubleWideCached = battle::CUnitState::doubleWide();

+ 2 - 1
lib/CStack.h

@@ -37,8 +37,9 @@ private:
 
 	bool doubleWideCached = false;
 
-	void postDeserialize(const CArmedInstance * army, const SlotID & extSlot);
 public:
+	void postDeserialize(const CArmedInstance * army);
+
 	const CStackInstance * base = nullptr; //garrison slot from which stack originates (nullptr for war machines, summoned cres, etc)
 	
 	BattleHex initialPosition; //position on battlefield; -2 - keep, -3 - lower tower, -4 - upper tower

+ 6 - 0
lib/battle/BattleInfo.cpp

@@ -959,6 +959,12 @@ CGHeroInstance * BattleInfo::battleGetFightingHero(BattleSide side) const
 	return const_cast<CGHeroInstance*>(CBattleInfoEssentials::battleGetFightingHero(side));
 }
 
+void BattleInfo::postDeserialize()
+{
+	for (auto & unit : stacks)
+		unit->postDeserialize(getSideArmy(unit->unitSide()));
+}
+
 #if SCRIPTING_ENABLED
 scripting::Pool * BattleInfo::getContextPool() const
 {

+ 5 - 0
lib/battle/BattleInfo.h

@@ -31,6 +31,8 @@ class DLL_LINKAGE BattleInfo : public CBonusSystemNode, public CBattleInfoCallba
 {
 	BattleSideArray<SideInBattle> sides; //sides[0] - attacker, sides[1] - defender
 	std::unique_ptr<BattleLayout> layout;
+
+	void postDeserialize();
 public:
 	BattleID battleID = BattleID(0);
 
@@ -66,6 +68,9 @@ public:
 		h & tacticDistance;
 		h & static_cast<CBonusSystemNode&>(*this);
 		h & replayAllowed;
+
+		if(!h.saving)
+			postDeserialize();
 	}
 
 	//////////////////////////////////////////////////////////////////////////

+ 2 - 4
server/CGameHandler.cpp

@@ -3439,12 +3439,10 @@ void CGameHandler::objectVisited(const CGObjectInstance * obj, const CGHeroInsta
 		queries->popIfTop(visitQuery); //visit ends here if no queries were created
 }
 
-void CGameHandler::objectVisitEnded(const CGHeroInstance *h, PlayerColor player)
+void CGameHandler::objectVisitEnded(const ObjectInstanceID & heroObjectID, PlayerColor player)
 {
 	using events::ObjectVisitEnded;
 
-	logGlobal->debug("%s visit ends.\n", h->nodeName());
-
 	auto endVisit = [&](ObjectVisitEnded & event)
 	{
 		HeroVisit hv;
@@ -3456,7 +3454,7 @@ void CGameHandler::objectVisitEnded(const CGHeroInstance *h, PlayerColor player)
 
 	//TODO: ObjectVisitEnded should also have id of visited object,
 	//but this requires object being deleted only by `removeAfterVisit()` but not `removeObject()`
-	ObjectVisitEnded::defaultExecute(serverEventBus.get(), endVisit, player, h->id);
+	ObjectVisitEnded::defaultExecute(serverEventBus.get(), endVisit, player, heroObjectID);
 }
 
 bool CGameHandler::buildBoat(ObjectInstanceID objid, PlayerColor playerID)

+ 1 - 1
server/CGameHandler.h

@@ -238,7 +238,7 @@ public:
 
 	bool complain(const std::string &problem); //sends message to all clients, prints on the logs and return true
 	void objectVisited( const CGObjectInstance * obj, const CGHeroInstance * h );
-	void objectVisitEnded(const CGHeroInstance *h, PlayerColor player);
+	void objectVisitEnded(const ObjectInstanceID & heroObjectID, PlayerColor player);
 	bool dig(const CGHeroInstance *h);
 	void moveArmy(const CArmedInstance *src, const CArmedInstance *dst, bool allowMerging);
 

+ 1 - 2
server/queries/VisitQueries.cpp

@@ -53,9 +53,8 @@ MapObjectVisitQuery::MapObjectVisitQuery(CGameHandler * owner, const CGObjectIns
 void MapObjectVisitQuery::onRemoval(PlayerColor color)
 {
 	auto object = gh->gameState()->getObjInstance(visitedObject);
-	auto hero = gh->gameState()->getHero(visitingHero);
 
-	gh->objectVisitEnded(hero, players.front());
+	gh->objectVisitEnded(visitingHero, players.front());
 
 	//Can object visit affect 2 players and what would be desired behavior?
 	if(removeObjectAfterVisit)