Maelstrom: Removed gNumPlayers since we will be able to have a sparse player array.

https://github.com/libsdl-org/Maelstrom/commit/909055a684c27e086960fe9d923cb88560bf8926

From 909055a684c27e086960fe9d923cb88560bf8926 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Sat, 19 Nov 2011 20:34:52 -0500
Subject: [PATCH] Removed gNumPlayers since we will be able to have a sparse
 player array.

---
 game/game.cpp     | 121 ++++++++++++++++++++++++++++++++++------------
 game/gameinfo.cpp |  18 +++++++
 game/gameinfo.h   |   2 +
 game/make.cpp     |  12 ++++-
 game/netplay.cpp  |  17 ++++---
 game/netplay.h    |   1 -
 game/objects.h    |  38 ++++++++++-----
 game/player.cpp   |  32 +++++++++---
 game/player.h     |  10 ++++
 game/shinobi.h    |  21 ++++----
 10 files changed, 202 insertions(+), 70 deletions(-)

diff --git a/game/game.cpp b/game/game.cpp
index be66e008..e4de1107 100644
--- a/game/game.cpp
+++ b/game/game.cpp
@@ -71,8 +71,8 @@ void NewGame(void)
 	SeedRandom(gGameInfo.seed);
 
 	/* Send a "NEW_GAME" packet onto the network */
