Explorar el Código

CGSubterraneanGate: fix pairing and always assign all gates to channel

Before gates on underground layer didn't had any channel assigned and of course any function that attempt to check -1 channel caused crash.
Also I find out that at point postInit executed It's possible to get mutable gamestate via gameState() callback so we don't need to pass it there.
ArseniyShestakov hace 10 años
padre
commit
17f3f94ca6
Se han modificado 3 ficheros con 19 adiciones y 11 borrados
  1. 1 1
      lib/CGameState.cpp
  2. 17 9
      lib/mapObjects/MiscObjects.cpp
  3. 1 1
      lib/mapObjects/MiscObjects.h

+ 1 - 1
lib/CGameState.cpp

@@ -1867,7 +1867,7 @@ void CGameState::initMapObjects()
 			}
 		}
 	}
-	CGSubterraneanGate::postInit(gs); //pairing subterranean gates
+	CGSubterraneanGate::postInit(); //pairing subterranean gates
 
 	map->calculateGuardingGreaturePositions(); //calculate once again when all the guards are placed and initialized
 }

+ 17 - 9
lib/mapObjects/MiscObjects.cpp

@@ -996,13 +996,13 @@ void CGSubterraneanGate::initObj()
 	type = BOTH;
 }
 
-void CGSubterraneanGate::postInit( CGameState * gs ) //matches subterranean gates into pairs
+void CGSubterraneanGate::postInit() //matches subterranean gates into pairs
 {
 	//split on underground and surface gates
 	std::vector<CGSubterraneanGate *> gatesSplit[2]; //surface and underground gates
 	for(auto & obj : cb->gameState()->map->objects)
 	{
-		auto hlp = dynamic_cast<CGSubterraneanGate *>(gs->getObjInstance(obj->id));
+		auto hlp = dynamic_cast<CGSubterraneanGate *>(cb->gameState()->getObjInstance(obj->id));
 		if(hlp)
 			gatesSplit[hlp->pos.z].push_back(hlp);
 	}
@@ -1013,6 +1013,15 @@ void CGSubterraneanGate::postInit( CGameState * gs ) //matches subterranean gate
 		return a->pos < b->pos;
 	});
 
+	auto assignToChannel = [&](CGSubterraneanGate * obj)
+	{
+		if(obj->channel == TeleportChannelID())
+		{ // if object not linked to channel then create new channel
+			obj->channel = TeleportChannelID(cb->gameState()->map->teleportChannels.size());
+			addToChannel(cb->gameState()->map->teleportChannels, obj);
+		}
+	};
+
 	for(size_t i = 0; i < gatesSplit[0].size(); i++)
 	{
 		CGSubterraneanGate * objCurrent = gatesSplit[0][i];
@@ -1022,7 +1031,7 @@ void CGSubterraneanGate::postInit( CGameState * gs ) //matches subterranean gate
 		for(int j = 0; j < gatesSplit[1].size(); j++)
 		{
 			CGSubterraneanGate *checked = gatesSplit[1][j];
-			if(!checked)
+			if(checked->channel != TeleportChannelID())
 				continue;
 			si32 hlp = checked->pos.dist2dSQ(objCurrent->pos);
 			if(hlp < best.second)
@@ -1032,18 +1041,17 @@ void CGSubterraneanGate::postInit( CGameState * gs ) //matches subterranean gate
 			}
 		}
 
-		if(objCurrent->channel == TeleportChannelID())
-		{ // if object not linked to channel then create new channel
-			objCurrent->channel = TeleportChannelID(gs->map->teleportChannels.size());
-			addToChannel(cb->gameState()->map->teleportChannels, objCurrent);
-		}
-
+		assignToChannel(objCurrent);
 		if(best.first >= 0) //found pair
 		{
 			gatesSplit[1][best.first]->channel = objCurrent->channel;
 			addToChannel(cb->gameState()->map->teleportChannels, gatesSplit[1][best.first]);
 		}
 	}
+
+	// we should assign empty channels to underground gates if they don't have matching overground gates
+	for(size_t i = 0; i < gatesSplit[1].size(); i++)
+		assignToChannel(gatesSplit[1][i]);
 }
 
 void CGWhirlpool::onHeroVisit( const CGHeroInstance * h ) const

+ 1 - 1
lib/mapObjects/MiscObjects.h

@@ -315,7 +315,7 @@ class DLL_LINKAGE CGSubterraneanGate : public CGMonolith
 public:
 	void onHeroVisit(const CGHeroInstance * h) const override;
 	void initObj() override;
-	static void postInit(CGameState * gs);
+	static void postInit();
 
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{