From c69e86d119cf73689140dcaf8c08032d480cd168 Mon Sep 17 00:00:00 2001
From: Christoph Oelckers <coelckers@users.noreply.github.com>
Date: Wed, 16 Nov 2022 11:55:41 +0100
Subject: [PATCH] - Blood: unlimited the tracking conditions.

---
 source/games/blood/src/callback.cpp |  9 +--
 source/games/blood/src/nnexts.cpp   | 91 +++++++++++------------------
 source/games/blood/src/nnexts.h     |  6 +-
 3 files changed, 40 insertions(+), 66 deletions(-)

diff --git a/source/games/blood/src/callback.cpp b/source/games/blood/src/callback.cpp
index 1172be553..57e060fc2 100644
--- a/source/games/blood/src/callback.cpp
+++ b/source/games/blood/src/callback.cpp
@@ -832,11 +832,12 @@ void callbackCondition(DBloodActor* actor, sectortype*)
 {
 	if (actor->xspr.isTriggered) return;
 
-	TRCONDITION const* pCond = &gCondition[actor->xspr.sysData1];
-	for (unsigned i = 0; i < pCond->length; i++) {
+	TRCONDITION const* pCond = &gConditions[actor->xspr.sysData1];
+	for (auto& obj : pCond->objects) 
+	{
 		EVENT evn;
-		evn.target = pCond->obj[i].obj;
-		evn.cmd = pCond->obj[i].cmd;
+		evn.target = obj.obj;
+		evn.cmd = obj.cmd;
 		evn.funcID = kCallbackCondition;
 		useCondition(actor, evn);
 	}
diff --git a/source/games/blood/src/nnexts.cpp b/source/games/blood/src/nnexts.cpp
index f6dc5232e..3d5af8745 100644
--- a/source/games/blood/src/nnexts.cpp
+++ b/source/games/blood/src/nnexts.cpp
@@ -59,8 +59,7 @@ short gEffectGenCallbacks[] = {
 
 TRPLAYERCTRL gPlayerCtrl[kMaxPlayers];
 
-TRCONDITION gCondition[kMaxTrackingConditions];
-int gTrackingCondsCount;
+TArray<TRCONDITION> gConditions;
 
 std::default_random_engine gStdRandom;
 
@@ -464,19 +463,7 @@ void nnExtResetGlobals()
 	memset(gProxySpritesList, 0, sizeof(gProxySpritesList));
 	memset(gPhysSpritesList, 0, sizeof(gPhysSpritesList));
 	memset(gImpactSpritesList, 0, sizeof(gImpactSpritesList));
-
-	// reset tracking conditions, if any
-	for (size_t i = 0; i < countof(gCondition); i++)
-	{
-		TRCONDITION* pCond = &gCondition[i];
-		for (unsigned k = 0; k < kMaxTracedObjects; k++)
-		{
-			pCond->obj[k].obj = EventObject(nullptr);
-		}
-		pCond->actor = nullptr;
-		pCond->length = 0;
-	}
-	gTrackingCondsCount = 0;
+	gConditions.Clear();
 }
 
 //---------------------------------------------------------------------------
@@ -812,11 +799,9 @@ void nnExtInitModernStuff(TArray<DBloodActor*>& actors)
 	while (auto iactor = it2.Next())
 	{
 		if (iactor->xspr.busyTime <= 0 || iactor->xspr.isTriggered) continue;
-		else if (gTrackingCondsCount >= kMaxTrackingConditions)
-			I_Error("\nMax (%d) tracking conditions reached!", kMaxTrackingConditions);
 
 		int count = 0;
-		TRCONDITION* pCond = &gCondition[gTrackingCondsCount];
+		TRCONDITION* pCond = &gConditions[gConditions.Reserve(1)];
 
 		for (auto iactor2 : actors)
 		{
@@ -833,21 +818,18 @@ void nnExtInitModernStuff(TArray<DBloodActor*>& actors)
 			if (iactor2->spr.type == kModernCondition || iactor2->spr.type == kModernConditionFalse)
 				condError(iactor, "Tracking condition always must be first in condition sequence!");
 
-			if (count >= kMaxTracedObjects)
-				condError(iactor, "Max(%d) objects to track reached for condition #%d, RXID: %d!");
-
-			pCond->obj[count].obj = EventObject(iactor2);
-			pCond->obj[count++].cmd = (uint8_t)iactor2->xspr.command;
+			pCond->objects.Reserve(2);
+			pCond->objects[count].obj = EventObject(iactor2);
+			pCond->objects[count++].cmd = (uint8_t)iactor2->xspr.command;
 		}
 
 		for (auto& sect : sector)
 		{
 			if (!sect.hasX() || sect.xs().txID != iactor->xspr.rxID) continue;
-			else if (count >= kMaxTracedObjects)
-				condError(iactor, "Max(%d) objects to track reached for condition #%d, RXID: %d!");
 
-			pCond->obj[count].obj = EventObject(&sect);
-			pCond->obj[count++].cmd = sect.xs().command;
+			pCond->objects.Reserve(2);
+			pCond->objects[count].obj = EventObject(&sect);
+			pCond->objects[count++].cmd = sect.xs().command;
 		}
 
 		for (auto& wal : wall)
@@ -861,20 +843,15 @@ void nnExtInitModernStuff(TArray<DBloodActor*>& actors)
 				continue;
 			}
 
-			if (count >= kMaxTracedObjects)
-				condError(iactor, "Max(%d) objects to track reached for condition #%d, RXID: %d!");
-
-			pCond->obj[count].obj = EventObject(&wal);
-			pCond->obj[count++].cmd = wal.xw().command;
+			pCond->objects.Reserve(2);
+			pCond->objects[count].obj = EventObject(&wal);
+			pCond->objects[count++].cmd = wal.xw().command;
 		}
 
 		if (iactor->xspr.data1 > kCondGameMax && count == 0)
 			Printf(PRINT_HIGH, "No objects to track found for condition #%d, RXID: %d!", iactor->GetIndex(), iactor->xspr.rxID);
 
-		pCond->length = count;
 		pCond->actor = iactor;
-		gTrackingCondsCount++;
-
 	}
 }
 