-	if ( gNumPlayers > 1 ) {
-		if ( gOurPlayer == 0 ) {
+	if ( gGameInfo.IsMultiplayer() ) {
+		if ( gGameInfo.IsHosting() ) {
 			if ( Send_NewGame() < 0)
 				return;
 		} else {
@@ -80,6 +80,13 @@ void NewGame(void)
 				return;
 		}
 	}
+	for (int i = 0; i < MAX_PLAYERS; ++i) {
+		if (gGameInfo.IsValidPlayer(i)) {
+			gPlayers[i]->SetControlType(gGameInfo.GetPlayer(i)->controlMask);
+		} else {
+			gPlayers[i]->SetControlType(CONTROL_NONE);
+		}
+	}
 
 	ui->ShowPanel(PANEL_GAME);
 #ifdef USE_TOUCHCONTROL
@@ -154,13 +161,17 @@ GamePanelDelegate::OnShow()
 	gGameOn = 1;
 	gPaused = 0;
 	gWave = gGameInfo.wave - 1;
-	for ( i=gNumPlayers; i--; )
+	OBJ_LOOP(i, MAX_PLAYERS) {
+		if (!gPlayers[i]->IsValid()) {
+			continue;
+		}
 		gPlayers[i]->NewGame(gGameInfo.lives, gGameInfo.deathMatch);
+	}
 	gLastStar = STAR_DELAY;
 	gLastDrawn = 0L;
 	gNumSprites = 0;
 
-	if ( gNumPlayers > 1 ) {
+	if ( gGameInfo.IsMultiplayer() ) {
 		if (m_multiplayerCaption) {
 			m_multiplayerCaption->Show();
 		}
@@ -228,8 +239,12 @@ GamePanelDelegate::OnTick()
 		gGameOn = 0;
 		return;
 	}
-	OBJ_LOOP(i, gNumPlayers)
+	OBJ_LOOP(i, MAX_PLAYERS) {
+		if (!gPlayers[i]->IsValid()) {
+			continue;
+		}
 		gPlayers[i]->HandleKeys();
+	}
 
 	if ( gPaused ) {
 		return;
@@ -248,7 +263,10 @@ GamePanelDelegate::OnTick()
 	}
 
 	/* -- Do all hit detection */
-	OBJ_LOOP(j, gNumPlayers) {
+	OBJ_LOOP(j, MAX_PLAYERS) {
+		if (!gPlayers[j]->IsValid()) {
+			continue;
+		}
 		if ( ! gPlayers[j]->Alive() )
 			continue;
 
@@ -264,7 +282,10 @@ GamePanelDelegate::OnTick()
 			}
 		}
 		if ( gGameInfo.deathMatch ) {
-			OBJ_LOOP(i, gNumPlayers) {
+			OBJ_LOOP(i, MAX_PLAYERS) {
+				if (!gPlayers[i]->IsValid()) {
+					continue;
+				}
 				if ( i == j )	// Don't shoot ourselves. :)
 					continue;
 				(void) gPlayers[i]->HitBy(gPlayers[j]);
@@ -272,7 +293,10 @@ GamePanelDelegate::OnTick()
 		}
 	}
 	if ( gEnemySprite ) {
-		OBJ_LOOP(i, gNumPlayers) {
+		OBJ_LOOP(i, MAX_PLAYERS) {
+			if (!gPlayers[i]->IsValid()) {
+				continue;
+			}
 			if ( ! gPlayers[i]->Alive() )
 				continue;
 			(void) gPlayers[i]->HitBy(gEnemySprite);
@@ -291,7 +315,10 @@ GamePanelDelegate::OnTick()
 	if ( gShakeTime && (gShakeTime-- > 0) ) {
 		int shakeV;
 
-		OBJ_LOOP(i, gNumPlayers) {
+		OBJ_LOOP(i, MAX_PLAYERS) {
+			if (!gPlayers[i]->IsValid()) {
+				continue;
+			}
 			shakeV = FastRandom(SHAKE_FACTOR);
 			if ( ! gPlayers[i]->Alive() )
 				continue;
@@ -304,8 +331,12 @@ GamePanelDelegate::OnTick()
 	}
 
 	/* -- Move all of the sprites */
-	OBJ_LOOP(i, gNumPlayers)
+	OBJ_LOOP(i, MAX_PLAYERS) {
+		if (!gPlayers[i]->IsValid()) {
+			continue;
+		}
 		gPlayers[i]->Move(0);
+	}
 	OBJ_LOOP(i, gNumSprites) {
 		if ( gSprites[i]->Move(gFreezeTime) < 0 ) {
 			delete gSprites[i];
@@ -339,13 +370,21 @@ GamePanelDelegate::OnDraw()
 	/* -- Blit all the sprites */
 	OBJ_LOOP(i, gNumSprites)
 		gSprites[i]->BlitSprite();
-	OBJ_LOOP(i, gNumPlayers)
+	OBJ_LOOP(i, MAX_PLAYERS) {
+		if (!gPlayers[i]->IsValid()) {
+			continue;
+		}
 		gPlayers[i]->BlitSprite();
+	}
 
 	/* -- Show the player dots */
-	if ( gNumPlayers > 1 ) {
-		OBJ_LOOP(i, gNumPlayers)
+	if ( gGameInfo.IsMultiplayer() ) {
+		OBJ_LOOP(i, MAX_PLAYERS) {
+			if (!gPlayers[i]->IsValid()) {
+				continue;
+			}
 			gPlayers[i]->ShowDot();
+		}
 	}
 }
 
@@ -364,12 +403,12 @@ GamePanelDelegate::DrawStatus(Bool first)
 /* -- Draw the status display */
 
 	if (first && gWave == 1) {
-		OBJ_LOOP(i, gNumPlayers) {
+		OBJ_LOOP(i, MAX_PLAYERS) {
 			lastLife[i] = lastScores[i] = 0;
 		}
 	}
 
-	if ( gNumPlayers > 1 ) {
+	if ( gGameInfo.IsMultiplayer() ) {
 		char caption[BUFSIZ];
 
 		sprintf(caption, "You are player %d --- displaying player %d",
@@ -443,7 +482,10 @@ GamePanelDelegate::DrawStatus(Bool first)
 	}
 
 	/* Check for everyone else's new lives */
-	OBJ_LOOP(i, gNumPlayers) {
+	OBJ_LOOP(i, MAX_PLAYERS) {
+		if (!gPlayers[i]->IsValid()) {
+			continue;
+		}
 		Score = gPlayers[i]->GetScore();
 
 		if ( i == gDisplayed && m_score ) {
@@ -537,7 +579,10 @@ GamePanelDelegate::DoHousekeeping()
 
 	/* -- Make sure someone is still playing... */
 	bool PlayersLeft = false;
-	for ( i=0; i < gNumPlayers; ++i ) {
+	OBJ_LOOP(i, MAX_PLAYERS) {
+		if (!gPlayers[i]->IsValid()) {
+			continue;
+		}
 		if ( gPlayers[i]->Kicking() ) {
 			PlayersLeft = true;
 			break;
@@ -605,7 +650,10 @@ GamePanelDelegate::DoBonus()
 
 	bonus = panel->GetElement<UIElement>("bonus");
 	score = panel->GetElement<UIElement>("score");
-	OBJ_LOOP(i, gNumPlayers) {
+	OBJ_LOOP(i, MAX_PLAYERS) {
+		if (!gPlayers[i]->IsValid()) {
+			continue;
+		}
 		if ( i != gOurPlayer ) {
 			gPlayers[i]->MultBonus();
 			continue;
@@ -662,7 +710,10 @@ GamePanelDelegate::DoBonus()
 		Delay(SOUND_DELAY);
 
 	/* -- Count the score down */
-	OBJ_LOOP(i, gNumPlayers) {
+	OBJ_LOOP(i, MAX_PLAYERS) {
+		if (!gPlayers[i]->IsValid()) {
+			continue;
+		}
 		if ( i != gOurPlayer ) {
 			while ( gPlayers[i]->GetBonus() > 500 ) {
 				gPlayers[i]->IncrScore(500);
@@ -726,7 +777,7 @@ GamePanelDelegate::DoBonus()
 void
 GamePanelDelegate::NextWave()
 {
-	int	index, x, y;
+	int	i, x, y;
 	int	NewRoids;
 	short	temp;
 
@@ -809,12 +860,16 @@ GamePanelDelegate::NextWave()
 	gWhenDone = 0;
 
 	/* -- Create the ship's sprite */
-	for ( index=gNumPlayers; index--; )
-		gPlayers[index]->NewWave();
+	OBJ_LOOP(i, MAX_PLAYERS) {
+		if (!gPlayers[i]->IsValid()) {
+			continue;
+		}
+		gPlayers[i]->NewWave();
+	}
 	DrawStatus(true);
 
 	/* -- Create some asteroids */
-	for (index = 0; index < NewRoids; index++) {
+	for (i = 0; i < NewRoids; i++) {
 		int	randval;
 	
 		x = FastRandom(SCREEN_WIDTH) * SCALE_FACTOR;
@@ -862,16 +917,16 @@ static void DoGameOver(void)
 	Bool done = false;
 
 	/* Get the final scoring */
-	struct FinalScore *final = new struct FinalScore[gNumPlayers];
-	for ( i=0; i<gNumPlayers; ++i ) {
+	struct FinalScore *final = new struct FinalScore[MAX_PLAYERS];
+	for ( i=0; i<MAX_PLAYERS; ++i ) {
 		final[i].Player = i+1;
 		final[i].Score = gPlayers[i]->GetScore();
 		final[i].Frags = gPlayers[i]->GetFrags();
 	}
 	if ( gGameInfo.deathMatch )
-		qsort(final,gNumPlayers,sizeof(struct FinalScore),cmp_byfrags);
+		qsort(final,MAX_PLAYERS,sizeof(struct FinalScore),cmp_byfrags);
 	else
-		qsort(final,gNumPlayers,sizeof(struct FinalScore),cmp_byscore);
+		qsort(final,MAX_PLAYERS,sizeof(struct FinalScore),cmp_byscore);
 
 	panel = ui->GetPanel(PANEL_GAMEOVER);
 	if (!panel) {
@@ -885,8 +940,12 @@ static void DoGameOver(void)
 	}
 
 	/* Show the player ranking */
-	if ( gNumPlayers > 1 ) {
-		for ( i=0; i<gNumPlayers; ++i ) {
+	if ( gGameInfo.IsMultiplayer() ) {
+		OBJ_LOOP(i, MAX_PLAYERS) {
+			if (!gPlayers[i]->IsValid()) {
+				continue;
+			}
+
 			char name[32];
 			char buffer[BUFSIZ], num1[12], num2[12];
 
@@ -927,7 +986,7 @@ static void DoGameOver(void)
 	/* -- They got a high score! */
 	gLastHigh = which;
 
-	if ((which != -1) && (gNumPlayers == 1) &&
+	if ((which != -1) && !gGameInfo.IsMultiplayer() &&
 			(gGameInfo.wave == 1) && (gGameInfo.lives == 3)) {
 		sound->PlaySound(gBonusShot, 5);
 
@@ -1007,7 +1066,7 @@ static void DoGameOver(void)
 		sound->PlaySound(gGotPrize, 6);
 		SaveScores();
 	} else
-	if ( gNumPlayers > 1 )	/* Let them watch their ranking */
+	if ( gGameInfo.IsMultiplayer() )	/* Let them watch their ranking */
 		SDL_Delay(3000);
 
 	while ( sound->Playing() )
diff --git a/game/gameinfo.cpp b/game/gameinfo.cpp
index c7643a49..2059b22a 100644
--- a/game/gameinfo.cpp
+++ b/game/gameinfo.cpp
@@ -317,6 +317,12 @@ GameInfo::IsHosting() const
 	return localID == gameID;
 }
 
+bool
+GameInfo::IsMultiplayer() const
+{
+	return (GetNumPlayers() > 1);
+}
+
 bool
 GameInfo::IsLocalNode(int index) const
 {
@@ -362,6 +368,18 @@ GameInfo::IsNetworkPlayer(int index) const
 	return (players[index].nodeID != localID);
 }
 
+int
+GameInfo::GetNumPlayers() const
+{
+	int numPlayers = 0;
+	for (int i = 0; i < MAX_PLAYERS; ++i) {
+		if (players[i].nodeID) {
+			++numPlayers;
+		}
+	}
+	return numPlayers;
+}
+
 bool
 GameInfo::IsFull() const
 {
diff --git a/game/gameinfo.h b/game/gameinfo.h
index 372baa9c..ae2b9ded 100644
--- a/game/gameinfo.h
+++ b/game/gameinfo.h
@@ -148,12 +148,14 @@ class GameInfo
 	void RemovePlayer(int index);
 
 	bool IsHosting() const;
+	bool IsMultiplayer() const;
 	bool IsLocalNode(int index) const;
 	bool IsNetworkNode(int index) const;
 
 	bool IsValidPlayer(int index) const;
 	bool IsLocalPlayer(int index) const;
 	bool IsNetworkPlayer(int index) const;
+	int GetNumPlayers() const;
 
 	bool IsFull() const;
 
diff --git a/game/make.cpp b/game/make.cpp
index 0a0d7ea9..d20abb82 100644
--- a/game/make.cpp
+++ b/game/make.cpp
@@ -135,7 +135,11 @@ void MakeNova(void)
 
 // -- Make sure it isn't appearing right next to the ship
 
-	for ( i=gNumPlayers; i--; ) {
+	OBJ_LOOP(i, MAX_PLAYERS) {
+		if (!gPlayers[i]->IsValid()) {
+			continue;
+		}
+
 		int	xDist, yDist;
 	
 		/* Make sure the player is alive. :) */
@@ -266,7 +270,11 @@ void MakeGravity(void)
 	
 	// -- Make sure it isn't appearing right next to the ship
 
-		for ( i=gNumPlayers; i--; ) {
+		OBJ_LOOP(i, MAX_PLAYERS) {
+			if (!gPlayers[i]->IsValid()) {
+				continue;
+			}
+
 			int	xDist, yDist;
 	
 			/* Make sure the player is alive. :) */
diff --git a/game/netplay.cpp b/game/netplay.cpp
index f3d2acad..0d25eb52 100644
--- a/game/netplay.cpp
+++ b/game/netplay.cpp
@@ -108,7 +108,6 @@ int InitNetData(bool hosting)
 	}
 
 	/* Initialize network game variables */
-	gNumPlayers = 0;
 	gOurPlayer  = -1;
 	for ( i=0; i<MAX_PLAYERS; ++i ) {
 		SyncPtrs[0][i] = NULL;
@@ -147,22 +146,24 @@ int CheckPlayers(void)
 {
 	int i;
 
-	gNumPlayers = 0;
+	if (gGameInfo.GetNumPlayers() == 0) {
+		error("No players specified!\r\n");
+		return(-1);
+	}
+
+	gNumPlayers = gGameInfo.GetNumPlayers();
 	gOurPlayer  = -1;
 	for ( i=0; i<MAX_PLAYERS; ++i ) {
 		if (gGameInfo.IsValidPlayer(i)) {
 			if (gGameInfo.IsLocalPlayer(i)) {
-				gOurPlayer = i;
+				if (gOurPlayer < 0) {
+					gOurPlayer = i;
+				}
 			} else {
 				PlayAddr[i] = gGameInfo.GetPlayerAddress(i);
 			}
-			++gNumPlayers;
 		}
 	}
-	if (gNumPlayers == 0) {
-		error("No players specified!\r\n");
-		return(-1);
-	}
 	if (gOurPlayer < 0) {
 		error("Which player are you?\r\n");
 		return(-1);
diff --git a/game/netplay.h b/game/netplay.h
index d44f3289..74e78b72 100644
--- a/game/netplay.h
+++ b/game/netplay.h
@@ -34,5 +34,4 @@ extern int   Await_NewGame();
 
 /* Variables from netplay.cpp */
 extern int	gOurPlayer;
-extern int	gNumPlayers;
 extern UDPsocket gNetFD;
diff --git a/game/objects.h b/game/objects.h
index 881f89df..58a69922 100644
--- a/game/objects.h
+++ b/game/objects.h
@@ -78,8 +78,12 @@ class Prize : public Object {
 						gSprites[i] = gSprites[gNumSprites];
 					}
 				}
-				OBJ_LOOP(i, gNumPlayers)
+				OBJ_LOOP(i, MAX_PLAYERS) {
+					if (!gPlayers[i]->IsValid()) {
+						continue;
+					}
 					gPlayers[i]->CutThrust(SHAKE_DURATION);
+				}
 				gShakeTime = SHAKE_DURATION;
 				break;
 		}
@@ -144,8 +148,12 @@ class Nova : public Object {
 					gSprites[i] = gSprites[gNumSprites];
 				}
 			}
-			OBJ_LOOP(i, gNumPlayers)
+			OBJ_LOOP(i, MAX_PLAYERS) {
+				if (!gPlayers[i]->IsValid()) {
+					continue;
+				}
 				gPlayers[i]->CutThrust(SHAKE_DURATION);
+			}
 			gShakeTime = SHAKE_DURATION;
 		}
 		return(-1);
@@ -298,7 +306,10 @@ class Gravity : public Object {
 			return(Object::Move(Frozen));
 
 		/* Warp the courses of the players */
-		OBJ_LOOP(i, gNumPlayers) {
+		OBJ_LOOP(i, MAX_PLAYERS) {
+			if (!gPlayers[i]->IsValid()) {
+				continue;
+			}
 			int X, Y, xAccel, yAccel;
 
 			if ( ! gPlayers[i]->Alive() )
@@ -337,18 +348,21 @@ class Homing : public Object {
 
 	/* This is duplicated in the Shinobi class */
 	virtual int AcquireTarget(void) {
-		int i, newtarget=(-1);
+		int targets[MAX_PLAYERS];
+		int numTargets = 0;
 
-		for ( i=0; i<gNumPlayers; ++i ) {
-			if ( gPlayers[i]->Alive() )
-				break;
+		for ( int i=0; i < MAX_PLAYERS; ++i ) {
+			if (!gPlayers[i]->IsValid()) {
+				continue;
+			}
+			if ( gPlayers[i]->Alive() ) {
+				targets[numTargets++] = i;
+			}
 		}
-		if ( i != gNumPlayers ) {	// Player(s) alive!
-			do {
-				newtarget = FastRandom(gNumPlayers);
-			} while ( ! gPlayers[newtarget]->Alive() );
+		if (numTargets > 0) {
+			return targets[FastRandom(numTargets)];
 		}
-		return(newtarget);
+		return -1;
 	}
 
 	int Move(int Frozen) {
diff --git a/game/player.cpp b/game/player.cpp
index 4b2ad845..ebe6062e 100644
--- a/game/player.cpp
+++ b/game/player.cpp
@@ -50,6 +50,7 @@ Player:: Player(int index) : Object(0, 0, 0, 0, gPlayerShip, NO_PHASE_CHANGE)
 {
 	int i;
 
+	Valid = 0;
 	Index = index;
 	Score = 0;
 	for ( i=0; i<MAX_SHOTS; ++i ) {
@@ -103,8 +104,7 @@ Player::NewWave(void)
 	WasShielded = 0;
 	Sphase = 0;
 	SetPos(
-		((SCREEN_WIDTH/2-((gNumPlayers/2-Index)*(2*SPRITES_WIDTH)))
-							*SCALE_FACTOR),
+		((SCREEN_WIDTH/2-((gGameInfo.GetNumPlayers()/2-Index)*(2*SPRITES_WIDTH)))*SCALE_FACTOR),
 		((SCREEN_HEIGHT/2)*SCALE_FACTOR)
 	);
 	xvec = yvec = 0;
@@ -159,7 +159,10 @@ Player::IncrFrags(void)
 	if ( gGameInfo.deathMatch && (Frags >= gGameInfo.deathMatch) ) {
 		/* Game over, we got a stud. :) */
 		int i;
-		OBJ_LOOP(i, gNumPlayers) {
+		OBJ_LOOP(i, MAX_PLAYERS) {
+			if (!gPlayers[i]->IsValid()) {
+				continue;
+			}
 			gPlayers[i]->IncrLives(-1);
 			gPlayers[i]->Explode();
 #ifdef DEBUG
@@ -241,8 +244,7 @@ Player::BeenTimedOut(void)
 {
 	Exploding = 0;
 	SetPos(
-		((SCREEN_WIDTH/2-((gNumPlayers/2-Index)*(2*SPRITES_WIDTH)))
-							*SCALE_FACTOR),
+		((SCREEN_WIDTH/2-((gGameInfo.GetNumPlayers()/2-Index)*(2*SPRITES_WIDTH)))*SCALE_FACTOR),
 		((SCREEN_HEIGHT/2)*SCALE_FACTOR)
 	);
 	if ( gGameInfo.deathMatch )
@@ -647,6 +649,17 @@ Player::ExplodeSound(void)
 	sound->PlaySound(gShipHitSound, 3);
 }
 
+void
+Player::SetControlType(Uint8 controlType)
+{
+	if (controlType == CONTROL_NONE) {
+		Valid = 0;
+	} else {
+		Valid = 1;
+	}
+	this->controlType = controlType;
+}
+
 void
 Player::SetControl(unsigned char which, int toggle)
 {
@@ -745,6 +758,11 @@ int InitPlayerSprites(void)
 /* Function to switch the displayed player */
 void RotatePlayerView()
 {
-	if ( ++gDisplayed == gNumPlayers )
-		gDisplayed = 0;
+	for (int i = 0; i < MAX_PLAYERS; ++i) {
+		if ( ++gDisplayed == MAX_PLAYERS )
+			gDisplayed = 0;
+
+		if (gPlayers[gDisplayed]->IsValid())
+			break;
+	}
 }
diff --git a/game/player.h b/game/player.h
index f7fdffc5..f468341b 100644
--- a/game/player.h
+++ b/game/player.h
@@ -37,6 +37,9 @@ class Player : public Object {
 	Player(int index);
 	~Player();
 
+	virtual int IsValid(void) {
+		return(Valid);
+	}
 	virtual int IsPlayer(void) {
 		return(1);
 	}
@@ -134,9 +137,14 @@ class Player : public Object {
 		}
 	}
 
+	void SetControlType(Uint8 controlType);
+	Uint8 GetControlType() {
+		return controlType;
+	}
 	void SetControl(unsigned char which, int toggle);
 
 private:
+	int Valid;
 	int Index;
 	int Lives;
 	int Score;
@@ -167,6 +175,8 @@ class Player : public Object {
 	int numshots;
 	Uint32 ship_color;
 
+	Uint8 controlType;
+
 	/* Create a new shot */
 	int MakeShot(int offset);
 	/* Rubout a flying shot */
diff --git a/game/shinobi.h b/game/shinobi.h
index 9675abdb..6157fe2a 100644
--- a/game/shinobi.h
+++ b/game/shinobi.h
@@ -51,18 +51,21 @@ class Shinobi : public Object {
 
 	/* This is duplicated in the Homing class */
 	virtual int AcquireTarget(void) {
-		int i, newtarget=(-1);
+		int targets[MAX_PLAYERS];
+		int numTargets = 0;
 
-		for ( i=0; i<gNumPlayers; ++i ) {
-			if ( gPlayers[i]->Alive() )
-				break;
+		for ( int i=0; i < MAX_PLAYERS; ++i ) {
+			if (!gPlayers[i]->IsValid()) {
+				continue;
+			}
+			if ( gPlayers[i]->Alive() ) {
+				targets[numTargets++] = i;
+			}
 		}
-		if ( i != gNumPlayers ) {	// Player(s) alive!
-			do {
-				newtarget = FastRandom(gNumPlayers);
-			} while ( ! gPlayers[newtarget]->Alive() );
+		if (numTargets > 0) {
+			return targets[FastRandom(numTargets)];
 		}
-		return(newtarget);
+		return -1;
 	}