@@ -1081,23 +1058,23 @@ static void windGenDoVerticalWind(int factor, sectortype* pSector)
 void nnExtProcessSuperSprites()
 {
 	// process tracking conditions
-	if (gTrackingCondsCount > 0)
+	if (gConditions.Size() > 0)
 	{
-		for (int i = 0; i < gTrackingCondsCount; i++)
+		for (unsigned i = 0; i < gConditions.Size(); i++)
 		{
-			TRCONDITION const* pCond = &gCondition[i];
+			TRCONDITION const* pCond = &gConditions[i];
 			auto aCond = pCond->actor;
 			if (aCond->xspr.locked || aCond->xspr.isTriggered || ++aCond->xspr.busy < aCond->xspr.busyTime)
 				continue;
 
-			if (pCond->length > 0)
+			if (pCond->objects.Size() > 0)
 			{
 				aCond->xspr.busy = 0;
-				for (unsigned k = 0; k < pCond->length; k++)
+				for (unsigned k = 0; k < pCond->objects.Size(); k++)
 				{
 					EVENT evn;
-					evn.target = pCond->obj[k].obj;
-					evn.cmd = pCond->obj[k].cmd;
+					evn.target = pCond->objects[k].obj;
+					evn.cmd = pCond->objects[k].cmd;
 					evn.funcID = kCallbackMax;
 					evn.initiator = nullptr;
 					useCondition(pCond->actor, evn);
@@ -2071,18 +2048,18 @@ void trPlayerCtrlLink(DBloodActor* sourceactor, PLAYER* pPlayer, bool checkCondi
 	// let's check if there is tracking condition expecting objects with this TX id
 	if (checkCondition && sourceactor->xspr.txID >= kChannelUser)
 	{
-		for (int i = 0; i < gTrackingCondsCount; i++)
+		for (unsigned i = 0; i < gConditions.Size(); i++)
 		{
-			TRCONDITION* pCond = &gCondition[i];
+			TRCONDITION* pCond = &gConditions[i];
 			if (pCond->actor->xspr.rxID != sourceactor->xspr.txID)
 				continue;
 
 			// search for player control sprite and replace it with actual player sprite
-			for (unsigned k = 0; k < pCond->length; k++)
+			for (unsigned k = 0; k < pCond->objects.Size(); k++)
 			{
-				if (!pCond->obj[k].obj.isActor() || pCond->obj[k].obj.actor() != sourceactor) continue;
-				pCond->obj[k].obj = EventObject(pPlayer->actor);
-				pCond->obj[k].cmd = (uint8_t)pPlayer->actor->xspr.command;
+				if (!pCond->objects[k].obj.isActor() || pCond->objects[k].obj.actor() != sourceactor) continue;
+				pCond->objects[k].obj = EventObject(pPlayer->actor);
+				pCond->objects[k].cmd = (uint8_t)pPlayer->actor->xspr.command;
 				break;
 			}
 		}
@@ -4813,13 +4790,13 @@ bool condCheckSprite(DBloodActor* aCond, int cmpOp, bool PUSH)
 void conditionsUpdateIndex(DBloodActor* oldActor, DBloodActor* newActor)
 {
 	// update index in tracking conditions first
-	for (int i = 0; i < gTrackingCondsCount; i++)
+	for (unsigned i = 0; i < gConditions.Size(); i++)
 	{
-		TRCONDITION* pCond = &gCondition[i];
-		for (unsigned k = 0; k < pCond->length; k++)
+		TRCONDITION* pCond = &gConditions[i];
+		for (unsigned k = 0; k < pCond->objects.Size(); k++)
 		{
-			if (!pCond->obj[k].obj.isActor() || pCond->obj[k].obj.actor() != oldActor) continue;
-			pCond->obj[k].obj = EventObject(newActor);
+			if (!pCond->objects[k].obj.isActor() || pCond->objects[k].obj.actor() != oldActor) continue;
+			pCond->objects[k].obj = EventObject(newActor);
 			break;
 		}
 	}
@@ -9455,9 +9432,8 @@ FSerializer& Serialize(FSerializer& arc, const char* keyname, TRCONDITION& w, TR
 	if (arc.isReading()) w = {};
 	if (arc.BeginObject(keyname))
 	{
-		arc("length", w.length, &nul.length)
-			("xindex", w.actor, &nul.actor)
-			.Array("obj", w.obj, w.length)
+		arc("xindex", w.actor, &nul.actor)
+			("obj", w.objects)
 			.EndObject();
 	}
 	return arc;
@@ -9476,8 +9452,7 @@ void SerializeNNExts(FSerializer& arc)
 			("impactspritescount", gImpactSpritesCount)
 			.Array("impactspriteslist", gImpactSpritesList, gImpactSpritesCount)
 			("eventredirects", gEventRedirectsUsed)
-			("trconditioncount", gTrackingCondsCount)
-			.Array("trcondition", gCondition, gTrackingCondsCount);
+			("trcondition", gConditions);
 		gSprNSect.Serialize(arc);
 		arc.EndObject();
 	}
diff --git a/source/games/blood/src/nnexts.h b/source/games/blood/src/nnexts.h
index a4dc2a774..0634dd7e4 100644
--- a/source/games/blood/src/nnexts.h
+++ b/source/games/blood/src/nnexts.h
@@ -244,8 +244,7 @@ struct OBJECTS_TO_TRACK {
 
 struct TRCONDITION {
 	DBloodActor* actor;
-	uint8_t length;
-	OBJECTS_TO_TRACK obj[kMaxTracedObjects];
+	TArray<OBJECTS_TO_TRACK> objects;
 };
 
 struct PATROL_FOUND_SOUNDS {
@@ -275,7 +274,7 @@ extern const VECTORINFO_EXTRA gVectorInfoExtra[kVectorMax];
 extern const MISSILEINFO_EXTRA gMissileInfoExtra[kMissileMax];
 extern const DUDEINFO_EXTRA gDudeInfoExtra[kDudeMax];
 extern TRPLAYERCTRL gPlayerCtrl[kMaxPlayers];
-extern TRCONDITION gCondition[kMaxTrackingConditions];
+extern TArray<TRCONDITION> gConditions;
 inline TObjPtr<DBloodActor*> gProxySpritesList[kMaxSuperXSprites];
 inline TObjPtr<DBloodActor*> gSightSpritesList[kMaxSuperXSprites];
 inline TObjPtr<DBloodActor*> gPhysSpritesList[kMaxSuperXSprites];
@@ -284,7 +283,6 @@ inline int gProxySpritesCount;
 inline int gSightSpritesCount;
 inline int gPhysSpritesCount;
 inline int gImpactSpritesCount;
-extern int gTrackingCondsCount;
 extern AISTATE genPatrolStates[kPatrolStateSize];