//Queen Command.c

#ifdef PRECOMPILEDHEADERS
	#include "Strategic All.h"
	#include "GameSettings.h"
#else
	#include "Queen Command.h"
	#include "Strategic Event Handler.h"
	#include "Overhead Types.h"
	#include "strategicmap.h"
	#include "Soldier Init List.h"
	#include "debug.h"
	#include "Random.h"
	#include "Strategic Movement.h"
	#include "Overhead.h"
	#include "Strategic Pathing.h"
	#include "strategic.h"
	#include "message.h"
	#include "Map Edgepoints.h"
	#include "PreBattle Interface.h"
	#include "strategic status.h"
	#include "squads.h"
	#include "assignments.h"
	#include "items.h"
	#include "tactical save.h"
	#include "Soldier Ani.h"
	#include "Strategic AI.h"
	#include "GameSettings.h"
	#include "MessageBoxScreen.h"
	#include "screenids.h"
	#include "Strategic Town Loyalty.h"
	#include "Soldier Profile.h"
	#include "Quests.h"
	#include "jascreens.h"
	#include "Auto Resolve.h"
	#include "Game Event Hook.h"
	#include "Animation Data.h"
	#include "Game Clock.h"
	#include "renderworld.h"
	#include "Town Militia.h"
	#include "Dialogue Control.h"
	#include "Campaign Init.h"
	#include "meanwhile.h"
	#include "Soldier macros.h"
	#include "Morale.h"
	#include "CampaignStats.h"		// added by Flugente
	#include "ASD.h"				// added by Flugente
#endif

#ifdef JA2BETAVERSION
	extern BOOLEAN gfClearCreatureQuest;
#endif

#include "connect.h"
#include "Reinforcement.h"
#include "MilitiaSquads.h"

#ifdef JA2UB
#include "Explosion Control.h"
#include "Ja25_Tactical.h"
#include "Ja25 Strategic Ai.h"
#include "MapScreen Quotes.h"
#include "email.h"
#include "interface Dialogue.h"
#include "Arms Dealer Init.h"
#endif

#include "GameInitOptionsScreen.h"

#include <vector>

//The sector information required for the strategic AI.  Contains the number of enemy troops,
//as well as intentions, etc.
//SECTORINFO SectorInfo[256];
std::vector<SECTORINFO> SectorInfo (256);

UNDERGROUND_SECTORINFO *gpUndergroundSectorInfoHead = NULL;
extern UNDERGROUND_SECTORINFO* gpUndergroundSectorInfoTail;
BOOLEAN gfPendingNonPlayerTeam[PLAYER_PLAN] = {FALSE, FALSE, FALSE, FALSE, FALSE};
UINT32 guiTurnCnt = 0, guiReinforceTurn = 0, guiArrived = 0;//dnl ch68 080913
extern void BuildUndergroundSectorInfoList();

extern void EndCreatureQuest();

extern GARRISON_GROUP *gGarrisonGroup;
extern INT32 giGarrisonArraySize;

#ifdef JA2TESTVERSION
extern BOOLEAN gfOverrideSector;
#endif

//Buggler: Externalized to gModSettings.iMeanwhileInterrogatePOWGridNo
//INT32 gsInterrogationGridNo[3] = { 7756, 7757, 7758 };

#ifdef JA2UB
INT32		gsGridNoForMapEdgePointInfo=-1;
#endif

#ifdef JA2UB
void HandleBloodCatDeaths( SECTORINFO *pSector );
#endif

extern void Ensure_RepairedGarrisonGroup( GARRISON_GROUP **ppGarrison, INT32 *pGarraySize );


void ValidateEnemiesHaveWeapons()
{
	#ifdef JA2BETAVERSION
		SGPRect CenteringRect= {0 + xResOffset, 0, SCREEN_WIDTH - xResOffset, SCREEN_HEIGHT };
		INT32 i, iErrorDialog;
		SOLDIERTYPE *pSoldier;
		INT32 iNumInvalid = 0;

		for( i = gTacticalStatus.Team[ ENEMY_TEAM ].bFirstID; i <= gTacticalStatus.Team[ ENEMY_TEAM ].bLastID; ++i )
		{
			pSoldier = MercPtrs[ i ];
			if( !pSoldier->bActive || !pSoldier->bInSector )
			{
				continue;
			}

			// Flugente: zombies are fine with having no weapons...
			if ( pSoldier->IsZombie() )
				continue;

			if( !pSoldier->inv[ HANDPOS ].usItem )
			{
				++iNumInvalid;
			}
			// WDS DEBUG
			// Uncommenting the following two lines will cause all the PLACED soldiers to instantly drop dead, 
			// which is useful for debugging some things
			//pSoldier->bBleeding = 10;
			//pSoldier->stats.bLife = 1;
		}

		// do message box and return
		if( iNumInvalid )
		{
			CHAR16 str[ 100 ];
			swprintf( str, L"%d enemies have been added without any weapons!  KM:0.  Please note sector.", iNumInvalid );
			iErrorDialog = DoMessageBox( MSG_BOX_BASIC_STYLE, str, GAME_SCREEN, MSG_BOX_FLAG_OK, NULL, &CenteringRect );
		}
	#endif
}

//Counts enemies and crepitus, but not bloodcats.
UINT8 NumHostilesInSector( INT16 sSectorX, INT16 sSectorY, INT16 sSectorZ )
{
	UINT8 ubNumHostiles = 0;

	AssertGE( sSectorX, MINIMUM_VALID_X_COORDINATE);
	AssertLE( sSectorX, MAXIMUM_VALID_X_COORDINATE );
	AssertGE( sSectorY, MINIMUM_VALID_Y_COORDINATE);
	AssertLE( sSectorY, MAXIMUM_VALID_Y_COORDINATE );
	AssertGE( sSectorZ, MINIMUM_VALID_Z_COORDINATE );
	AssertLE( sSectorZ, MAXIMUM_VALID_Z_COORDINATE );

	if( sSectorZ )
	{
		UNDERGROUND_SECTORINFO *pSector;
		pSector = FindUnderGroundSector( sSectorX, sSectorY, (UINT8)sSectorZ );
		if( pSector )
		{
			ubNumHostiles = (UINT8)(pSector->ubNumAdmins + pSector->ubNumTroops + pSector->ubNumElites + pSector->ubNumCreatures + pSector->ubNumRobots + pSector->ubNumJeeps + pSector->ubNumTanks);
		}
	}
	else
	{
		SECTORINFO *pSector;
		GROUP *pGroup;

		//Count stationary hostiles
		pSector = &SectorInfo[ SECTOR( sSectorX, sSectorY ) ];
		ubNumHostiles = (UINT8)(pSector->ubNumAdmins + pSector->ubNumTroops + pSector->ubNumElites + pSector->ubNumCreatures + pSector->ubNumRobots + pSector->ubNumJeeps + pSector->ubNumTanks);

		//Count mobile enemies
		pGroup = gpGroupList;
		while( pGroup )
		{
			if ( pGroup->usGroupTeam != OUR_TEAM && pGroup->usGroupTeam != MILITIA_TEAM && !pGroup->fVehicle && pGroup->ubSectorX == sSectorX && pGroup->ubSectorY == sSectorY )
			{
				ubNumHostiles += pGroup->ubGroupSize;
			}
			pGroup = pGroup->next;
		}
	}

	return ubNumHostiles;
}

UINT8 NumEnemiesInAnySector( INT16 sSectorX, INT16 sSectorY, INT16 sSectorZ )
{
	UINT8 ubNumEnemies = 0;

	AssertGE( sSectorX, MINIMUM_VALID_X_COORDINATE);
	AssertLE( sSectorX, MAXIMUM_VALID_X_COORDINATE );
	AssertGE( sSectorY, MINIMUM_VALID_Y_COORDINATE);
	AssertLE( sSectorY, MAXIMUM_VALID_Y_COORDINATE );
	AssertGE( sSectorZ, MINIMUM_VALID_Z_COORDINATE );
	AssertLE( sSectorZ, MAXIMUM_VALID_Z_COORDINATE );

	if( sSectorZ )
	{
		UNDERGROUND_SECTORINFO *pSector;
		pSector = FindUnderGroundSector( sSectorX, sSectorY, (UINT8)sSectorZ );
		if( pSector )
		{
			ubNumEnemies = (UINT8)(pSector->ubNumAdmins + pSector->ubNumTroops + pSector->ubNumElites + pSector->ubNumRobots + pSector->ubNumJeeps + pSector->ubNumTanks);
		}
	}
	else
	{
		SECTORINFO *pSector;
		GROUP *pGroup;

		//Count stationary enemies
		pSector = &SectorInfo[ SECTOR( sSectorX, sSectorY ) ];
		ubNumEnemies = (UINT8)(pSector->ubNumAdmins + pSector->ubNumTroops + pSector->ubNumElites + pSector->ubNumRobots + pSector->ubNumJeeps + pSector->ubNumTanks);

		//Count mobile enemies
		pGroup = gpGroupList;
		while( pGroup )
		{
			if ( pGroup->usGroupTeam != OUR_TEAM && pGroup->usGroupTeam != MILITIA_TEAM && !pGroup->fVehicle && pGroup->ubSectorX == sSectorX && pGroup->ubSectorY == sSectorY )
			{
				ubNumEnemies += pGroup->ubGroupSize;
			}
			pGroup = pGroup->next;
		}
	}

	return ubNumEnemies;
}

// returns how many members of a team are in a sector - not intended for OUR_TEAM!
UINT8 NumNonPlayerTeamMembersInSector( INT16 sSectorX, INT16 sSectorY, UINT8 ubTeam )
{
	SECTORINFO *pSector;
	GROUP *pGroup;
	UINT8 ubNumTroops;

	// HEADROCK: This is a TEMPORARY fix to avoid the assertion error. Not sure this is the best solution,
    // probably isn't. But I need this bit to work.
    if (sSectorX < MINIMUM_VALID_X_COORDINATE ||
        sSectorX > MAXIMUM_VALID_X_COORDINATE ||
        sSectorY < MINIMUM_VALID_Y_COORDINATE ||
        sSectorY > MAXIMUM_VALID_Y_COORDINATE)
    {
        return (0);
    }

	AssertGE( sSectorX, MINIMUM_VALID_X_COORDINATE);
	AssertLE( sSectorX, MAXIMUM_VALID_X_COORDINATE );
	AssertGE( sSectorY, MINIMUM_VALID_Y_COORDINATE);
	AssertLE( sSectorY, MAXIMUM_VALID_Y_COORDINATE );

	pSector = &SectorInfo[ SECTOR( sSectorX, sSectorY ) ];

	if ( ubTeam == ENEMY_TEAM )
	{
		ubNumTroops = (UINT8)(pSector->ubNumAdmins + pSector->ubNumTroops + pSector->ubNumElites + pSector->ubNumRobots + pSector->ubNumJeeps + pSector->ubNumTanks);
	
		if ( is_networked )
			ubNumTroops += numenemyLAN((UINT8)sSectorX,(UINT8)sSectorY ); //hayden
	}
	else if ( ubTeam == MILITIA_TEAM )
	{
		ubNumTroops = (UINT8)(pSector->ubNumberOfCivsAtLevel[0] + pSector->ubNumberOfCivsAtLevel[1] + pSector->ubNumberOfCivsAtLevel[2]);
	}
	else if ( ubTeam == CREATURE_TEAM )
	{
		ubNumTroops = pSector->ubNumCreatures;
	}

	pGroup = gpGroupList;
	while( pGroup )
	{
		if ( pGroup->usGroupTeam == ubTeam && !pGroup->fVehicle && pGroup->ubSectorX == sSectorX && pGroup->ubSectorY == sSectorY )
		{
			ubNumTroops += pGroup->ubGroupSize;
		}
		pGroup = pGroup->next;
	}

	return ubNumTroops;
}

// returns how many members of a team are in a sector - only intended for OUR_TEAM! POWs not included
UINT16 NumPlayerTeamMembersInSector( INT16 sSectorX, INT16 sSectorY, INT8 sSectorZ )
{
	UINT16 teammemberspresent = 0;

	SOLDIERTYPE*		pTeamSoldier = NULL;
	UINT16				bMercID = gTacticalStatus.Team[gbPlayerNum].bFirstID;
	UINT16				bLastTeamID = gTacticalStatus.Team[gbPlayerNum].bLastID;
	for ( pTeamSoldier = MercPtrs[bMercID]; bMercID <= bLastTeamID; ++bMercID, pTeamSoldier++ )
	{
		// we test several conditions before we allow adding an opinion
		// other merc must be active, have a profile, be someone else and not be in transit or dead
		if ( pTeamSoldier->bActive && !pTeamSoldier->flags.fBetweenSectors  && pTeamSoldier->stats.bLife > 0 && !(pTeamSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE) &&
			 !(pTeamSoldier->bAssignment == IN_TRANSIT || pTeamSoldier->bAssignment == ASSIGNMENT_DEAD || pTeamSoldier->bAssignment == ASSIGNMENT_POW || pTeamSoldier->bAssignment == ASSIGNMENT_MINIEVENT) &&
			 (pTeamSoldier->sSectorX == sSectorX && pTeamSoldier->sSectorY == sSectorY && pTeamSoldier->bSectorZ == sSectorZ) )
		{
			++teammemberspresent;
		}
	}

	return teammemberspresent;
}

UINT16 NumEnemyArmedVehiclesInSector( INT16 sSectorX, INT16 sSectorY, UINT8 usTeam )
{
	SECTORINFO *pSector;
	GROUP *pGroup;
	UINT16 ubNum;

	// HEADROCK: This is a TEMPORARY fix to avoid the assertion error. Not sure this is the best solution,
	// probably isn't. But I need this bit to work.
	if ( sSectorX < MINIMUM_VALID_X_COORDINATE ||
		 sSectorX > MAXIMUM_VALID_X_COORDINATE ||
		 sSectorY < MINIMUM_VALID_Y_COORDINATE ||
		 sSectorY > MAXIMUM_VALID_Y_COORDINATE )
	{
		return (0);
	}

	AssertGE( sSectorX, MINIMUM_VALID_X_COORDINATE );
	AssertLE( sSectorX, MAXIMUM_VALID_X_COORDINATE );
	AssertGE( sSectorY, MINIMUM_VALID_Y_COORDINATE );
	AssertLE( sSectorY, MAXIMUM_VALID_Y_COORDINATE );

	pSector = &SectorInfo[SECTOR( sSectorX, sSectorY )];

	if ( usTeam == ENEMY_TEAM )
		ubNum = (UINT16)(pSector->ubNumTanks + pSector->ubNumJeeps);
	
	pGroup = gpGroupList;
	while ( pGroup )
	{
		if ( pGroup->usGroupTeam == usTeam && !pGroup->fVehicle && pGroup->ubSectorX == sSectorX && pGroup->ubSectorY == sSectorY )
		{
			ubNum += pGroup->pEnemyGroup->ubNumTanks + pGroup->pEnemyGroup->ubNumJeeps;
		}
		pGroup = pGroup->next;
	}

	return ubNum;
}

UINT8 NumStationaryEnemiesInSector( INT16 sSectorX, INT16 sSectorY )
{
	SECTORINFO *pSector;

	AssertGE( sSectorX, MINIMUM_VALID_X_COORDINATE);
	AssertLE( sSectorX, MAXIMUM_VALID_X_COORDINATE );
	AssertGE( sSectorY, MINIMUM_VALID_Y_COORDINATE);
	AssertLE( sSectorY, MAXIMUM_VALID_Y_COORDINATE );
	pSector = &SectorInfo[ SECTOR( sSectorX, sSectorY ) ];

	if( pSector->ubGarrisonID == NO_GARRISON )
	{ //If no garrison, no stationary.
		return( 0 );
	}

	Ensure_RepairedGarrisonGroup( &gGarrisonGroup, &giGarrisonArraySize );	 /* added NULL fix, 2007-03-03, Sgt. Kolja */

	// don't count roadblocks as stationary garrison, we want to see how many enemies are in them, not question marks
	if ( gGarrisonGroup[ pSector->ubGarrisonID ].ubComposition == ROADBLOCK )
	{
		// pretend they're not stationary
		return( 0 );
	}

	return (UINT8)(pSector->ubNumAdmins + pSector->ubNumTroops + pSector->ubNumElites + pSector->ubNumTanks + pSector->ubNumJeeps + pSector->ubNumRobots);
}

UINT8 NumMobileEnemiesInSector( INT16 sSectorX, INT16 sSectorY )
{
	GROUP *pGroup;
	SECTORINFO *pSector;
	UINT8 ubNumTroops;
	AssertGE( sSectorX, MINIMUM_VALID_X_COORDINATE);
	AssertLE( sSectorX, MAXIMUM_VALID_X_COORDINATE );
	AssertGE( sSectorY, MINIMUM_VALID_Y_COORDINATE);
	AssertLE( sSectorY, MAXIMUM_VALID_Y_COORDINATE );

	ubNumTroops = 0;
	pGroup = gpGroupList;
	while( pGroup )
	{
		if ( pGroup->usGroupTeam != OUR_TEAM && pGroup->usGroupTeam != MILITIA_TEAM && !pGroup->fVehicle && pGroup->ubSectorX == sSectorX && pGroup->ubSectorY == sSectorY )
		{
			ubNumTroops += pGroup->ubGroupSize;
		}
		pGroup = pGroup->next;
	}

	pSector = &SectorInfo[ SECTOR( sSectorX, sSectorY ) ];
	if( pSector->ubGarrisonID == ROADBLOCK )
	{
		//consider these troops as mobile troops even though they are in a garrison
		ubNumTroops += (UINT8)(pSector->ubNumAdmins + pSector->ubNumTroops + pSector->ubNumElites + pSector->ubNumRobots + pSector->ubNumJeeps + pSector->ubNumTanks);
	}

	return ubNumTroops;
}

void GetNumberOfMobileEnemiesInSector( INT16 sSectorX, INT16 sSectorY, UINT8 *pubNumAdmins, UINT8 *pubNumTroops, UINT8 *pubNumElites, UINT8 *pubNumRobots, UINT8 *pubNumTanks, UINT8 *pubNumJeeps )
{
	GROUP *pGroup;
	SECTORINFO *pSector;
	AssertGE( sSectorX, MINIMUM_VALID_X_COORDINATE);
	AssertLE( sSectorX, MAXIMUM_VALID_X_COORDINATE );
	AssertGE( sSectorY, MINIMUM_VALID_Y_COORDINATE);
	AssertLE( sSectorY, MAXIMUM_VALID_Y_COORDINATE );

	//Now count the number of mobile groups in the sector.
	*pubNumTroops = *pubNumElites = *pubNumAdmins = *pubNumRobots = *pubNumTanks = *pubNumJeeps = 0;
	pGroup = gpGroupList;
	while( pGroup )
	{
		if ( pGroup->usGroupTeam != OUR_TEAM && pGroup->usGroupTeam != MILITIA_TEAM && !pGroup->fVehicle && pGroup->ubSectorX == sSectorX && pGroup->ubSectorY == sSectorY )
		{
			*pubNumTroops += pGroup->pEnemyGroup->ubNumTroops;
			*pubNumElites += pGroup->pEnemyGroup->ubNumElites;
			*pubNumAdmins += pGroup->pEnemyGroup->ubNumAdmins;
			*pubNumRobots += pGroup->pEnemyGroup->ubNumRobots;
			*pubNumTanks += pGroup->pEnemyGroup->ubNumTanks;
			*pubNumJeeps += pGroup->pEnemyGroup->ubNumJeeps;
		}
		pGroup = pGroup->next;
	}

	pSector = &SectorInfo[ SECTOR( sSectorX, sSectorY ) ];
	if( pSector->ubGarrisonID == ROADBLOCK )
	{
		//consider these troops as mobile troops even though they are in a garrison
		*pubNumAdmins += pSector->ubNumAdmins;
		*pubNumTroops += pSector->ubNumTroops;
		*pubNumElites += pSector->ubNumElites;
		*pubNumRobots += pSector->ubNumRobots;
		*pubNumTanks += pSector->ubNumTanks;
		*pubNumJeeps += pSector->ubNumJeeps;
	}
}

void GetNumberOfMobileEnemiesInSectorWithoutRoadBlock( INT16 sSectorX, INT16 sSectorY, UINT8 usTeam, UINT8 *pubNumAdmins, UINT8 *pubNumTroops, UINT8 *pubNumElites, UINT8 *pubNumRobots, UINT8 *pubNumTanks, UINT8 *pubNumJeeps )
{
	GROUP *pGroup;
	AssertGE( sSectorX, MINIMUM_VALID_X_COORDINATE);
	AssertLE( sSectorX, MAXIMUM_VALID_X_COORDINATE );
	AssertGE( sSectorY, MINIMUM_VALID_Y_COORDINATE);
	AssertLE( sSectorY, MAXIMUM_VALID_Y_COORDINATE );

	//Now count the number of mobile groups in the sector.
	*pubNumTroops = *pubNumElites = *pubNumAdmins = *pubNumRobots = *pubNumTanks = *pubNumJeeps = 0;
	pGroup = gpGroupList;
	while( pGroup )
	{
		if ( pGroup->usGroupTeam == usTeam && !pGroup->fVehicle && pGroup->ubSectorX == sSectorX && pGroup->ubSectorY == sSectorY )
		{
			*pubNumTroops += pGroup->pEnemyGroup->ubNumTroops;
			*pubNumElites += pGroup->pEnemyGroup->ubNumElites;
			*pubNumAdmins += pGroup->pEnemyGroup->ubNumAdmins;
			*pubNumRobots += pGroup->pEnemyGroup->ubNumRobots;
			*pubNumTanks += pGroup->pEnemyGroup->ubNumTanks;
			*pubNumJeeps += pGroup->pEnemyGroup->ubNumJeeps;
		}
		pGroup = pGroup->next;
	}
}


void GetNumberOfStationaryEnemiesInSector( INT16 sSectorX, INT16 sSectorY, UINT8 *pubNumAdmins, UINT8 *pubNumTroops, UINT8 *pubNumElites, UINT8 *pubNumRobots, UINT8 *pubNumTanks, UINT8 *pubNumJeeps )
{
	SECTORINFO *pSector;
	AssertGE( sSectorX, MINIMUM_VALID_X_COORDINATE);
	AssertLE( sSectorX, MAXIMUM_VALID_X_COORDINATE );
	AssertGE( sSectorY, MINIMUM_VALID_Y_COORDINATE);
	AssertLE( sSectorY, MAXIMUM_VALID_Y_COORDINATE );
	pSector = &SectorInfo[ SECTOR( sSectorX, sSectorY ) ];

	//grab the number of each type in the stationary sector
	*pubNumAdmins = pSector->ubNumAdmins;
	*pubNumTroops = pSector->ubNumTroops;
	*pubNumElites = pSector->ubNumElites;
	*pubNumRobots = pSector->ubNumRobots;
	*pubNumTanks = pSector->ubNumTanks;
	*pubNumJeeps = pSector->ubNumJeeps;
}

void GetNumberOfEnemiesInSector( INT16 sSectorX, INT16 sSectorY, UINT8 *pubNumAdmins, UINT8 *pubNumTroops, UINT8 *pubNumElites, UINT8 *pubNumRobots, UINT8 *pubNumTanks, UINT8 *pubNumJeeps )
{
	UINT8 ubNumAdmins, ubNumTroops, ubNumElites, ubNumRobots, ubNumTanks, ubNumJeeps;

	GetNumberOfStationaryEnemiesInSector( sSectorX, sSectorY, pubNumAdmins, pubNumTroops, pubNumElites, pubNumRobots, pubNumTanks, pubNumJeeps );

	GetNumberOfMobileEnemiesInSector( sSectorX, sSectorY, &ubNumAdmins, &ubNumTroops, &ubNumElites, &ubNumRobots, &ubNumTanks, &ubNumJeeps );

	*pubNumAdmins += ubNumAdmins;
	*pubNumTroops += ubNumTroops;
	*pubNumElites += ubNumElites;
	*pubNumRobots += ubNumRobots;
	*pubNumTanks += ubNumTanks;
	*pubNumJeeps += ubNumJeeps;
}

void EndTacticalBattleForEnemy()
{
	GROUP *pGroup;
	INT32 i;

	//Clear enemies in battle for all stationary groups in the sector.
	if( gbWorldSectorZ > 0 )
	{
		UNDERGROUND_SECTORINFO *pSector;
		pSector = FindUnderGroundSector( gWorldSectorX, gWorldSectorY, gbWorldSectorZ );
		pSector->ubAdminsInBattle = 0;
		pSector->ubTroopsInBattle = 0;
		pSector->ubElitesInBattle = 0;
		pSector->ubRobotsInBattle = 0;
		pSector->ubTanksInBattle = 0;
		pSector->ubJeepsInBattle = 0;
	}
	else if( !gbWorldSectorZ )
	{
		SECTORINFO *pSector;
		pSector = &SectorInfo[ SECTOR( gWorldSectorX, gWorldSectorY ) ];
		//grab the number of each type in the stationary sector
		pSector->ubAdminsInBattle = 0;
		pSector->ubTroopsInBattle = 0;
		pSector->ubElitesInBattle = 0;
		pSector->ubRobotsInBattle = 0;
		pSector->ubTanksInBattle = 0;
		pSector->ubJeepsInBattle = 0;
		pSector->ubNumCreatures = 0;
		pSector->ubCreaturesInBattle = 0;
	}
	else	// negative
		return;

	//Clear this value so that profiled enemies can be added into battles in the future.
	gfProfiledEnemyAdded = FALSE;

	//Clear enemies in battle for all mobile groups in the sector.
	pGroup = gpGroupList;
	while( pGroup )
	{
		if ( pGroup->usGroupTeam == ENEMY_TEAM && !pGroup->fVehicle && pGroup->ubSectorX == gWorldSectorX && pGroup->ubSectorY == gWorldSectorY )
		{
			pGroup->pEnemyGroup->ubTroopsInBattle = 0;
			pGroup->pEnemyGroup->ubElitesInBattle = 0;
			pGroup->pEnemyGroup->ubRobotsInBattle = 0;
			pGroup->pEnemyGroup->ubAdminsInBattle = 0;
			pGroup->pEnemyGroup->ubTanksInBattle = 0;
			pGroup->pEnemyGroup->ubJeepsInBattle = 0;
		}
		pGroup = pGroup->next;
	}


	//Check to see if any of our mercs have abandoned the militia during a battle.  This is cause for a rather
	//severe loyalty blow.
	for( i = gTacticalStatus.Team[ MILITIA_TEAM ].bFirstID; i <= gTacticalStatus.Team[ MILITIA_TEAM ].bLastID; ++i )
	{
		if( MercPtrs[ i ]->bActive && MercPtrs[ i ]->bInSector && MercPtrs[ i ]->stats.bLife >= OKLIFE )
		{ //found one live militia, so look for any enemies/creatures.
			// NOTE: this is relying on ENEMY_TEAM being immediately followed by CREATURE_TEAM
			for( i = gTacticalStatus.Team[ ENEMY_TEAM ].bFirstID; i <= gTacticalStatus.Team[ CREATURE_TEAM ].bLastID; ++i )
			{
				if( MercPtrs[ i ]->bActive && MercPtrs[ i ]->bInSector && MercPtrs[ i ]->stats.bLife >= OKLIFE )
				{ //confirmed at least one enemy here, so do the loyalty penalty.
					HandleGlobalLoyaltyEvent( GLOBAL_LOYALTY_ABANDON_MILITIA, gWorldSectorX, gWorldSectorY, 0 );
					break;
				}
			}
			break;
		}
	}
}

UINT8 NumFreeSlots( UINT8 ubTeam )
{
	UINT8 ubNumFreeSlots = 0;

	//Count the number of free enemy slots.  It is possible to have multiple groups exceed the maximum.
	for ( INT32 i = gTacticalStatus.Team[ubTeam].bFirstID; i <= gTacticalStatus.Team[ubTeam].bLastID; ++i )
	{
		if ( !Menptr[i].bActive )
			++ubNumFreeSlots;
	}

	// the militia team size can be restricted by the ini
	if ( ubTeam == MILITIA_TEAM )
	{
		ubNumFreeSlots = (UINT8)max( 0, (INT8)ubNumFreeSlots - (INT8)(gGameExternalOptions.ubGameMaximumNumberOfRebels - gGameExternalOptions.iMaxMilitiaPerSector) );
	}

	return ubNumFreeSlots;
}


//Called when entering a sector so the campaign AI can automatically insert the
//correct number of troops of each type based on the current number in the sector
//in global focus (gWorldSectorX/Y)
BOOLEAN PrepareEnemyForSectorBattle()
{
	SECTORINFO *pSector;
	GROUP *pGroup;
	SOLDIERTYPE *pSoldier;
	unsigned ubNumAdmins, ubNumTroops, ubNumElites, ubNumRobots, ubNumTanks, ubNumJeeps;
	unsigned ubTotalAdmins, ubTotalElites, ubTotalRobots, ubTotalTroops, ubTotalTanks, ubTotalJeeps;
	unsigned totalCountOfStationaryEnemies = 0;
	unsigned totalCountOfMobileEnemies = 0;
	int sNumSlots;

	gfPendingNonPlayerTeam[ENEMY_TEAM] = FALSE;

	if( gbWorldSectorZ > 0 )
		return PrepareEnemyForUndergroundBattle();

	// Add the invading group
	if ( gpBattleGroup && gpBattleGroup->usGroupTeam == ENEMY_TEAM )
	{
		//The enemy has instigated the battle which means they are the ones entering the conflict.
		//The player was actually in the sector first, and the enemy doesn't use reinforced placements
		HandleArrivalOfReinforcements( gpBattleGroup );

		// Reinforcement groups?  Bring it on!
		// Omerta has a special setting
		if ( gGameExternalOptions.gfAllowReinforcements &&
			( (GetTownIdForSector( gWorldSectorX, gWorldSectorY ) != OMERTA) || zDiffSetting[gGameOptions.ubDifficultyLevel].bAllowReinforcementsOmerta ) )
		{
			UINT16 pusMoveDir[4][3];
			UINT8 ubDirNumber = 0;
			GROUP *pGroup;
			SECTORINFO *pThisSector;

			// They arrived in multiple groups, so here they come
			pThisSector = &SectorInfo[ SECTOR( gWorldSectorX, gWorldSectorY ) ];

			GenerateDirectionInfos( gWorldSectorX, gWorldSectorY, &ubDirNumber, pusMoveDir,	FALSE, TRUE );

			for( unsigned ubIndex = 0; ubIndex < ubDirNumber; ++ubIndex )
			{
				while ( NumMobileEnemiesInSector( SECTORX( pusMoveDir[ubIndex][0] ), SECTORY( pusMoveDir[ubIndex][0] ) ) && GetNonPlayerGroupInSector( SECTORX( pusMoveDir[ubIndex][0] ), SECTORY( pusMoveDir[ubIndex][0] ), ENEMY_TEAM ) )
				{
					pGroup = GetNonPlayerGroupInSector( SECTORX( pusMoveDir[ubIndex][0] ), SECTORY( pusMoveDir[ubIndex][0] ), ENEMY_TEAM );

					pGroup->ubPrevX = pGroup->ubSectorX;
					pGroup->ubPrevY = pGroup->ubSectorY;

					pGroup->ubSectorX = pGroup->ubNextX = (UINT8)gWorldSectorX;
					pGroup->ubSectorY = pGroup->ubNextY = (UINT8)gWorldSectorY;
				}
			}

			//It is now possible that other enemy groups have also arrived.  Add them in the same manner.
			pGroup = gpGroupList;
			while( pGroup )
			{
				if ( pGroup != gpBattleGroup && pGroup->usGroupTeam != OUR_TEAM && !pGroup->fVehicle &&
					  pGroup->ubSectorX == gpBattleGroup->ubSectorX &&
						pGroup->ubSectorY == gpBattleGroup->ubSectorY &&
						!pGroup->pEnemyGroup->ubAdminsInBattle &&
						!pGroup->pEnemyGroup->ubTroopsInBattle &&
						!pGroup->pEnemyGroup->ubElitesInBattle &&
						!pGroup->pEnemyGroup->ubRobotsInBattle &&
						!pGroup->pEnemyGroup->ubTanksInBattle &&
						!pGroup->pEnemyGroup->ubJeepsInBattle )
				{
					HandleArrivalOfReinforcements( pGroup );
				}

				pGroup = pGroup->next;
			}
		}

		ValidateEnemiesHaveWeapons();
		UnPauseGame();
		return ( ( BOOLEAN) ( gpBattleGroup->ubGroupSize > 0 ) );
	}

	// WDS Count the number of placements.  This will limit the maximum number of enemies we can place on the map
	SOLDIERINITNODE *curr = gSoldierInitHead;
	unsigned mapMaximumNumberOfEnemies = 0;
	while( curr )
	{
		if( curr->pBasicPlacement->bTeam == ENEMY_TEAM )
		{
			++mapMaximumNumberOfEnemies;
		}
		curr = curr->next;
	}

	AssertGE (mapMaximumNumberOfEnemies, 0);
	
	if (mapMaximumNumberOfEnemies > gGameExternalOptions.ubGameMaximumNumberOfEnemies)
		mapMaximumNumberOfEnemies = gGameExternalOptions.ubGameMaximumNumberOfEnemies;
	//is there more enemies in the sector then we can actually place on map? 
	//are there more enemies in the sector then we can actually place on map? 
	gfPendingNonPlayerTeam[ENEMY_TEAM] = (NumNonPlayerTeamMembersInSector( gWorldSectorX, gWorldSectorY, ENEMY_TEAM ) > mapMaximumNumberOfEnemies);

	pSector = &SectorInfo[ SECTOR( gWorldSectorX, gWorldSectorY ) ];

	// OJW - 20090403 - override max ai in co-op
	if (is_networked && is_server && gMaxEnemiesEnabled == 1)
	{
		float totalEnemies = (float)(pSector->ubNumAdmins + pSector->ubNumTroops + pSector->ubNumElites + pSector->ubNumRobots + pSector->ubNumTanks + pSector->ubNumJeeps);
		ubTotalAdmins = (unsigned int)(((float)pSector->ubNumAdmins / totalEnemies) * mapMaximumNumberOfEnemies);
		ubTotalTroops = (unsigned int)(((float)pSector->ubNumTroops / totalEnemies) * mapMaximumNumberOfEnemies);
		ubTotalElites = (unsigned int)(((float)pSector->ubNumElites / totalEnemies) * mapMaximumNumberOfEnemies);
		ubTotalRobots = (unsigned int)(((float)pSector->ubNumRobots / totalEnemies) * mapMaximumNumberOfEnemies);
		ubTotalTanks = (unsigned int)(((float)pSector->ubNumTanks / totalEnemies) * mapMaximumNumberOfEnemies);
		ubTotalJeeps = (unsigned int)(((float)pSector->ubNumJeeps / totalEnemies) * mapMaximumNumberOfEnemies);
		totalEnemies = (float)(ubTotalAdmins + ubTotalTroops + ubTotalElites + ubTotalRobots + ubTotalTanks + ubTotalJeeps);

		// take care of any rounding losses
		while (totalEnemies < mapMaximumNumberOfEnemies)
		{
			// just fill out with standard troops
			++ubTotalTroops;
			++totalEnemies;
		}

		pSector->ubNumAdmins = ubTotalAdmins;
		pSector->ubNumTroops = ubTotalTroops;
		pSector->ubNumElites = ubTotalElites;
		pSector->ubNumRobots = ubTotalRobots;
		pSector->ubNumTanks = ubTotalTanks;
		pSector->ubNumJeeps = ubTotalJeeps;
		pSector->ubAdminsInBattle = 0;
		pSector->ubTroopsInBattle = 0;
		pSector->ubElitesInBattle = 0;
		pSector->ubRobotsInBattle = 0;
		pSector->ubTanksInBattle = 0;
		pSector->ubJeepsInBattle = 0;
	}
	else
	{
		if( pSector->uiFlags & SF_USE_MAP_SETTINGS )
		{
			//count the number of enemy placements in a map and use those
			SOLDIERINITNODE *curr = gSoldierInitHead;
			ubTotalAdmins = ubTotalTroops = ubTotalElites = ubTotalRobots = ubTotalJeeps = ubTotalTanks = 0;
			while( curr )
			{
				if( curr->pBasicPlacement->bTeam == ENEMY_TEAM )
				{
					switch( curr->pBasicPlacement->ubSoldierClass )
					{
						case SOLDIER_CLASS_ADMINISTRATOR:
						case SOLDIER_CLASS_BANDIT:				ubTotalAdmins++;	break;
						case SOLDIER_CLASS_ARMY:				ubTotalTroops++;	break;
						case SOLDIER_CLASS_ELITE:				ubTotalElites++;	break;
						case SOLDIER_CLASS_ROBOT:				ubTotalRobots++;	break;
						case SOLDIER_CLASS_TANK:				ubTotalTanks++;		break;
						case SOLDIER_CLASS_JEEP:				ubTotalJeeps++;		break;
					}
				}
				curr = curr->next;
			}
			pSector->ubNumAdmins = ubTotalAdmins;
			pSector->ubNumTroops = ubTotalTroops;
			pSector->ubNumElites = ubTotalElites;
			pSector->ubNumRobots = ubTotalRobots;
			pSector->ubNumTanks = ubTotalTanks;
			pSector->ubNumJeeps = ubTotalJeeps;
			pSector->ubAdminsInBattle = 0;
			pSector->ubTroopsInBattle = 0;
			pSector->ubElitesInBattle = 0;
			pSector->ubRobotsInBattle = 0;
			pSector->ubTanksInBattle = 0;
			pSector->ubJeepsInBattle = 0;
		}
		else
		{
			ubTotalAdmins = pSector->ubNumAdmins - pSector->ubAdminsInBattle;
			ubTotalTroops = pSector->ubNumTroops - pSector->ubTroopsInBattle;
			ubTotalElites = pSector->ubNumElites - pSector->ubElitesInBattle;
			ubTotalRobots = pSector->ubNumRobots - pSector->ubRobotsInBattle;
			ubTotalTanks  = pSector->ubNumTanks  - pSector->ubTanksInBattle;
			ubTotalJeeps = pSector->ubNumJeeps - pSector->ubJeepsInBattle;
		}
	}

	totalCountOfStationaryEnemies = ubTotalAdmins + ubTotalTroops + ubTotalElites + ubTotalRobots + ubTotalTanks + ubTotalJeeps;

	if( totalCountOfStationaryEnemies > mapMaximumNumberOfEnemies )
	{
		/*
		#ifdef JA2BETAVERSION
			ScreenMsg( FONT_RED, MSG_ERROR, L"The total stationary enemy forces in sector %c%d is %d. (max %d)",
				gWorldSectorY + 'A' - 1, gWorldSectorX, ubTotalAdmins + ubTotalTroops + ubTotalElites, mapMaximumNumberOfEnemies );
		#endif
		*/

		ubTotalAdmins = min( mapMaximumNumberOfEnemies, ubTotalAdmins );
		ubTotalTroops = min( mapMaximumNumberOfEnemies-ubTotalAdmins, ubTotalTroops );
		ubTotalElites = min( mapMaximumNumberOfEnemies-ubTotalAdmins-ubTotalTroops, ubTotalElites );
		ubTotalRobots = min( mapMaximumNumberOfEnemies-ubTotalAdmins-ubTotalTroops-ubTotalElites, ubTotalRobots );
		ubTotalTanks  = min( mapMaximumNumberOfEnemies-ubTotalAdmins-ubTotalTroops-ubTotalElites-ubTotalRobots, ubTotalTanks );
		ubTotalJeeps  = min( mapMaximumNumberOfEnemies-ubTotalAdmins-ubTotalTroops-ubTotalElites-ubTotalRobots-ubTotalTanks, ubTotalJeeps );
	}

	pSector->ubAdminsInBattle += ubTotalAdmins;
	pSector->ubTroopsInBattle += ubTotalTroops;
	pSector->ubElitesInBattle += ubTotalElites;
	pSector->ubRobotsInBattle += ubTotalRobots;
	pSector->ubTanksInBattle += ubTotalTanks;
	pSector->ubJeepsInBattle += ubTotalJeeps;

#ifdef JA2TESTVERSION
	if( gfOverrideSector )
	{
		//if there are no troops in the current groups, then we're done.
		if ( !ubTotalAdmins && !ubTotalTroops && !ubTotalElites && !ubTotalTanks && !ubTotalJeeps && !ubTotalRobots)
			return FALSE;
		AddSoldierInitListEnemyDefenceSoldiers( ubTotalAdmins, ubTotalTroops, ubTotalElites, ubTotalTanks, ubTotalJeeps, ubTotalRobots );
		ValidateEnemiesHaveWeapons();
		UnPauseGame();
		return TRUE;
	}
#endif

	//Search for movement groups that happen to be in the sector.
	sNumSlots = NumFreeSlots( ENEMY_TEAM );
	if (sNumSlots > (int)mapMaximumNumberOfEnemies)
		sNumSlots = mapMaximumNumberOfEnemies;

	/*
	 * WDS - this test no longer valid with the above change
	//Test:  All slots should be free at this point!
	if( sNumSlots != gTacticalStatus.Team[ENEMY_TEAM].bLastID - gTacticalStatus.Team[ENEMY_TEAM].bFirstID + 1 )
	{
		#ifdef JA2BETAVERSION
			ScreenMsg( FONT_RED, MSG_ERROR, L"All enemy slots should be free at this point.  Only %d of %d are available.\nTrying to add %d admins, %d troops, and %d elites.",
				sNumSlots, gTacticalStatus.Team[ENEMY_TEAM].bLastID - gTacticalStatus.Team[ENEMY_TEAM].bFirstID + 1 ,
				ubTotalAdmins, ubTotalTroops, ubTotalElites );
		#endif
	}
	*/

	//Subtract the total number of stationary enemies from the available slots, as stationary forces take
	//precendence in combat.  The mobile forces that could also be in the same sector are considered later if
	//all the slots fill up.
	sNumSlots -= ubTotalAdmins + ubTotalTroops + ubTotalElites + ubTotalRobots + ubTotalTanks + ubTotalJeeps;

	//Now, process all of the groups and search for both enemy and player groups in the sector.
	//For enemy groups, we fill up the slots until we have none left or all of the groups have been
	//processed.

	for( pGroup = gpGroupList; pGroup; pGroup = pGroup->next)
	{
		if ( pGroup->usGroupTeam == ENEMY_TEAM && !pGroup->fVehicle &&
				 pGroup->ubSectorX == gWorldSectorX && pGroup->ubSectorY == gWorldSectorY && !gbWorldSectorZ )
		{ //Process enemy group in sector.
			if( sNumSlots > 0 )
			{
				AssertGE(pGroup->pEnemyGroup->ubNumAdmins, pGroup->pEnemyGroup->ubAdminsInBattle);
				ubNumAdmins = pGroup->pEnemyGroup->ubNumAdmins - pGroup->pEnemyGroup->ubAdminsInBattle;
				sNumSlots -= ubNumAdmins;
				if( sNumSlots < 0 )
				{ //adjust the value to zero
					ubNumAdmins += sNumSlots;
					sNumSlots = 0;
					gfPendingNonPlayerTeam[ENEMY_TEAM] = TRUE;
				}
				pGroup->pEnemyGroup->ubAdminsInBattle += ubNumAdmins;
				ubTotalAdmins += ubNumAdmins;
			}
			if( sNumSlots > 0 )
			{ //Add regular army forces.
				AssertGE(pGroup->pEnemyGroup->ubNumTroops, pGroup->pEnemyGroup->ubTroopsInBattle);
				ubNumTroops = pGroup->pEnemyGroup->ubNumTroops - pGroup->pEnemyGroup->ubTroopsInBattle;
				sNumSlots -= ubNumTroops;
				if( sNumSlots < 0 )
				{ //adjust the value to zero
					ubNumTroops += sNumSlots;
					sNumSlots = 0;
					gfPendingNonPlayerTeam[ENEMY_TEAM] = TRUE;
				}
				pGroup->pEnemyGroup->ubTroopsInBattle += ubNumTroops;
				ubTotalTroops += ubNumTroops;
			}
			if( sNumSlots > 0 )
			{ //Add elite troops
				AssertGE(pGroup->pEnemyGroup->ubNumElites, pGroup->pEnemyGroup->ubElitesInBattle);
				ubNumElites = pGroup->pEnemyGroup->ubNumElites - pGroup->pEnemyGroup->ubElitesInBattle;
				sNumSlots -= ubNumElites;
				if( sNumSlots < 0 )
				{ //adjust the value to zero
					ubNumElites += sNumSlots;
					sNumSlots = 0;
					gfPendingNonPlayerTeam[ENEMY_TEAM] = TRUE;
				}
				pGroup->pEnemyGroup->ubElitesInBattle += ubNumElites;
				ubTotalElites += ubNumElites;
			}
			if( sNumSlots > 0 )
			{ //Add robots
				AssertGE(pGroup->pEnemyGroup->ubNumRobots, pGroup->pEnemyGroup->ubRobotsInBattle);
				ubNumRobots = pGroup->pEnemyGroup->ubNumRobots - pGroup->pEnemyGroup->ubRobotsInBattle;
				sNumSlots -= ubNumRobots;
				if( sNumSlots < 0 )
				{ //adjust the value to zero
					ubNumRobots += sNumSlots;
					sNumSlots = 0;
					gfPendingNonPlayerTeam[ENEMY_TEAM] = TRUE;
				}
				pGroup->pEnemyGroup->ubRobotsInBattle += ubNumRobots;
				ubTotalRobots += ubNumRobots;
			}
			if( sNumSlots > 0 )
			{ //Add tanks
				AssertGE(pGroup->pEnemyGroup->ubNumTanks, pGroup->pEnemyGroup->ubTanksInBattle);
				ubNumTanks = pGroup->pEnemyGroup->ubNumTanks - pGroup->pEnemyGroup->ubTanksInBattle;
				sNumSlots -= ubNumTanks;
				if( sNumSlots < 0 )
				{ //adjust the value to zero
					ubNumTanks += sNumSlots;
					sNumSlots = 0;
					gfPendingNonPlayerTeam[ENEMY_TEAM] = TRUE;
				}
				pGroup->pEnemyGroup->ubTanksInBattle += ubNumTanks;
				ubTotalTanks += ubNumTanks;
			}
			if ( sNumSlots > 0 )
			{
				//Add jeeps
				AssertGE( pGroup->pEnemyGroup->ubNumJeeps, pGroup->pEnemyGroup->ubJeepsInBattle );
				ubNumJeeps = pGroup->pEnemyGroup->ubNumJeeps - pGroup->pEnemyGroup->ubJeepsInBattle;
				sNumSlots -= ubNumJeeps;
				if ( sNumSlots < 0 )
				{ //adjust the value to zero
					ubNumJeeps += sNumSlots;
					sNumSlots = 0;
					gfPendingNonPlayerTeam[ENEMY_TEAM] = TRUE;
				}
				pGroup->pEnemyGroup->ubJeepsInBattle += ubNumJeeps;
				ubTotalJeeps += ubNumJeeps;
			}
			//NOTE:
			//no provisions for profile troop leader or retreat groups yet.
		}

		if ( pGroup->usGroupTeam == OUR_TEAM && !pGroup->fVehicle && !pGroup->fBetweenSectors &&
				pGroup->ubSectorX == gWorldSectorX && pGroup->ubSectorY == gWorldSectorY && !gbWorldSectorZ )
		{ //TEMP:  The player path needs to get destroyed, otherwise, it'll be impossible to move the
			//			 group after the battle is resolved.

			// no one in the group any more continue loop
			if( pGroup->pPlayerList == NULL )
			{
				continue;
			}

			// clear the movt for this grunt and his buddies
			RemoveGroupWaypoints( pGroup->ubGroupID );
		}
	}

	//if there are no troops in the current groups, then we're done.
	if ( !ubTotalAdmins && !ubTotalTroops && !ubTotalElites && !ubTotalRobots && !ubTotalTanks && !ubTotalJeeps )
	{
		return FALSE;
	}

	AddSoldierInitListEnemyDefenceSoldiers( ubTotalAdmins, ubTotalTroops, ubTotalElites, ubTotalRobots, ubTotalTanks, ubTotalJeeps );

	//Now, we have to go through all of the enemies in the new map, and assign their respective groups if
	//in a mobile group, but only for the ones that were assigned from the
	//sNumSlots = mapMaximumNumberOfEnemies - totalCountOfStationaryEnemies;

	// Flugente: at this point, soldiers have already been placed, thus enough slots for them exist
	sNumSlots = min( mapMaximumNumberOfEnemies, NumNonPlayerTeamMembersInSector( gWorldSectorX, gWorldSectorY, ENEMY_TEAM ) );

	pGroup = gpGroupList;
	unsigned firstSlot = gTacticalStatus.Team[ ENEMY_TEAM ].bFirstID;
	unsigned lastSlot = gTacticalStatus.Team[ ENEMY_TEAM ].bLastID;
	unsigned slotsAvailable = lastSlot-firstSlot+1;
	while( pGroup && sNumSlots > 0 )
	{
		if ( pGroup->usGroupTeam != OUR_TEAM && !pGroup->fVehicle &&
				 pGroup->ubSectorX == gWorldSectorX && pGroup->ubSectorY == gWorldSectorY && !gbWorldSectorZ )
		{
			ubNumAdmins = pGroup->pEnemyGroup->ubAdminsInBattle;
			ubNumTroops = pGroup->pEnemyGroup->ubTroopsInBattle;
			ubNumElites = pGroup->pEnemyGroup->ubElitesInBattle;
			ubNumRobots = pGroup->pEnemyGroup->ubRobotsInBattle;
			ubNumTanks = pGroup->pEnemyGroup->ubTanksInBattle;
			ubNumJeeps = pGroup->pEnemyGroup->ubJeepsInBattle;
			unsigned num = ubNumAdmins + ubNumTroops + ubNumElites + ubNumRobots + ubNumTanks + ubNumJeeps;

			AssertGE((int)slotsAvailable, sNumSlots);

			for (unsigned slot = firstSlot;	(slot <= lastSlot) && num && sNumSlots;	++slot)
			{
				pSoldier = &Menptr[ slot ];

				// Skip inactive and already grouped soldiers
				if (!pSoldier->bActive || pSoldier->ubGroupID)
				{
					// if this guy already has an ID, reduce the number of people who still need one
					--num;
					--sNumSlots;
					firstSlot = slot + 1;
					
					continue;
				}

				// At this point we should not have added more soldiers than are in slots
				AssertGT( sNumSlots, 0 );

				switch( pSoldier->ubSoldierClass )
				{
					case SOLDIER_CLASS_ADMINISTRATOR:
						if( ubNumAdmins )
						{
							num--;
							sNumSlots--;
							ubNumAdmins--;
							pSoldier->ubGroupID = pGroup->ubGroupID;
							firstSlot = slot + 1;
						}
						break;
					case SOLDIER_CLASS_ARMY:
						if( ubNumTroops )
						{
							num--;
							sNumSlots--;
							ubNumTroops--;
							pSoldier->ubGroupID = pGroup->ubGroupID;
							firstSlot = slot + 1;
						}
						break;
					case SOLDIER_CLASS_ELITE:
						if( ubNumElites )
						{
							num--;
							sNumSlots--;
							ubNumElites--;
							pSoldier->ubGroupID = pGroup->ubGroupID;
							firstSlot = slot + 1;
						}
						break;
					// silversurfer: bugfix for Jaggzilla bug #623
					// Mike or Iggy can be part of the enemy team and they are created from an Elite but they don't have SOLDIER_CLASS_ELITE.
					// Therefore once this for loop was done ubNumElites was still 1 which caused an assertion error.
					case SOLDIER_CLASS_NONE:
						if( ubNumElites )
						{
							if ( pSoldier->ubProfile == MIKE || pSoldier->ubProfile == IGGY )
							{
								num--;
								sNumSlots--;
								ubNumElites--;
								pSoldier->ubGroupID = pGroup->ubGroupID;
								firstSlot = slot + 1;
							}
						}
						break;
					case SOLDIER_CLASS_ROBOT:
						if( ubNumRobots )
						{
							num--;
							sNumSlots--;
							ubNumRobots--;
							pSoldier->ubGroupID = pGroup->ubGroupID;
							firstSlot = slot + 1;
						}
						break;
					case SOLDIER_CLASS_TANK:
						if( ubNumTanks )
						{
							num--;
							sNumSlots--;
							ubNumTanks--;
							pSoldier->ubGroupID = pGroup->ubGroupID;
							firstSlot = slot + 1;
						}
						break;
					case SOLDIER_CLASS_JEEP:
						if ( ubNumJeeps )
						{
							num--;
							sNumSlots--;
							ubNumJeeps--;
							pSoldier->ubGroupID = pGroup->ubGroupID;
							firstSlot = slot + 1;
						}
						break;
				}
			}

			// Flugente: instead of just crashing the game without any explanation to the user, ignore this issue if it still exists.
			// The worst that should happen is a warning that a soldier has no group id.
			/*AssertEQ( ubNumElites , 0);
			AssertEQ( ubNumTroops , 0);
			AssertEQ( ubNumAdmins , 0);
			AssertEQ( ubNumTanks , 0);
			AssertEQ( ubNumJeeps , 0);
			AssertEQ( ubNumRobots , 0);
			AssertEQ( num , 0);*/
		}
		pGroup = pGroup->next;
	}

	ValidateEnemiesHaveWeapons();
	UnPauseGame();

	return TRUE;
}

BOOLEAN PrepareEnemyForUndergroundBattle()
{
	UNDERGROUND_SECTORINFO *pUnderground;
	unsigned ubTotalAdmins, ubTotalTroops, ubTotalElites, ubTotalRobots, ubTotalTanks, ubTotalJeeps;

	pUnderground = gpUndergroundSectorInfoHead;
	while( pUnderground )
	{
		if( pUnderground->ubSectorX == gWorldSectorX &&
			  pUnderground->ubSectorY == gWorldSectorY &&
				pUnderground->ubSectorZ == gbWorldSectorZ )
		{ //This is the sector we are going to be fighting in.
			if( pUnderground->ubNumAdmins || pUnderground->ubNumTroops || pUnderground->ubNumElites )
			{
				ubTotalAdmins = (UINT8)(pUnderground->ubNumAdmins - pUnderground->ubAdminsInBattle);
				ubTotalTroops = (UINT8)(pUnderground->ubNumTroops - pUnderground->ubTroopsInBattle);
				ubTotalElites = (UINT8)(pUnderground->ubNumElites - pUnderground->ubElitesInBattle);
				ubTotalRobots = (UINT8)(pUnderground->ubNumRobots - pUnderground->ubRobotsInBattle);
				ubTotalTanks = (UINT8)(pUnderground->ubNumTanks - pUnderground->ubTanksInBattle);
				ubTotalJeeps = (UINT8)(pUnderground->ubNumJeeps - pUnderground->ubJeepsInBattle);
				pUnderground->ubAdminsInBattle += ubTotalAdmins;
				pUnderground->ubTroopsInBattle += ubTotalTroops;
				pUnderground->ubElitesInBattle += ubTotalElites;
				pUnderground->ubRobotsInBattle += ubTotalRobots;
				pUnderground->ubTanksInBattle += ubTotalTanks;
				pUnderground->ubJeepsInBattle += ubTotalJeeps;
				AddSoldierInitListEnemyDefenceSoldiers( pUnderground->ubNumAdmins, pUnderground->ubNumTroops, pUnderground->ubNumElites, pUnderground->ubNumRobots, pUnderground->ubNumTanks, pUnderground->ubNumJeeps );
				ValidateEnemiesHaveWeapons();
				UnPauseGame();
			}
			return ((BOOLEAN)(pUnderground->ubNumAdmins + pUnderground->ubNumTroops + pUnderground->ubNumElites + pUnderground->ubNumRobots + pUnderground->ubNumTanks + pUnderground->ubNumJeeps > 0));
		}
		pUnderground = pUnderground->next;
	}

	// underground sector not found in list
	Assert( FALSE );
	return FALSE;
}

//The queen AI layer must process the event by subtracting forces, etc.
void ProcessQueenCmdImplicationsOfDeath( SOLDIERTYPE *pSoldier )
{
	INT32 iNumEnemiesInSector;
	SECTORINFO *pSector;
	INT32 iMaxEnemyGroupSize = gGameExternalOptions.iMaxEnemyGroupSize;
    DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"QueenCommand");

	AssertNotNIL (pSoldier);

	EvaluateDeathEffectsToSoldierInitList( pSoldier );

	switch( pSoldier->ubProfile )
	{
#ifdef JA2UB	
		case 75://MORRIS:

			if( !pSoldier->bSectorZ )
			{
				pSector = &SectorInfo[ SECTOR( pSoldier->sSectorX, pSoldier->sSectorY ) ];
				if( pSector->ubNumElites )
				{
					pSector->ubNumElites--;
				}
				if( pSector->ubElitesInBattle )
				{
					pSector->ubElitesInBattle--;
				}
			}
			 else
			{
				UNDERGROUND_SECTORINFO *pUnderground;
				pUnderground = FindUnderGroundSector( (UINT8)pSoldier->sSectorX, (UINT8)pSoldier->sSectorY, (UINT8)pSoldier->bSectorZ );
				Assert( pUnderground );
				if( pUnderground->ubNumElites )
				{
					pUnderground->ubNumElites--;
				}
				if( pUnderground->ubElitesInBattle )
				{
					pUnderground->ubElitesInBattle--;
				}
			}
			break;
#endif			
		case MIKE:
		case IGGY:
			if( pSoldier->ubProfile == IGGY && !gubFact[ FACT_IGGY_AVAILABLE_TO_ARMY ] )
			{ //Iggy is on our team!
				break;
			}
			if( !pSoldier->bSectorZ )
			{
				pSector = &SectorInfo[ SECTOR( pSoldier->sSectorX, pSoldier->sSectorY ) ];
				if( pSector->ubNumElites )
				{
					pSector->ubNumElites--;
				}
				if( pSector->ubElitesInBattle )
				{
					pSector->ubElitesInBattle--;
				}
			}
			else
			{
				UNDERGROUND_SECTORINFO *pUnderground;
				pUnderground = FindUnderGroundSector( (UINT8)pSoldier->sSectorX, (UINT8)pSoldier->sSectorY, (UINT8)pSoldier->bSectorZ );
				Assert( pUnderground );
				if( pUnderground->ubNumElites )
				{
					pUnderground->ubNumElites--;
				}
				if( pUnderground->ubElitesInBattle )
				{
					pUnderground->ubElitesInBattle--;
				}
			}
			break;
		case TANK_CAR:
			if( !pSoldier->bSectorZ )
			{
				pSector = &SectorInfo[ SECTOR( pSoldier->sSectorX, pSoldier->sSectorY ) ];
				if( pSector->ubNumTanks )
				{
					pSector->ubNumTanks--;
				}
				if( pSector->ubTanksInBattle )
				{
					pSector->ubTanksInBattle--;
				}
			}
			else
			{
				UNDERGROUND_SECTORINFO *pUnderground;
				pUnderground = FindUnderGroundSector( (UINT8)pSoldier->sSectorX, (UINT8)pSoldier->sSectorY, (UINT8)pSoldier->bSectorZ );
				Assert( pUnderground );
				if( pUnderground->ubNumTanks)
				{
					pUnderground->ubNumTanks--;
				}
				if( pUnderground->ubTanksInBattle )
				{
					pUnderground->ubTanksInBattle--;
				}
			}
			break;

		case COMBAT_JEEP_CAR:
			if ( !pSoldier->bSectorZ )
			{
				pSector = &SectorInfo[SECTOR( pSoldier->sSectorX, pSoldier->sSectorY )];
				if ( pSector->ubNumJeeps )
				{
					pSector->ubNumJeeps--;
				}
				if ( pSector->ubJeepsInBattle )
				{
					pSector->ubJeepsInBattle--;
				}
			}
			else
			{
				UNDERGROUND_SECTORINFO *pUnderground;
				pUnderground = FindUnderGroundSector( (UINT8)pSoldier->sSectorX, (UINT8)pSoldier->sSectorY, (UINT8)pSoldier->bSectorZ );
				Assert( pUnderground );
				if ( pUnderground->ubNumJeeps )
				{
					pUnderground->ubNumJeeps--;
				}
				if ( pUnderground->ubJeepsInBattle )
				{
					pUnderground->ubJeepsInBattle--;
				}
			}
			break;
	}

	if( pSoldier->aiData.bNeutral || pSoldier->bTeam != ENEMY_TEAM && pSoldier->bTeam != CREATURE_TEAM )
		return;

	//we are recording an enemy death
	if( pSoldier->ubGroupID )
	{
		//The enemy was in a mobile group
		GROUP *pGroup;
		pGroup = GetGroup( pSoldier->ubGroupID );
		if( !pGroup )
		{
			#ifdef JA2BETAVERSION
				CHAR16 str[256];
				swprintf( str, L"Enemy soldier killed with ubGroupID of %d, and the group doesn't exist!", pSoldier->ubGroupID );
				DoScreenIndependantMessageBox( str, MSG_BOX_FLAG_OK, NULL );
			#endif
			return;
		}

		if ( pGroup->usGroupTeam == OUR_TEAM )
		{
#ifdef JA2BETAVERSION
				CHAR16 str[256];
				swprintf( str, L"Attempting to process player group %d thinking it's an enemy group in ProcessQueenCmdImplicationsOfDeath()", pSoldier->ubGroupID );
				DoScreenIndependantMessageBox( str, MSG_BOX_FLAG_OK, NULL );
#endif
			return;
		}
		else if ( pGroup->usGroupTeam == MILITIA_TEAM )
		{
#ifdef JA2BETAVERSION
			CHAR16 str[256];
			swprintf( str, L"Attempting to process militia group %d thinking it's an enemy group in ProcessQueenCmdImplicationsOfDeath()", pSoldier->ubGroupID );
			DoScreenIndependantMessageBox( str, MSG_BOX_FLAG_OK, NULL );
#endif
			return;
		}

		switch( pSoldier->ubSoldierClass )
		{
			case SOLDIER_CLASS_ROBOT:
				if( pGroup->pEnemyGroup->ubNumRobots )
				{
					pGroup->pEnemyGroup->ubNumRobots--;
				}
				if( pGroup->pEnemyGroup->ubRobotsInBattle )
				{
					pGroup->pEnemyGroup->ubRobotsInBattle--;
				}
				break;
			case SOLDIER_CLASS_ELITE:
				#ifdef JA2BETAVERSION
					if( !pGroup->pEnemyGroup->ubNumElites )
					{
						//swprintf( str, L"Enemy elite killed with ubGroupID of %d, but the group doesn't contain elites!", pGroup->ubGroupID );
						//DoScreenIndependantMessageBox( str, MSG_BOX_FLAG_OK, NULL );
						break;
					}
					if( guiCurrentScreen == GAME_SCREEN )
					{
						if ( pGroup->ubGroupSize <= iMaxEnemyGroupSize && pGroup->pEnemyGroup->ubNumElites != pGroup->pEnemyGroup->ubElitesInBattle && !gfPendingNonPlayerTeam[ENEMY_TEAM] ||
								pGroup->ubGroupSize > iMaxEnemyGroupSize /* || pGroup->pEnemyGroup->ubNumElites > 50 || pGroup->pEnemyGroup->ubElitesInBattle > 50*/ )
						{
							DoScreenIndependantMessageBox( L"Group elite counters are bad.  What were the last 2-3 things to die, and how?  Save game and send to KM with info!!!", MSG_BOX_FLAG_OK, NULL );
						}
					}
				#endif
				if( pGroup->pEnemyGroup->ubNumElites )
				{
					pGroup->pEnemyGroup->ubNumElites--;
				}
				if( pGroup->pEnemyGroup->ubElitesInBattle )
				{
					pGroup->pEnemyGroup->ubElitesInBattle--;
				}
				break;
			case SOLDIER_CLASS_ARMY:
				#ifdef JA2BETAVERSION
					if( !pGroup->pEnemyGroup->ubNumTroops )
					{
						//swprintf( str, L"Enemy troop killed with ubGroupID of %d, but the group doesn't contain elites!", pGroup->ubGroupID );
						//DoScreenIndependantMessageBox( str, MSG_BOX_FLAG_OK, NULL );
						break;
					}
					if( guiCurrentScreen == GAME_SCREEN )
					{
						if ( pGroup->ubGroupSize <= iMaxEnemyGroupSize && pGroup->pEnemyGroup->ubNumTroops != pGroup->pEnemyGroup->ubTroopsInBattle && !gfPendingNonPlayerTeam[ENEMY_TEAM] ||
								pGroup->ubGroupSize > iMaxEnemyGroupSize /*|| pGroup->pEnemyGroup->ubNumTroops > 50 || pGroup->pEnemyGroup->ubTroopsInBattle > 50*/ )
						{
							// haydent
							if (!is_client)
							{
								DoScreenIndependantMessageBox( L"Group troop counters are bad.  What were the last 2-3 things to die, and how?  Save game and send to KM with info!!!", MSG_BOX_FLAG_OK, NULL );
						
							}
						}
					}
				#endif
				if( pGroup->pEnemyGroup->ubNumTroops )
				{
					pGroup->pEnemyGroup->ubNumTroops--;
				}
				if( pGroup->pEnemyGroup->ubTroopsInBattle )
				{
					pGroup->pEnemyGroup->ubTroopsInBattle--;
				}
				break;
			case SOLDIER_CLASS_ADMINISTRATOR:
				#ifdef JA2BETAVERSION
					if( !pGroup->pEnemyGroup->ubNumAdmins )
					{
						//swprintf( str, L"Enemy administrator killed with ubGroupID of %d, but the group doesn't contain elites!", pGroup->ubGroupID );
						//DoScreenIndependantMessageBox( str, MSG_BOX_FLAG_OK, NULL );
						break;
					}
					if( guiCurrentScreen == GAME_SCREEN )
					{
						if ( pGroup->ubGroupSize <= iMaxEnemyGroupSize && pGroup->pEnemyGroup->ubNumAdmins != pGroup->pEnemyGroup->ubAdminsInBattle && !gfPendingNonPlayerTeam[ENEMY_TEAM] ||
						pGroup->ubGroupSize > iMaxEnemyGroupSize /*|| pGroup->pEnemyGroup->ubNumAdmins > 50 || pGroup->pEnemyGroup->ubAdminsInBattle > 50*/ )
						{
							DoScreenIndependantMessageBox( L"Group admin counters are bad.  What were the last 2-3 things to die, and how?  Save game and send to KM with info!!!", MSG_BOX_FLAG_OK, NULL );
						}
					}
				#endif
				if( pGroup->pEnemyGroup->ubNumAdmins )
				{
					pGroup->pEnemyGroup->ubNumAdmins--;
				}
				if( pGroup->pEnemyGroup->ubAdminsInBattle )
				{
					pGroup->pEnemyGroup->ubAdminsInBattle--;
				}
				break;
		}
		if( pGroup->ubGroupSize )
			pGroup->ubGroupSize--;
		RecalculateGroupWeight( pGroup );
		if( !pGroup->ubGroupSize )
		{
			RemovePGroup( pGroup );
		}
	}
	else
	{ //The enemy was in a stationary defence group
		if( !gbWorldSectorZ || IsAutoResolveActive() )
		{ //ground level (SECTORINFO)
			SECTORINFO *pSector;
			#ifdef JA2BETAVERSION
			UINT32 ubTotalEnemies;
			#endif

//			if( !IsAutoResolveActive() )
//			{
				pSector = &SectorInfo[ SECTOR( pSoldier->sSectorX, pSoldier->sSectorY ) ];
//			}
//			else
//			{
//				pSector = &SectorInfo[ GetAutoResolveSectorID() ];
//			}

			#ifdef JA2BETAVERSION
				ubTotalEnemies = pSector->ubNumAdmins + pSector->ubNumTroops + pSector->ubNumElites + pSector->ubNumTanks + pSector->ubNumJeeps;
			#endif

			switch( pSoldier->ubSoldierClass )
			{
				case SOLDIER_CLASS_ADMINISTRATOR:
					#ifdef JA2BETAVERSION
						if( guiCurrentScreen == GAME_SCREEN )
						{
							if( ubTotalEnemies <= gGameExternalOptions.ubGameMaximumNumberOfEnemies && pSector->ubNumAdmins != pSector->ubAdminsInBattle ||
								!pSector->ubNumAdmins || !pSector->ubAdminsInBattle ||
								pSector->ubNumAdmins > gGameExternalOptions.ubGameMaximumNumberOfEnemies || pSector->ubAdminsInBattle > gGameExternalOptions.ubGameMaximumNumberOfEnemies )
							{
								DoScreenIndependantMessageBox( L"Sector admin counters are bad.  What were the last 2-3 things to die, and how?  Save game and send to KM with info!!!", MSG_BOX_FLAG_OK, NULL );
							}
						}
					#endif
					if( pSector->ubNumAdmins )
					{
						pSector->ubNumAdmins--;
					}
					if( pSector->ubAdminsInBattle )
					{
						pSector->ubAdminsInBattle--;
					}
					break;
				case SOLDIER_CLASS_ARMY:
					#ifdef JA2BETAVERSION
						if( guiCurrentScreen == GAME_SCREEN )
						{
							if( ubTotalEnemies <= gGameExternalOptions.ubGameMaximumNumberOfEnemies && pSector->ubNumTroops != pSector->ubTroopsInBattle ||
									!pSector->ubNumTroops || !pSector->ubTroopsInBattle ||
									pSector->ubNumTroops > gGameExternalOptions.ubGameMaximumNumberOfEnemies || pSector->ubTroopsInBattle > gGameExternalOptions.ubGameMaximumNumberOfEnemies )
							{
								if(!is_client)DoScreenIndependantMessageBox( L"Sector troop counters are bad.  What were the last 2-3 things to die, and how?  Save game and send to KM with info!!!", MSG_BOX_FLAG_OK, NULL );
								//disabled: hayden.
							}
						}
					#endif
					if( pSector->ubNumTroops )
					{
						pSector->ubNumTroops--;
					}
					if( pSector->ubTroopsInBattle )
					{
						pSector->ubTroopsInBattle--;
					}
					break;
				case SOLDIER_CLASS_ELITE:
					#ifdef JA2BETAVERSION
						if( guiCurrentScreen == GAME_SCREEN )
						{
							if( ubTotalEnemies <= gGameExternalOptions.ubGameMaximumNumberOfEnemies && pSector->ubNumElites != pSector->ubElitesInBattle ||
									!pSector->ubNumElites || !pSector->ubElitesInBattle ||
									pSector->ubNumElites > gGameExternalOptions.ubGameMaximumNumberOfEnemies || pSector->ubElitesInBattle > gGameExternalOptions.ubGameMaximumNumberOfEnemies )
							{
								DoScreenIndependantMessageBox( L"Sector elite counters are bad.  What were the last 2-3 things to die, and how?  Save game and send to KM with info!!!", MSG_BOX_FLAG_OK, NULL );
							}
						}
					#endif
					if( pSector->ubNumElites )
					{
						pSector->ubNumElites--;
					}
					if( pSector->ubElitesInBattle )
					{
						pSector->ubElitesInBattle--;
					}
					break;
				case SOLDIER_CLASS_ROBOT:
					if( pSector->ubNumRobots )
					{
						pSector->ubNumRobots--;
					}
					if( pSector->ubRobotsInBattle )
					{
						pSector->ubRobotsInBattle--;
					}
					break;
				case SOLDIER_CLASS_CREATURE:
				case SOLDIER_CLASS_BANDIT:
				case SOLDIER_CLASS_ZOMBIE:
					if( pSoldier->ubBodyType != BLOODCAT )
					{
						#ifdef JA2BETAVERSION
							if( guiCurrentScreen == GAME_SCREEN )
							{
								if( ubTotalEnemies <= (UINT32)iMaxEnemyGroupSize && pSector->ubNumCreatures != pSector->ubCreaturesInBattle ||
									!pSector->ubNumCreatures || !pSector->ubCreaturesInBattle ||
									pSector->ubNumCreatures > 50 || pSector->ubCreaturesInBattle > 50 )
								{
									DoScreenIndependantMessageBox( L"Sector creature counters are bad.  What were the last 2-3 things to die, and how?  Save game and send to KM with info!!!", MSG_BOX_FLAG_OK, NULL );
								}
							}
						#endif
						if( pSector->ubNumCreatures )
						{
							pSector->ubNumCreatures--;
						}
						if( pSector->ubCreaturesInBattle )
						{
							pSector->ubCreaturesInBattle--;
						}
					}
					else
					{
						if( pSector->bBloodCats )
						{
							pSector->bBloodCats--;
						}
#ifdef JA2UB						
							//JA25 UB
							//handle anything important when bloodcats die
							HandleBloodCatDeaths( pSector );
#endif
					}

					break;
			}
			RecalculateSectorWeight( (UINT8)SECTOR( pSoldier->sSectorX, pSoldier->sSectorY ) );
		}
		else
		{ //basement level (UNDERGROUND_SECTORINFO)
			UNDERGROUND_SECTORINFO *pSector = FindUnderGroundSector( gWorldSectorX, gWorldSectorY, gbWorldSectorZ );
			#ifdef JA2BETAVERSION
			UINT32 ubTotalEnemies = pSector->ubNumAdmins + pSector->ubNumTroops + pSector->ubNumElites + pSector->ubNumTanks + pSector->ubNumJeeps;
			#endif
			if( pSector )
			{
				switch( pSoldier->ubSoldierClass )
				{
					case SOLDIER_CLASS_ADMINISTRATOR:
						#ifdef JA2BETAVERSION
						if( ubTotalEnemies <= (UINT32)iMaxEnemyGroupSize && pSector->ubNumAdmins != pSector->ubAdminsInBattle ||
								!pSector->ubNumAdmins || !pSector->ubAdminsInBattle ||
								pSector->ubNumAdmins > 100 || pSector->ubAdminsInBattle > iMaxEnemyGroupSize )
						{
							DoScreenIndependantMessageBox( L"Underground sector admin counters are bad.  What were the last 2-3 things to die, and how?  Save game and send to KM with info!!!", MSG_BOX_FLAG_OK, NULL );
						}
						#endif
						if( pSector->ubNumAdmins )
						{
							pSector->ubNumAdmins--;
						}
						if( pSector->ubAdminsInBattle )
						{
							pSector->ubAdminsInBattle--;
						}
						break;
					case SOLDIER_CLASS_ARMY:
						#ifdef JA2BETAVERSION
						if( ubTotalEnemies <= (UINT32)iMaxEnemyGroupSize && pSector->ubNumTroops != pSector->ubTroopsInBattle ||
								!pSector->ubNumTroops || !pSector->ubTroopsInBattle ||
								pSector->ubNumTroops > 100 || pSector->ubTroopsInBattle > iMaxEnemyGroupSize )
						{
							DoScreenIndependantMessageBox( L"Underground sector troop counters are bad.  What were the last 2-3 things to die, and how?  Save game and send to KM with info!!!", MSG_BOX_FLAG_OK, NULL );
						}
						#endif
						if( pSector->ubNumTroops )
						{
							pSector->ubNumTroops--;
						}
						if( pSector->ubTroopsInBattle )
						{
							pSector->ubTroopsInBattle--;
						}
						break;
					case SOLDIER_CLASS_ELITE:
						#ifdef JA2BETAVERSION
						if( ubTotalEnemies <= (UINT32)iMaxEnemyGroupSize && pSector->ubNumElites != pSector->ubElitesInBattle ||
								!pSector->ubNumElites || !pSector->ubElitesInBattle ||
								pSector->ubNumElites > 100 || pSector->ubElitesInBattle > iMaxEnemyGroupSize )
						{
							DoScreenIndependantMessageBox( L"Underground sector elite counters are bad.  What were the last 2-3 things to die, and how?  Save game and send to KM with info!!!", MSG_BOX_FLAG_OK, NULL );
						}
						#endif
						if( pSector->ubNumElites )
						{
							pSector->ubNumElites--;
						}
						if( pSector->ubElitesInBattle )
						{
							pSector->ubElitesInBattle--;
						}
						break;
					case SOLDIER_CLASS_ROBOT:
						if( pSector->ubNumRobots )
						{
							pSector->ubNumRobots--;
						}
						if( pSector->ubRobotsInBattle )
						{
							pSector->ubRobotsInBattle--;
						}
						break;
					case SOLDIER_CLASS_CREATURE:
					case SOLDIER_CLASS_BANDIT:
					case SOLDIER_CLASS_ZOMBIE:
						if (pSoldier->ubBodyType == BLOODCAT)
						{
							if( pSector->ubNumBloodcats > 0 )
								pSector->ubNumBloodcats--;
						}
						else
						{
#ifdef JA2BETAVERSION
							if( ubTotalEnemies <= (UINT32)iMaxEnemyGroupSize && pSector->ubNumCreatures != pSector->ubCreaturesInBattle ||
								!pSector->ubNumCreatures || 
								!pSector->ubCreaturesInBattle ||
								pSector->ubNumCreatures > gGameExternalOptions.ubGameMaximumNumberOfCreatures || 
								pSector->ubCreaturesInBattle > gGameExternalOptions.ubGameMaximumNumberOfCreatures )
							{
								DoScreenIndependantMessageBox( L"Underground sector creature counters are bad.  What were the last 2-3 things to die, and how?  Save game and send to KM with info!!!", MSG_BOX_FLAG_OK, NULL );
							}
#endif
							if( pSector->ubNumCreatures )
							{
								pSector->ubNumCreatures--;
							}
							if( pSector->ubCreaturesInBattle )
							{
								pSector->ubCreaturesInBattle--;
							}

							if ( pSoldier->ubSoldierClass == SOLDIER_CLASS_CREATURE )
							{
								if ( !pSector->ubNumCreatures && gWorldSectorX != 9 && gWorldSectorY != 10 )
								{
									//If the player has successfully killed all creatures in ANY underground sector except J9
									//then cancel any pending creature town attack.
									DeleteAllStrategicEventsOfType( EVENT_CREATURE_ATTACK );
								}

								// a monster has died.  Post an event to immediately check whether a mine has been cleared.
								AddStrategicEventUsingSeconds( EVENT_CHECK_IF_MINE_CLEARED, GetWorldTotalSeconds() + 15, 0 );

								if ( pSoldier->ubBodyType == QUEENMONSTER )
								{
									//Need to call this, as the queen is really big, and killing her leaves a bunch
									//of bad tiles in behind her.  Calling this function cleans it up.
									InvalidateWorldRedundency();
									//Now that the queen is dead, turn off the creature quest.
									EndCreatureQuest();
									EndQuest( QUEST_CREATURES, gWorldSectorX, gWorldSectorY );
								}
							}
						}
						break;
				}
			}
		}
	}
	if( !pSoldier->bSectorZ )
	{
		pSector = &SectorInfo[ SECTOR( pSoldier->sSectorX, pSoldier->sSectorY ) ];
		iNumEnemiesInSector = NumNonPlayerTeamMembersInSector( pSoldier->sSectorX, pSoldier->sSectorY, ENEMY_TEAM );
		if( iNumEnemiesInSector )
		{
			if( pSector->bLastKnownEnemies >= 0 )
			{
				pSector->bLastKnownEnemies = (INT8)iNumEnemiesInSector;
			}
		}
		else
		{
			pSector->bLastKnownEnemies = 0;
		}
	}
}

//Well, not so rarely with mobile reinforcements!
//Rarely, there will be more enemies than supported by the engine.  In this case, these
//soldiers are waiting for a slot to be free so that they can enter the battle.  This
//essentially allows for an infinite number of troops, though only gGameExternalOptions.ubGameMaximumNumberOfEnemies at a time can fight.
//This is also called whenever an enemy group's reinforcements arrive because the code is
//identical, though it is highly likely that they will all be successfully added on the first call.
void AddPossiblePendingEnemiesToBattle()
{
	// Check if no world is loaded, and is not underground level
	if(!(gWorldSectorX > 0 && gWorldSectorY > 0 && gbWorldSectorZ == 0))//dnl ch57 161009
		return;

#ifdef JA2UB
	BOOLEAN fMagicallyAppeared=FALSE;
#endif

	UINT8 ubSlots, ubNumAvailable;
	UINT8 ubNumRobots, ubNumElites, ubNumTroops, ubNumAdmins, ubNumTanks, ubNumJeeps;
	UINT8 ubNumGroupsInSector;
	UINT8 ubGroupIndex;
	GROUP *pGroup;
	SECTORINFO *pSector = &SectorInfo[ SECTOR( gWorldSectorX, gWorldSectorY ) ];
	GROUP **pGroupInSectorList;
	static UINT8 ubPredefinedInsertionCode = 255;

	// haydent
	if (is_networked)
	{
		if ((is_client && !is_server) || gEnemyEnabled == 0)
		{
			return;
		}
	}
	
	if ( (!PlayerMercsInSector( (UINT8)gWorldSectorX, (UINT8)gWorldSectorY, 0 ) && !NumNonPlayerTeamMembersInSector( gWorldSectorX, gWorldSectorY, MILITIA_TEAM ))
		|| !NumNonPlayerTeamMembersInSector( gWorldSectorX, gWorldSectorY, ENEMY_TEAM ) )
		return;

	// Flugente: if there is an enemy helicopter here, it can add reinforcements
	if ( gTacticalStatus.Team[ENEMY_TEAM].bAwareOfOpposition )
	{
		EnemyHeliTroopDrop( SECTOR( gWorldSectorX, gWorldSectorY ) );
	}

	ubSlots = NumFreeSlots( ENEMY_TEAM );
	// silversurfer: Only if there are enemy troops in the sector already we can talk about "reinforcements". If no troops are there we will spawn the incoming troops without delay.
	if( gGameExternalOptions.sMinDelayEnemyReinforcements && gTacticalStatus.Team[ENEMY_TEAM].bTeamActive )//dnl ch68 080913
	{
		if(gTacticalStatus.Team[ENEMY_TEAM].bAwareOfOpposition == TRUE)
		{
			if(guiReinforceTurn == 0)
			{
				guiReinforceTurn = guiTurnCnt + gGameExternalOptions.sMinDelayEnemyReinforcements + Random(gGameExternalOptions.sRndDelayEnemyReinforcements+1);// first possible reinforcement
				ubSlots = 0;
			}
			else if(guiTurnCnt >= guiReinforceTurn)
			{
				guiReinforceTurn = guiTurnCnt + gGameExternalOptions.sMinDelayEnemyReinforcements/3 + Random(gGameExternalOptions.sRndDelayEnemyReinforcements+1);// any other reinforcement should appear more frequently
				ubNumAvailable = gGameExternalOptions.sMinEnterEnemyReinforcements + Random(gGameExternalOptions.sRndEnterEnemyReinforcements+1);// total allowed units to enter per reinforce turn
//SendFmtMsg("Enemy reinforcements: ubSlots=%d ubNumAvailable=%d", ubSlots, ubNumAvailable);
				if(ubSlots > ubNumAvailable)
					ubSlots = ubNumAvailable;
				guiArrived += (ubNumAvailable - ubSlots);
			}
			else
			{
				if(guiArrived > 0)
				{
					if(ubSlots > guiArrived)
						ubSlots = guiArrived;
					guiArrived -= ubSlots;
				}
				else
					ubSlots = 0;
			}
		}
		else
			guiReinforceTurn = guiArrived = 0;
//SendFmtMsg("Enemy reinforcements: guiTurnCnt=%d guiReinforceTurn=%d guiArrived=%d", guiTurnCnt, guiReinforceTurn, guiArrived);
	}

	if( !ubSlots )
	{
		//no available slots to add enemies to.  Try again later...
		return;
	}

	if ( !gfPendingNonPlayerTeam[ENEMY_TEAM] )
	{
		//Optimization.  No point in checking for group reinforcements if we know that there aren't any more enemies that can
		//be added to this battle.  This changes whenever a new enemy group arrives at the scene.

		while (ubSlots)
		{
			UINT8 ubInsertionCode = 255;

			if( gTacticalStatus.Team[ ENEMY_TEAM ].bAwareOfOpposition == TRUE )
				ubInsertionCode = DoReinforcementAsPendingNonPlayer( gWorldSectorX, gWorldSectorY, ENEMY_TEAM );

			if (ubInsertionCode == 255)
			{
				break;
			}

			// Assume we added one since there are supposedly more available and room for them
			ubSlots--;
		}

		// It's probable that the "pending enemies" flag isn't working right.  So we'll go ahead and continue into
		// the group insertion code from here.
		//return;
	}

	if ( pSector->ubNumRobots + pSector->ubNumElites + pSector->ubNumTroops + pSector->ubNumAdmins + pSector->ubNumTanks + pSector->ubNumJeeps )
	{
		ubNumRobots = ubNumElites = ubNumTroops = ubNumAdmins = ubNumTanks = ubNumJeeps = 0;

		ubNumAvailable = pSector->ubNumRobots + pSector->ubNumElites + pSector->ubNumTroops + pSector->ubNumAdmins + pSector->ubNumTanks + pSector->ubNumJeeps
			- pSector->ubRobotsInBattle - pSector->ubElitesInBattle - pSector->ubTroopsInBattle - pSector->ubAdminsInBattle - pSector->ubTanksInBattle - pSector->ubJeepsInBattle;
		while( ubNumAvailable && ubSlots )
		{
			// So they just magically appear out of nowhere from the edge?

			//This group has enemies waiting for a chance to enter the battle.
			if( pSector->ubRobotsInBattle < pSector->ubNumRobots )
			{ //Add a robot
				pSector->ubRobotsInBattle++;
				ubNumAvailable--;
				ubSlots--;
				ubNumRobots++;
			}
			else if( pSector->ubElitesInBattle < pSector->ubNumElites )
			{ //Add an elite troop
				pSector->ubElitesInBattle++;
				ubNumAvailable--;
				ubSlots--;
				ubNumElites++;
			}
			else if( pSector->ubTroopsInBattle < pSector->ubNumTroops )
			{ //Add a regular troop.
				pSector->ubTroopsInBattle++;
				ubNumAvailable--;
				ubSlots--;
				ubNumTroops++;
			}
			else if( pSector->ubAdminsInBattle < pSector->ubNumAdmins )
			{ //Add an elite troop
				pSector->ubAdminsInBattle++;
				ubNumAvailable--;
				ubSlots--;
				ubNumAdmins++;
			}
			else if( pSector->ubTanksInBattle < pSector->ubNumTanks )
			{ //Add a tank
				pSector->ubTanksInBattle++;
				ubNumAvailable--;
				ubSlots--;
				ubNumTanks++;
			}
			else if ( pSector->ubJeepsInBattle < pSector->ubNumJeeps )
			{
				//Add a jeep
				pSector->ubJeepsInBattle++;
				ubNumAvailable--;
				ubSlots--;
				ubNumJeeps++;
			}
			else
			{
				AssertMsg( 0, "AddPossiblePendingEnemiesToBattle():  Logic Error -- by Kris" );
			}
		}


		if ( ubNumAdmins || ubNumTroops || ubNumElites || ubNumRobots || ubNumTanks || ubNumJeeps )
		{	//This group has contributed forces, then add them now, because different
			//groups appear on different sides of the map.
			UINT8 ubStrategicInsertionCode = ubPredefinedInsertionCode;
			//First, determine which entrypoint to use, based on the travel direction of the group.

			if( ubStrategicInsertionCode == 255 )
			{
				if ( NumNonPlayerTeamMembersInSector( gWorldSectorX + 1, gWorldSectorY, ENEMY_TEAM ) )
					ubStrategicInsertionCode = INSERTION_CODE_EAST;
				else if ( NumNonPlayerTeamMembersInSector( gWorldSectorX - 1, gWorldSectorY, ENEMY_TEAM ) )
					ubStrategicInsertionCode = INSERTION_CODE_WEST;
				else if ( NumNonPlayerTeamMembersInSector( gWorldSectorX, gWorldSectorY + 1, ENEMY_TEAM ) )
					ubStrategicInsertionCode = INSERTION_CODE_SOUTH;
				else if ( NumNonPlayerTeamMembersInSector( gWorldSectorX, gWorldSectorY - 1, ENEMY_TEAM ) )
					ubStrategicInsertionCode = INSERTION_CODE_NORTH;
			#ifdef JA2UB
				else if( gsGridNoForMapEdgePointInfo != -1 )
					{
						//Ja25: it doesnt matter the entry point at this point, it will become GRIDNO at a later point
						ubStrategicInsertionCode = INSERTION_CODE_NORTH;
						fMagicallyAppeared = FALSE;
					}
			#endif
			}

			if( ubStrategicInsertionCode == 255 )
			{
				if ( !NumNonPlayerTeamMembersInSector( gWorldSectorX + 1, gWorldSectorY, MILITIA_TEAM ) )
					ubStrategicInsertionCode = INSERTION_CODE_EAST;
				else if ( !NumNonPlayerTeamMembersInSector( gWorldSectorX - 1, gWorldSectorY, MILITIA_TEAM ) )
					ubStrategicInsertionCode = INSERTION_CODE_WEST;
				else if ( !NumNonPlayerTeamMembersInSector( gWorldSectorX, gWorldSectorY + 1, MILITIA_TEAM ) )
					ubStrategicInsertionCode = INSERTION_CODE_SOUTH;
				else if ( !NumNonPlayerTeamMembersInSector( gWorldSectorX, gWorldSectorY - 1, MILITIA_TEAM ) )
					ubStrategicInsertionCode = INSERTION_CODE_NORTH;
			}

			if( ubStrategicInsertionCode < INSERTION_CODE_NORTH || ubStrategicInsertionCode > INSERTION_CODE_WEST )
				ubStrategicInsertionCode = INSERTION_CODE_NORTH + Random( 4 );

			AddEnemiesToBattle( 0, ubStrategicInsertionCode, ubNumAdmins, ubNumTroops, ubNumElites, ubNumRobots, ubNumTanks, ubNumJeeps, FALSE );
			gfPendingNonPlayerTeam[ENEMY_TEAM] = TRUE;
		}
	}

	ubPredefinedInsertionCode = 255;

	// Figure out which groups are in the sector, so we can have reinforcements arrive at random
	for (ubNumGroupsInSector = 0, pGroup = gpGroupList; pGroup; pGroup = pGroup->next)
	{
		if ( pGroup->usGroupTeam == ENEMY_TEAM && !pGroup->fVehicle && pGroup->ubSectorX == gWorldSectorX && pGroup->ubSectorY == gWorldSectorY && !gbWorldSectorZ )
			++ubNumGroupsInSector;
	}
	pGroupInSectorList = (GROUP**) MemAlloc( ubNumGroupsInSector * sizeof( GROUP*));
	for (ubNumGroupsInSector = 0, pGroup = gpGroupList; pGroup; pGroup = pGroup->next)
	{
		if ( pGroup->usGroupTeam == ENEMY_TEAM && !pGroup->fVehicle && pGroup->ubSectorX == gWorldSectorX && pGroup->ubSectorY == gWorldSectorY && !gbWorldSectorZ )
		{
			pGroupInSectorList[ ubNumGroupsInSector++] = pGroup;
		}
	}

	while( ubSlots && ubNumGroupsInSector )
	{
		UINT8 ubInsertionCode = 255;

		ubGroupIndex = Random( ubNumGroupsInSector);
		pGroup = pGroupInSectorList[ ubGroupIndex];

		// Flugente fix: check for underflow...
		UINT8 currentgroupsize = pGroup->pEnemyGroup->ubElitesInBattle + pGroup->pEnemyGroup->ubTroopsInBattle + pGroup->pEnemyGroup->ubAdminsInBattle 
			+ pGroup->pEnemyGroup->ubRobotsInBattle + pGroup->pEnemyGroup->ubTanksInBattle + pGroup->pEnemyGroup->ubJeepsInBattle;
		if ( currentgroupsize > pGroup->ubGroupSize )
			ubNumAvailable = 0;
		else
			ubNumAvailable = pGroup->ubGroupSize - currentgroupsize;

		if (!ubNumAvailable)
		{
			// Looks like we picked an empty group.  Make a note of it
			pGroupInSectorList[ ubGroupIndex] = pGroupInSectorList[ --ubNumGroupsInSector ];
			continue;
		}

		if( pGroup->ubPrevX && pGroup->ubPrevY )
		{
			if( pGroup->ubSectorX < pGroup->ubPrevX )
				ubInsertionCode = INSERTION_CODE_EAST;
			else if( pGroup->ubSectorX > pGroup->ubPrevX )
				ubInsertionCode = INSERTION_CODE_WEST;
			else if( pGroup->ubSectorY < pGroup->ubPrevY )
				ubInsertionCode = INSERTION_CODE_SOUTH;
			else if( pGroup->ubSectorY > pGroup->ubPrevY )
				ubInsertionCode = INSERTION_CODE_NORTH;
			else
			{
				// WANNE: Hack: If no valid insertion is found, get random insertion instead of Assert() error
				// sevenfm: use Random() instead
				//UINT32 rndInsertionCode = GetRndNum(3);
				UINT32 rndInsertionCode = Random(4);
				ubInsertionCode = rndInsertionCode;

				//Assert(0);
			}
		}
		else if( pGroup->ubNextX && pGroup->ubNextY )
		{
			if( pGroup->ubSectorX < pGroup->ubNextX )
				ubInsertionCode = INSERTION_CODE_EAST;
			else if( pGroup->ubSectorX > pGroup->ubNextX )
				ubInsertionCode = INSERTION_CODE_WEST;
			else if( pGroup->ubSectorY < pGroup->ubNextY )
				ubInsertionCode = INSERTION_CODE_SOUTH;
			else if( pGroup->ubSectorY > pGroup->ubNextY )
				ubInsertionCode = INSERTION_CODE_NORTH;
			else
			{
				// WANNE: Hack: If no valid insertion is found, get random insertion instead of Assert() error
				// sevenfm: use Random() instead
				//UINT32 rndInsertionCode = GetRndNum(3);
				UINT32 rndInsertionCode = Random(4);
				ubInsertionCode = rndInsertionCode;

				//Assert(0);
			}
		}
		else
		{
			// The group has no movement orders.  Where did it come from?
			Assert(0);
		}
		
		if ( pGroup->pEnemyGroup->ubElitesInBattle < pGroup->pEnemyGroup->ubNumElites )
		{ //Add an elite troop
			pGroup->pEnemyGroup->ubElitesInBattle++;
			ubSlots--;
			AddEnemiesToBattle( pGroup, ubInsertionCode, 0, 0, 1, 0, 0, 0, FALSE );
		}
		else if( pGroup->pEnemyGroup->ubTroopsInBattle < pGroup->pEnemyGroup->ubNumTroops )
		{ //Add a regular troop.
			pGroup->pEnemyGroup->ubTroopsInBattle++;
			ubSlots--;
			AddEnemiesToBattle( pGroup, ubInsertionCode, 0, 1, 0, 0, 0, 0, FALSE );
		}
		else if( pGroup->pEnemyGroup->ubAdminsInBattle < pGroup->pEnemyGroup->ubNumAdmins )
		{ //Add an admin troop
			pGroup->pEnemyGroup->ubAdminsInBattle++;
			ubSlots--;
			AddEnemiesToBattle( pGroup, ubInsertionCode, 1, 0, 0, 0, 0, 0, FALSE );
		}
		else if( pGroup->pEnemyGroup->ubRobotsInBattle < pGroup->pEnemyGroup->ubNumRobots)
		{ //Add a robot
			pGroup->pEnemyGroup->ubRobotsInBattle++;
			ubSlots--;
			AddEnemiesToBattle( pGroup, ubInsertionCode, 0, 0, 0, 1, 0, 0, FALSE );
		}
		else if( pGroup->pEnemyGroup->ubTanksInBattle < pGroup->pEnemyGroup->ubNumTanks )
		{ //Add a tank
			pGroup->pEnemyGroup->ubTanksInBattle++;
			ubSlots--;
			AddEnemiesToBattle( pGroup, ubInsertionCode, 0, 0, 0, 0, 1, 0, FALSE );
		}
		else if ( pGroup->pEnemyGroup->ubJeepsInBattle < pGroup->pEnemyGroup->ubNumJeeps )
		{ //Add a jeep
			pGroup->pEnemyGroup->ubJeepsInBattle++;
			ubSlots--;
			AddEnemiesToBattle( pGroup, ubInsertionCode, 0, 0, 0, 0, 0, 1, FALSE );
		}
		else
		{
			// WANNE: Instead of asserting, just add a regular troop
			//AssertMsg( 0, "AddPossiblePendingEnemiesToBattle():  Logic Error -- by Kris" );

			pGroup->pEnemyGroup->ubTroopsInBattle++;
			ubSlots--;
			AddEnemiesToBattle( pGroup, ubInsertionCode, 0, 1, 0, 0, 0, 0, FALSE );
		}
	}

	MemFree( pGroupInSectorList);

	if( ubSlots )
	{
		//After going through the process, we have finished with some free slots and no more enemies to add.
		//So, we can turn off the flag, as this check is no longer needed.
		gfPendingNonPlayerTeam[ENEMY_TEAM] = FALSE;
	}
}

void NotifyPlayersOfNewEnemies()
{
	INT32 iSoldiers, iChosenSoldier, i;
	SOLDIERTYPE *pSoldier;
	BOOLEAN fIgnoreBreath = FALSE;

	iSoldiers = 0;
	for( i = gTacticalStatus.Team[ OUR_TEAM ].bFirstID; i <= gTacticalStatus.Team[ OUR_TEAM ].bLastID; i++ )
	{ //find a merc that is aware.
		pSoldier = MercPtrs[ i ];
		if( pSoldier->bInSector && pSoldier->bActive && pSoldier->stats.bLife >= OKLIFE && pSoldier->bBreath >= OKBREATH )
		{
			iSoldiers++;
		}
	}
	if( !iSoldiers )
	{ // look for an out of breath merc.
		fIgnoreBreath = TRUE;

		for( i = gTacticalStatus.Team[ OUR_TEAM ].bFirstID; i <= gTacticalStatus.Team[ OUR_TEAM ].bLastID; i++ )
		{ //find a merc that is aware.
			pSoldier = MercPtrs[ i ];
			if( pSoldier->bInSector && pSoldier->bActive && pSoldier->stats.bLife >= OKLIFE )
			{
				iSoldiers++;
			}
		}
	}
	if( iSoldiers )
	{
		iChosenSoldier = Random( iSoldiers );
		for( i = gTacticalStatus.Team[ OUR_TEAM ].bFirstID; i <= gTacticalStatus.Team[ OUR_TEAM ].bLastID; i++ )
		{ //find a merc that is aware.
			pSoldier = MercPtrs[ i ];
			if( pSoldier->bInSector && pSoldier->bActive && pSoldier->stats.bLife >= OKLIFE &&
				( ( pSoldier->bBreath >= OKBREATH ) || fIgnoreBreath ) )
			{
				if( !iChosenSoldier )
				{
					// ATE: This is to allow special handling of initial heli drop
					if ( !DidGameJustStart() )
					{
						TacticalCharacterDialogueWithSpecialEvent( pSoldier, QUOTE_ENEMY_PRESENCE, 0, 0, 0 );
					}
					return;
				}
				iChosenSoldier--;
			}
		}
	}
	else
	{ //There is either nobody here or our mercs can't talk

	}
}

void AddEnemiesToBattle( GROUP *pGroup, UINT8 ubStrategicInsertionCode, UINT8 ubNumAdmins, UINT8 ubNumTroops, UINT8 ubNumElites, UINT8 ubNumRobots, UINT8 ubNumTanks, UINT8 ubNumJeeps, BOOLEAN fMagicallyAppeared )
{
	SOLDIERTYPE *pSoldier;
	MAPEDGEPOINTINFO MapEdgepointInfo;
	UINT8 ubCurrSlot;
	UINT8 ubTotalSoldiers;
	UINT8 bDesiredDirection=0;
	
	switch( ubStrategicInsertionCode )
	{
		case INSERTION_CODE_NORTH:	bDesiredDirection = SOUTHEAST;										break;
		case INSERTION_CODE_EAST:		bDesiredDirection = SOUTHWEST;										break;
		case INSERTION_CODE_SOUTH:	bDesiredDirection = NORTHWEST;										break;
		case INSERTION_CODE_WEST:		bDesiredDirection = NORTHEAST;										break;
		default:  AssertMsg( 0, "Illegal direction passed to AddEnemiesToBattle()" );	break;
	}
#ifdef JA2TESTVERSION
	ScreenMsg( FONT_RED, MSG_INTERFACE, L"Enemy reinforcements have arrived!  (%d admins, %d troops, %d elite)", ubNumAdmins, ubNumTroops, ubNumElites );
#endif

	if( fMagicallyAppeared )
	{ //update the strategic counters
		if( !gbWorldSectorZ )
		{
			SECTORINFO *pSector = &SectorInfo[ SECTOR( gWorldSectorX, gWorldSectorY ) ];
			pSector->ubNumAdmins		+= ubNumAdmins;
			pSector->ubAdminsInBattle	+= ubNumAdmins;
			pSector->ubNumTroops		+= ubNumTroops;
			pSector->ubTroopsInBattle	+= ubNumTroops;
			pSector->ubNumElites		+= ubNumElites;
			pSector->ubElitesInBattle	+= ubNumElites;
			pSector->ubNumRobots		+= ubNumRobots;
			pSector->ubRobotsInBattle	+= ubNumRobots;
			pSector->ubNumTanks			+= ubNumTanks;
			pSector->ubTanksInBattle	+= ubNumTanks;
			pSector->ubNumJeeps			+= ubNumJeeps;
			pSector->ubJeepsInBattle	+= ubNumJeeps;
		}
		else
		{
			UNDERGROUND_SECTORINFO *pSector = FindUnderGroundSector( gWorldSectorX, gWorldSectorY, gbWorldSectorZ );
			if( pSector )
			{
				pSector->ubNumAdmins		+= ubNumAdmins;
				pSector->ubAdminsInBattle	+= ubNumAdmins;
				pSector->ubNumTroops		+= ubNumTroops;
				pSector->ubTroopsInBattle	+= ubNumTroops;
				pSector->ubNumElites		+= ubNumElites;
				pSector->ubElitesInBattle	+= ubNumElites;
				pSector->ubNumRobots		+= ubNumRobots;
				pSector->ubRobotsInBattle	+= ubNumRobots;
				pSector->ubNumTanks			+= ubNumTanks;
				pSector->ubTanksInBattle	+= ubNumTanks;
				pSector->ubNumJeeps			+= ubNumJeeps;
				pSector->ubJeepsInBattle	+= ubNumJeeps;
			}
		}
		//Because the enemies magically appeared, have one of our soldiers say something...
		NotifyPlayersOfNewEnemies();
	}

	ubTotalSoldiers = ubNumAdmins + ubNumTroops + ubNumElites + ubNumRobots + ubNumTanks + ubNumJeeps;
	
#ifdef JA2UB
	if( gsGridNoForMapEdgePointInfo != -1 )
	{
		ubStrategicInsertionCode = INSERTION_CODE_GRIDNO;
	}

	if( ubStrategicInsertionCode == INSERTION_CODE_GRIDNO )
	{
		if( gsGridNoForMapEdgePointInfo == -1 )
		{
			Assert( 0 );
			gsGridNoForMapEdgePointInfo=0;
		}

		for( UINT8 ubCnt=0; ubCnt<32; ++ubCnt)
		{
			MapEdgepointInfo.sGridNo[ ubCnt ] = gsGridNoForMapEdgePointInfo;
		}

		MapEdgepointInfo.ubNumPoints = 32;
		MapEdgepointInfo.ubStrategicInsertionCode = INSERTION_CODE_GRIDNO;
	}
	else
	{
		ChooseMapEdgepoints( &MapEdgepointInfo, ubStrategicInsertionCode, ubTotalSoldiers );
	}
#else
	ChooseMapEdgepoints( &MapEdgepointInfo, ubStrategicInsertionCode, ubTotalSoldiers );
#endif	
	
	extern INT16 gsStrategicDiseaseOriginSector;

	// Flugente: we need to set the sector of origin to determine from which sector to take the disease ratio that affects health
	gsStrategicDiseaseOriginSector = -1;

	if ( !gbWorldSectorZ )
	{
		switch ( ubStrategicInsertionCode )
		{
		case INSERTION_CODE_NORTH:	gsStrategicDiseaseOriginSector = SECTOR( gWorldSectorX, gWorldSectorY - 1 );	break;
		case INSERTION_CODE_EAST:	gsStrategicDiseaseOriginSector = SECTOR( gWorldSectorX + 1, gWorldSectorY );	break;
		case INSERTION_CODE_SOUTH:	gsStrategicDiseaseOriginSector = SECTOR( gWorldSectorX, gWorldSectorY + 1 );	break;
		case INSERTION_CODE_WEST:	gsStrategicDiseaseOriginSector = SECTOR( gWorldSectorX - 1, gWorldSectorY );	break;
		default:
			break;
		}
	}
	
	ubCurrSlot = 0;
	while( ubTotalSoldiers )
	{
		if( ubNumElites && Random( ubTotalSoldiers ) < ubNumElites )
		{
			ubNumElites--;
			ubTotalSoldiers--;
			Assert(pSoldier = TacticalCreateEliteEnemy());
			if( pGroup )
			{
				pSoldier->ubGroupID = pGroup->ubGroupID;
			}

			pSoldier->ubInsertionDirection = bDesiredDirection;
			//Setup the position
			if( ubCurrSlot < MapEdgepointInfo.ubNumPoints )
			{ //using an edgepoint
				pSoldier->ubStrategicInsertionCode = INSERTION_CODE_GRIDNO;
				pSoldier->usStrategicInsertionData = MapEdgepointInfo.sGridNo[ ubCurrSlot++ ];
			}
			else
			{ //no edgepoints left, so put him at the entrypoint.
				pSoldier->ubStrategicInsertionCode = ubStrategicInsertionCode;
			}
			UpdateMercInSector( pSoldier, gWorldSectorX, gWorldSectorY, 0 );
		}
		else if( ubNumTroops && (UINT8)Random( ubTotalSoldiers ) < (UINT8)(ubNumElites + ubNumTroops) )
		{
			ubNumTroops--;
			ubTotalSoldiers--;
			Assert(pSoldier = TacticalCreateArmyTroop());
			if( pGroup )
			{
				pSoldier->ubGroupID = pGroup->ubGroupID;
			}

			pSoldier->ubInsertionDirection = bDesiredDirection;
			//Setup the position
			if( ubCurrSlot < MapEdgepointInfo.ubNumPoints )
			{ //using an edgepoint
				pSoldier->ubStrategicInsertionCode = INSERTION_CODE_GRIDNO;
				pSoldier->usStrategicInsertionData = MapEdgepointInfo.sGridNo[ ubCurrSlot++ ];
			}
			else
			{ //no edgepoints left, so put him at the entrypoint.
				pSoldier->ubStrategicInsertionCode = ubStrategicInsertionCode;
			}
			UpdateMercInSector( pSoldier, gWorldSectorX, gWorldSectorY, 0 );
		}
		else if( ubNumAdmins && (UINT8)Random( ubTotalSoldiers ) < (UINT8)(ubNumElites + ubNumTroops + ubNumAdmins) )
		{
			ubNumAdmins--;
			ubTotalSoldiers--;
			Assert(pSoldier = TacticalCreateAdministrator());
			if( pGroup )
			{
				pSoldier->ubGroupID = pGroup->ubGroupID;
			}

			pSoldier->ubInsertionDirection = bDesiredDirection;
			//Setup the position
			if( ubCurrSlot < MapEdgepointInfo.ubNumPoints )
			{ //using an edgepoint
				pSoldier->ubStrategicInsertionCode = INSERTION_CODE_GRIDNO;
				pSoldier->usStrategicInsertionData = MapEdgepointInfo.sGridNo[ ubCurrSlot++ ];
			}
			else
			{ //no edgepoints left, so put him at the entrypoint.
				pSoldier->ubStrategicInsertionCode = ubStrategicInsertionCode;
			}
			UpdateMercInSector( pSoldier, gWorldSectorX, gWorldSectorY, 0 );
		}
		else if( ubNumRobots && (UINT8)Random( ubTotalSoldiers ) < (UINT8)(ubNumElites + ubNumTroops + ubNumAdmins + ubNumRobots) )
		{
			ubNumRobots--;
			ubTotalSoldiers--;
			Assert(pSoldier = TacticalCreateEnemyRobot());
			if( pGroup )
			{
				pSoldier->ubGroupID = pGroup->ubGroupID;
			}

			pSoldier->ubInsertionDirection = bDesiredDirection;
			//Setup the position
			if( ubCurrSlot < MapEdgepointInfo.ubNumPoints )
			{ //using an edgepoint
				pSoldier->ubStrategicInsertionCode = INSERTION_CODE_GRIDNO;
				pSoldier->usStrategicInsertionData = MapEdgepointInfo.sGridNo[ ubCurrSlot++ ];
			}
			else
			{ //no edgepoints left, so put him at the entrypoint.
				pSoldier->ubStrategicInsertionCode = ubStrategicInsertionCode;
			}
			UpdateMercInSector( pSoldier, gWorldSectorX, gWorldSectorY, 0 );
		}
		else if( ubNumTanks && (UINT8)Random( ubTotalSoldiers ) < (UINT8)(ubNumElites + ubNumTroops + ubNumAdmins + ubNumRobots + ubNumTanks) && ubNumberOfVehicles < 9 )
		{
			ubNumTanks--;
			ubTotalSoldiers--;
			Assert(pSoldier = TacticalCreateEnemyTank());
			if( pGroup )
			{
				pSoldier->ubGroupID = pGroup->ubGroupID;
			}

			pSoldier->ubInsertionDirection = bDesiredDirection;
			//Setup the position
			if( ubCurrSlot < MapEdgepointInfo.ubNumPoints )
			{ //using an edgepoint
				pSoldier->ubStrategicInsertionCode = INSERTION_CODE_GRIDNO;
				pSoldier->usStrategicInsertionData = MapEdgepointInfo.sGridNo[ ubCurrSlot++ ];
			}
			else
			{ //no edgepoints left, so put him at the entrypoint.
				pSoldier->ubStrategicInsertionCode = ubStrategicInsertionCode;
			}
			UpdateMercInSector( pSoldier, gWorldSectorX, gWorldSectorY, 0 );
		}
		else if ( ubNumJeeps && (UINT8)Random( ubTotalSoldiers ) < (UINT8)(ubNumElites + ubNumTroops + ubNumAdmins + ubNumRobots + ubNumTanks + ubNumJeeps) && ubNumberOfVehicles < 9 )
		{
			ubNumJeeps--;
			ubTotalSoldiers--;
			Assert( pSoldier = TacticalCreateEnemyJeep( ) );
			if ( pGroup )
			{
				pSoldier->ubGroupID = pGroup->ubGroupID;
			}

			pSoldier->ubInsertionDirection = bDesiredDirection;
			//Setup the position
			if ( ubCurrSlot < MapEdgepointInfo.ubNumPoints )
			{ //using an edgepoint
				pSoldier->ubStrategicInsertionCode = INSERTION_CODE_GRIDNO;
				pSoldier->usStrategicInsertionData = MapEdgepointInfo.sGridNo[ubCurrSlot++];
			}
			else
			{ //no edgepoints left, so put him at the entrypoint.
				pSoldier->ubStrategicInsertionCode = ubStrategicInsertionCode;
			}
			UpdateMercInSector( pSoldier, gWorldSectorX, gWorldSectorY, 0 );
		}

		// HEADROCK HAM 3.2: enemy reinforcements arrive with 0 APs.
		if (gGameExternalOptions.ubReinforcementsFirstTurnFreeze == 1 || gGameExternalOptions.ubReinforcementsFirstTurnFreeze == 2)
		{			
			pSoldier->bActionPoints = 0;

			// Flugente: due to a fix, also note here that the reinforcements get no APs.
			pSoldier->usSoldierFlagMask |= SOLDIER_NO_AP;

			// Flugente: campaign stats
			if ( IsOurSoldier(pSoldier) )
				gCurrentIncident.usIncidentFlags |= INCIDENT_REINFORCEMENTS_PLAYERSIDE;
			else
				gCurrentIncident.usIncidentFlags |= INCIDENT_REINFORCEMENTS_ENEMY;
		}
	}

	// set this back so it doesn't affect others
	gsStrategicDiseaseOriginSector = -1;
	
#ifdef JA2UB
	gsGridNoForMapEdgePointInfo = -1;
#endif
}

void AddMilitiaToBattle( GROUP *pGroup, UINT8 ubStrategicInsertionCode, UINT8 ubNumGreens, UINT8 ubNumRegulars, UINT8 ubNumElites, BOOLEAN fMagicallyAppeared )
{
	SOLDIERTYPE *pSoldier;
	MAPEDGEPOINTINFO MapEdgepointInfo;
	UINT8 ubCurrSlot;
	UINT8 ubTotalSoldiers;
	UINT8 bDesiredDirection = 0;

	switch ( ubStrategicInsertionCode )
	{
	case INSERTION_CODE_NORTH:		bDesiredDirection = SOUTHEAST;					break;
	case INSERTION_CODE_EAST:		bDesiredDirection = SOUTHWEST;					break;
	case INSERTION_CODE_SOUTH:		bDesiredDirection = NORTHWEST;					break;
	case INSERTION_CODE_WEST:		bDesiredDirection = NORTHEAST;					break;
	default:  AssertMsg( 0, "Illegal direction passed to AddEnemiesToBattle()" );	break;
	}
#ifdef JA2TESTVERSION
	ScreenMsg( FONT_RED, MSG_INTERFACE, L"Militia reinforcements have arrived!  (%d greens, %d regulars, %d elite)", ubNumGreens, ubNumRegulars, ubNumElites );
#endif

	if ( fMagicallyAppeared )
	{
		//update the strategic counters
		if ( !gbWorldSectorZ )
		{
			SECTORINFO *pSector = &SectorInfo[SECTOR( gWorldSectorX, gWorldSectorY )];
			pSector->ubNumberOfCivsAtLevel[GREEN_MILITIA] += ubNumGreens;
			pSector->ubNumberOfCivsAtLevel[REGULAR_MILITIA] += ubNumRegulars;
			pSector->ubNumberOfCivsAtLevel[ELITE_MILITIA] += ubNumElites;
		}
		else
		{
			// there are no underground militia... error if this ever happens
			AssertMsg( 0, "Tried to add militia to an underground sector" );
		}
	}

	ubTotalSoldiers = ubNumGreens + ubNumRegulars + ubNumElites;

#ifdef JA2UB
	if ( gsGridNoForMapEdgePointInfo != -1 )
	{
		ubStrategicInsertionCode = INSERTION_CODE_GRIDNO;
	}

	if ( ubStrategicInsertionCode == INSERTION_CODE_GRIDNO )
	{
		if ( gsGridNoForMapEdgePointInfo == -1 )
		{
			Assert( 0 );
			gsGridNoForMapEdgePointInfo = 0;
		}

		for ( UINT8 ubCnt = 0; ubCnt<32; ++ubCnt )
		{
			MapEdgepointInfo.sGridNo[ubCnt] = gsGridNoForMapEdgePointInfo;
		}

		MapEdgepointInfo.ubNumPoints = 32;
		MapEdgepointInfo.ubStrategicInsertionCode = INSERTION_CODE_GRIDNO;
	}
	else
	{
		ChooseMapEdgepoints( &MapEdgepointInfo, ubStrategicInsertionCode, ubTotalSoldiers );
	}
#else
	ChooseMapEdgepoints( &MapEdgepointInfo, ubStrategicInsertionCode, (ubTotalSoldiers) );
#endif	

	ubCurrSlot = 0;
	while ( ubTotalSoldiers )
	{
		if ( ubNumElites && Random( ubTotalSoldiers ) < ubNumElites )
		{
			ubNumElites--;
			ubTotalSoldiers--;
			Assert( pSoldier = TacticalCreateMilitia( SOLDIER_CLASS_ELITE_MILITIA, gWorldSectorX, gWorldSectorY ) );
			if ( pGroup )
			{
				pSoldier->ubGroupID = pGroup->ubGroupID;
			}

			pSoldier->ubInsertionDirection = bDesiredDirection;
			//Setup the position
			if ( ubCurrSlot < MapEdgepointInfo.ubNumPoints )
			{ //using an edgepoint
				pSoldier->ubStrategicInsertionCode = INSERTION_CODE_GRIDNO;
				pSoldier->usStrategicInsertionData = MapEdgepointInfo.sGridNo[ubCurrSlot++];
			}
			else
			{ //no edgepoints left, so put him at the entrypoint.
				pSoldier->ubStrategicInsertionCode = ubStrategicInsertionCode;
			}
			UpdateMercInSector( pSoldier, gWorldSectorX, gWorldSectorY, 0 );
		}
		else if ( ubNumRegulars && (UINT8)Random( ubTotalSoldiers ) < (UINT8)(ubNumElites + ubNumRegulars) )
		{
			ubNumRegulars--;
			ubTotalSoldiers--;
			Assert( pSoldier = TacticalCreateMilitia( SOLDIER_CLASS_REG_MILITIA, gWorldSectorX, gWorldSectorY ) );
			if ( pGroup )
			{
				pSoldier->ubGroupID = pGroup->ubGroupID;
			}

			pSoldier->ubInsertionDirection = bDesiredDirection;
			//Setup the position
			if ( ubCurrSlot < MapEdgepointInfo.ubNumPoints )
			{ //using an edgepoint
				pSoldier->ubStrategicInsertionCode = INSERTION_CODE_GRIDNO;
				pSoldier->usStrategicInsertionData = MapEdgepointInfo.sGridNo[ubCurrSlot++];
			}
			else
			{ //no edgepoints left, so put him at the entrypoint.
				pSoldier->ubStrategicInsertionCode = ubStrategicInsertionCode;
			}
			UpdateMercInSector( pSoldier, gWorldSectorX, gWorldSectorY, 0 );
		}
		else if ( ubNumGreens && (UINT8)Random( ubTotalSoldiers ) < (UINT8)(ubNumElites + ubNumRegulars + ubNumGreens) )
		{
			ubNumGreens--;
			ubTotalSoldiers--;
			Assert( pSoldier = TacticalCreateMilitia( SOLDIER_CLASS_GREEN_MILITIA, gWorldSectorX, gWorldSectorY ) );
			if ( pGroup )
			{
				pSoldier->ubGroupID = pGroup->ubGroupID;
			}

			pSoldier->ubInsertionDirection = bDesiredDirection;
			//Setup the position
			if ( ubCurrSlot < MapEdgepointInfo.ubNumPoints )
			{ //using an edgepoint
				pSoldier->ubStrategicInsertionCode = INSERTION_CODE_GRIDNO;
				pSoldier->usStrategicInsertionData = MapEdgepointInfo.sGridNo[ubCurrSlot++];
			}
			else
			{ //no edgepoints left, so put him at the entrypoint.
				pSoldier->ubStrategicInsertionCode = ubStrategicInsertionCode;
			}
			UpdateMercInSector( pSoldier, gWorldSectorX, gWorldSectorY, 0 );
		}

		// HEADROCK HAM 3.2: enemy reinforcements arrive with 0 APs.
		if ( gGameExternalOptions.ubReinforcementsFirstTurnFreeze == 1 || gGameExternalOptions.ubReinforcementsFirstTurnFreeze == 2 )
		{
			pSoldier->bActionPoints = 0;

			// Flugente: due to a fix, also note here that the reinforcements get no APs.
			pSoldier->usSoldierFlagMask |= SOLDIER_NO_AP;

			// Flugente: campaign stats
			if ( IsOurSoldier( pSoldier ) )
				gCurrentIncident.usIncidentFlags |= INCIDENT_REINFORCEMENTS_PLAYERSIDE;
			else
				gCurrentIncident.usIncidentFlags |= INCIDENT_REINFORCEMENTS_ENEMY;
		}
	}

#ifdef JA2UB
	gsGridNoForMapEdgePointInfo = -1;
#endif
}


BOOLEAN SaveUnderGroundSectorInfoToSaveGame( HWFILE hFile )
{
	UINT32	uiNumBytesWritten;
	UINT32	uiNumOfRecords=0;
	UNDERGROUND_SECTORINFO *TempNode = gpUndergroundSectorInfoHead;

	//Loop through all the nodes to count how many there are
	while( TempNode )
	{
		uiNumOfRecords++;
		TempNode = TempNode->next;
	}


	//Write how many nodes there are
	FileWrite( hFile, &uiNumOfRecords, sizeof( UINT32 ), &uiNumBytesWritten );
	if( uiNumBytesWritten != sizeof( UINT32 ) )
	{
		return(FALSE);
	}

	TempNode = gpUndergroundSectorInfoHead;

	//Go through each node and save it.
	while( TempNode )
	{
		FileWrite( hFile, TempNode, sizeof( UNDERGROUND_SECTORINFO ), &uiNumBytesWritten );
		if( uiNumBytesWritten != sizeof( UNDERGROUND_SECTORINFO ) )
		{
			return(FALSE);
		}

		TempNode = TempNode->next;
	}

	return( TRUE );
}

BOOLEAN LoadUnderGroundSectorInfoFromSavedGame( HWFILE hFile )
{
	UINT32	uiNumBytesRead;
	UINT32	uiNumOfRecords=0;
	UINT32	cnt=0;
	UNDERGROUND_SECTORINFO *TempNode = NULL;
	UNDERGROUND_SECTORINFO *TempSpot = NULL;

	//Clear the current LL
	TrashUndergroundSectorInfo();

	//Read in the number of nodes stored
	FileRead( hFile, &uiNumOfRecords, sizeof( UINT32 ), &uiNumBytesRead );
	if( uiNumBytesRead != sizeof( UINT32 ) )
	{
		return(FALSE);
	}

	for( cnt = 0; cnt< uiNumOfRecords; cnt ++)
	{

		//Malloc space for the new node
		TempNode = (UNDERGROUND_SECTORINFO *) MemAlloc( sizeof( UNDERGROUND_SECTORINFO ) );
		if( TempNode == NULL )
			return( FALSE );


		//read in the new node
		FileRead( hFile, TempNode, sizeof( UNDERGROUND_SECTORINFO ), &uiNumBytesRead );
		if( uiNumBytesRead != sizeof( UNDERGROUND_SECTORINFO ) )
		{
			return(FALSE);
		}

		//If its the first time in, assign the node to the list
		if( cnt == 0 )
		{
			gpUndergroundSectorInfoHead = TempNode;
			TempSpot = gpUndergroundSectorInfoHead;
			TempSpot->next = NULL;
		}
		else
		{
			//assign the new node to the LL
			TempSpot->next = TempNode;

			//advance to the next node
			TempSpot = TempSpot->next;
			TempSpot->next = NULL;
			gpUndergroundSectorInfoTail = TempSpot;
		}

	}

#ifdef JA2BETAVERSION
	if( !uiNumOfRecords )
	{
		BuildUndergroundSectorInfoList();
		gfClearCreatureQuest = TRUE;
	}
#endif

	return( TRUE );
}


UNDERGROUND_SECTORINFO* FindUnderGroundSector( INT16 sMapX, INT16 sMapY, UINT8 bMapZ )
{
	UNDERGROUND_SECTORINFO *pUnderground;
	pUnderground = gpUndergroundSectorInfoHead;

	//Loop through all the underground sectors looking for specified sector
	while( pUnderground )
	{
		//If the sector is the right one
		if( pUnderground->ubSectorX == sMapX &&
			  pUnderground->ubSectorY == sMapY &&
				pUnderground->ubSectorZ == bMapZ )
		{
			return( pUnderground );
		}
		pUnderground = pUnderground->next;
	}


	return( NULL );
}




void BeginCaptureSquence( )
{
	if( !( gStrategicStatus.uiFlags & STRATEGIC_PLAYER_CAPTURED_FOR_RESCUE ) || !( gStrategicStatus.uiFlags & STRATEGIC_PLAYER_CAPTURED_FOR_ESCAPE ) )
	{
		gStrategicStatus.ubNumCapturedForRescue = 0;
	}
}

void EndCaptureSequence( )
{
#ifdef JA2UB
// no UB
#else
     
	// Set flag...
	if( !( gStrategicStatus.uiFlags & STRATEGIC_PLAYER_CAPTURED_FOR_RESCUE ) || !(gStrategicStatus.uiFlags & STRATEGIC_PLAYER_CAPTURED_FOR_ESCAPE) )
	{
		// CJC Dec 1 2002: fixing multiple captures:
		//gStrategicStatus.uiFlags |= STRATEGIC_PLAYER_CAPTURED_FOR_RESCUE;

		if ( gubQuest[ QUEST_HELD_IN_ALMA ] == QUESTNOTSTARTED )
		{
			// CJC Dec 1 2002: fixing multiple captures:
			gStrategicStatus.uiFlags |= STRATEGIC_PLAYER_CAPTURED_FOR_RESCUE;
			StartQuest( QUEST_HELD_IN_ALMA, gWorldSectorX, gWorldSectorY );
		}
		// CJC Dec 1 2002: fixing multiple captures:
		//else if ( gubQuest[ QUEST_HELD_IN_ALMA ] == QUESTDONE )
		else if (gubQuest[QUEST_HELD_IN_ALMA] != QUESTINPROGRESS && gubQuest[QUEST_HELD_IN_TIXA] == QUESTNOTSTARTED)
		{
			// CJC Dec 1 2002: fixing multiple captures:
			gStrategicStatus.uiFlags |= STRATEGIC_PLAYER_CAPTURED_FOR_RESCUE;
			StartQuest(QUEST_HELD_IN_TIXA, gWorldSectorX, gWorldSectorY);
		}
		else if (gubQuest[QUEST_HELD_IN_ALMA] != QUESTINPROGRESS && gubQuest[QUEST_HELD_IN_TIXA] != QUESTINPROGRESS && gubQuest[QUEST_INTERROGATION] == QUESTNOTSTARTED)
		{
			StartQuest( QUEST_INTERROGATION, gWorldSectorX, gWorldSectorY );
			// CJC Dec 1 2002: fixing multiple captures:
			gStrategicStatus.uiFlags |= STRATEGIC_PLAYER_CAPTURED_FOR_ESCAPE;

			// OK! - Schedule Meanwhile now!
			HandleInterrogationMeanwhileScene();
		}
		// CJC Dec 1 2002: fixing multiple captures
		else
		{
			// !?!? set both flags
			gStrategicStatus.uiFlags |= STRATEGIC_PLAYER_CAPTURED_FOR_RESCUE;
			gStrategicStatus.uiFlags |= STRATEGIC_PLAYER_CAPTURED_FOR_ESCAPE;
		}
	}
#endif
}

void EnemyCapturesPlayerSoldier( SOLDIERTYPE *pSoldier )
{
	UINT32					i;
	BOOLEAN       fMadeCorpse;
	INT32         iNumEnemiesInSector;

	AssertNotNIL(pSoldier);

	// ATE: Check first if ! in player captured sequence already
	// CJC Dec 1 2002: fixing multiple captures
	if ( ( gStrategicStatus.uiFlags & STRATEGIC_PLAYER_CAPTURED_FOR_RESCUE ) && (gStrategicStatus.uiFlags & STRATEGIC_PLAYER_CAPTURED_FOR_ESCAPE) )
	{
		return;
	}

	// If this is an EPC , just kill them...
	if ( AM_AN_EPC( pSoldier ) || AM_A_ROBOT(pSoldier))
	{
		pSoldier->stats.bLife = 0;
		pSoldier->iHealableInjury = 0; // added by SANDRO
		HandleSoldierDeath( pSoldier, &fMadeCorpse );
		return;
	}

	// can't capture mercs on mini event adventures
	if (pSoldier->bAssignment == ASSIGNMENT_MINIEVENT)
	{
		return;
	}
	
	if ( pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE )
	{
		return;
	}

	// ATE: Patch fix If in a vehicle, remove from vehicle...
	TakeSoldierOutOfVehicle( pSoldier );

	HandleMoraleEvent( pSoldier, MORALE_MERC_CAPTURED, pSoldier->sSectorX, pSoldier->sSectorY, pSoldier->bSectorZ );

	// Change to POW....
	//-add him to a POW assignment/group
	if( ( pSoldier->bAssignment != ASSIGNMENT_POW )  )
	{
		SetTimeOfAssignmentChangeForMerc( pSoldier );
	}

	ChangeSoldiersAssignment( pSoldier, ASSIGNMENT_POW );
	RemoveCharacterFromSquads( pSoldier );

	WORLDITEM			WorldItem;
	std::vector<WORLDITEM> pWorldItem;

#ifdef JA2UB
	if (gStrategicStatus.ubNumCapturedForRescue < 3 && (gubQuest[QUEST_HELD_IN_ALMA] == QUESTNOTSTARTED || gubQuest[QUEST_INTERROGATION] == QUESTNOTSTARTED))
#else
	if (gStrategicStatus.ubNumCapturedForRescue < 3 && (gubQuest[QUEST_HELD_IN_ALMA] == QUESTNOTSTARTED || gubQuest[QUEST_HELD_IN_TIXA] == QUESTNOTSTARTED || gubQuest[QUEST_INTERROGATION] == QUESTNOTSTARTED))
#endif 	
	{
		INT32 itemdropoffgridno = -1;

		// Is this the first one..?
		if ( gubQuest[QUEST_HELD_IN_ALMA] == QUESTNOTSTARTED )
		{
			//-teleport him to NE Alma sector (not Tixa as originally planned)
			pSoldier->aiData.bNeutral = TRUE;
			pSoldier->sSectorX = gModSettings.ubInitialPOWSectorX; //13
			pSoldier->sSectorY = gModSettings.ubInitialPOWSectorY; //9
			pSoldier->bSectorZ = 0;
			pSoldier->usStrategicInsertionData = gModSettings.iInitialPOWGridNo[gStrategicStatus.ubNumCapturedForRescue];
			itemdropoffgridno = gModSettings.iInitialPOWItemGridNo[gStrategicStatus.ubNumCapturedForRescue];
		}
		#ifndef JA2UB
		else if (gubQuest[QUEST_HELD_IN_TIXA] == QUESTNOTSTARTED)
		{
			//-teleport him to Tixa as originally planned
			pSoldier->aiData.bNeutral = TRUE;
			pSoldier->sSectorX = gModSettings.ubTixaPrisonSectorX;
			pSoldier->sSectorY = gModSettings.ubTixaPrisonSectorY;
			pSoldier->bSectorZ = 0;
			pSoldier->usStrategicInsertionData = gModSettings.iTixaPrisonPOWGridNo[gStrategicStatus.ubNumCapturedForRescue];
			itemdropoffgridno = gModSettings.iTixaPrisonPOWItemGridNo[gStrategicStatus.ubNumCapturedForRescue];
		}
		#endif
		else //if ( gubQuest[QUEST_HELD_IN_ALMA] == QUESTDONE )
		{
			//-teleport him to N7
			pSoldier->sSectorX = gModSettings.ubMeanwhileInterrogatePOWSectorX; //7
			pSoldier->sSectorY = gModSettings.ubMeanwhileInterrogatePOWSectorY; //14
			pSoldier->bSectorZ = 0;
			pSoldier->usStrategicInsertionData = gModSettings.iMeanwhileInterrogatePOWGridNo[gStrategicStatus.ubNumCapturedForRescue];
			itemdropoffgridno = gModSettings.iMeanwhileInterrogatePOWItemGridNo[gStrategicStatus.ubNumCapturedForRescue];
		}
		
		// OK, drop all items!
		UINT32 invsize = pSoldier->inv.size();
		for ( i = 0; i < invsize; ++i )
		{
			if ( pSoldier->inv[i].exists() )
			{
				WorldItem.fExists = TRUE;
				WorldItem.sGridNo = itemdropoffgridno;
				WorldItem.ubLevel = 0;
				WorldItem.usFlags = 0;
				WorldItem.bVisible = FALSE;
				WorldItem.bRenderZHeightAboveLevel = 0;
				pSoldier->inv[i].MoveThisObjectTo( WorldItem.object );
				pWorldItem.push_back( WorldItem );
			}
		}

		AddWorldItemsToUnLoadedSector( pSoldier->sSectorX, pSoldier->sSectorY, 0, itemdropoffgridno, pWorldItem.size(), pWorldItem, FALSE );

		// put him on the floor!!
		pSoldier->pathing.bLevel = 0;
		pSoldier->ubStrategicInsertionCode = INSERTION_CODE_GRIDNO;

		gStrategicStatus.ubNumCapturedForRescue++;
	}

	//Bandaging him would prevent him from dying (due to low HP)
	pSoldier->bBleeding = 0;

	// wake him up
	if ( pSoldier->flags.fMercAsleep )
	{
		PutMercInAwakeState( pSoldier );
		pSoldier->flags.fForcedToStayAwake = FALSE;
	}

	//Set his life to 50% + or - 10 HP.
	INT8 oldlife = pSoldier->stats.bLife;
	pSoldier->stats.bLife = max(35, pSoldier->stats.bLifeMax / 2);
	
	if ( pSoldier->stats.bLife >= 45 )
	{
		pSoldier->stats.bLife += (INT8)(10 - Random( 21 ) );
	}
		
	// SANDRO - make the lost life insta-healable
	pSoldier->iHealableInjury = ((pSoldier->stats.bLifeMax - pSoldier->stats.bLife) * 100);

	// make him quite exhausted when found
	pSoldier->bBreath = pSoldier->bBreathMax = 50;
	pSoldier->sBreathRed = 0;
	pSoldier->flags.fMercCollapsedFlag = FALSE;
}


void HandleEnemyStatusInCurrentMapBeforeLoadingNewMap()
{
	INT32 i;
	BOOLEAN fMadeCorpse;
	INT8 bKilledEnemies = 0, bKilledCreatures = 0, bKilledRebels = 0, bKilledCivilians = 0;
	return;
	//If any of the soldiers are dying, kill them now.
	for( i = gTacticalStatus.Team[ ENEMY_TEAM ].bFirstID; i <= gTacticalStatus.Team[ ENEMY_TEAM ].bLastID; i++ )
	{
		if( MercPtrs[ i ]->bActive && MercPtrs[ i ]->stats.bLife < OKLIFE && MercPtrs[ i ]->stats.bLife )
		{
			MercPtrs[ i ]->stats.bLife = 0;
			MercPtrs[ i ]->iHealableInjury = 0; // added just for sure - SANDRO
			HandleSoldierDeath( MercPtrs[ i ], &fMadeCorpse );
			bKilledEnemies++;
		}
	}
	//Do the same for the creatures.
	for( i = gTacticalStatus.Team[ CREATURE_TEAM ].bFirstID; i <= gTacticalStatus.Team[ CREATURE_TEAM ].bLastID; i++ )
	{
		if( MercPtrs[ i ]->bActive && MercPtrs[ i ]->stats.bLife < OKLIFE && MercPtrs[ i ]->stats.bLife )
		{
			MercPtrs[ i ]->stats.bLife = 0;
			HandleSoldierDeath( MercPtrs[ i ], &fMadeCorpse );
			bKilledCreatures++;
		}
	}
	//Militia
	for( i = gTacticalStatus.Team[ MILITIA_TEAM ].bFirstID; i <= gTacticalStatus.Team[ MILITIA_TEAM ].bLastID; i++ )
	{
		if( MercPtrs[ i ]->bActive && MercPtrs[ i ]->stats.bLife < OKLIFE && MercPtrs[ i ]->stats.bLife )
		{
			MercPtrs[ i ]->stats.bLife = 0;
			MercPtrs[ i ]->iHealableInjury = 0; // added just for sure - SANDRO
			HandleSoldierDeath( MercPtrs[ i ], &fMadeCorpse );
			bKilledRebels++;
		}
	}
	//Civilians
	for( i = gTacticalStatus.Team[ CIV_TEAM ].bFirstID; i <= gTacticalStatus.Team[ CIV_TEAM ].bLastID; i++ )
	{
		if( MercPtrs[ i ]->bActive && MercPtrs[ i ]->stats.bLife < OKLIFE && MercPtrs[ i ]->stats.bLife )
		{
			MercPtrs[ i ]->stats.bLife = 0;
			MercPtrs[ i ]->iHealableInjury = 0; // added just for sure - SANDRO
			HandleSoldierDeath( MercPtrs[ i ], &fMadeCorpse );
			bKilledCivilians++;
		}
	}

// TEST MESSAGES ONLY!
	if( bKilledCivilians )
		ScreenMsg( FONT_BLUE, MSG_TESTVERSION, L"%d civilians died after you left the sector.", bKilledCivilians );
	if( bKilledRebels )
		ScreenMsg( FONT_BLUE, MSG_TESTVERSION, L"%d militia died after you left the sector.", bKilledRebels );
	if( bKilledEnemies )
		ScreenMsg( FONT_BLUE, MSG_TESTVERSION, L"%d enemies died after you left the sector.", bKilledEnemies );
	if( bKilledCreatures )
		ScreenMsg( FONT_BLUE, MSG_TESTVERSION, L"%d creatures died after you left the sector.", bKilledCreatures );

	if( !gbWorldSectorZ )
	{
		SECTORINFO *pSector;
		pSector = &SectorInfo[ SECTOR(gWorldSectorX, gWorldSectorY) ];
		pSector->ubAdminsInBattle = 0;
		pSector->ubTroopsInBattle = 0;
		pSector->ubElitesInBattle = 0;
		pSector->ubCreaturesInBattle = 0;
		//RecalculateSectorWeight(
	}
	else if( gbWorldSectorZ > 0 )
	{
		UNDERGROUND_SECTORINFO *pSector;
		pSector = FindUnderGroundSector( gWorldSectorX, gWorldSectorY, gbWorldSectorZ );
		if( !pSector )
			return;
		pSector->ubAdminsInBattle = 0;
		pSector->ubTroopsInBattle = 0;
		pSector->ubElitesInBattle = 0;
		pSector->ubCreaturesInBattle = 0;
	}
}

BOOLEAN PlayerSectorDefended( UINT8 ubSectorID )
{
	if ( NumNonPlayerTeamMembersInSector( SECTORX( ubSectorID ), SECTORY( ubSectorID ), MILITIA_TEAM ) )
	{
		//militia in sector
		return TRUE;
	}

	if ( FindMovementGroupInSector( SECTORX( ubSectorID ), SECTORY( ubSectorID ), OUR_TEAM ) )
	{
		// player/militia in sector
		return TRUE;
	}

	return FALSE;
}

//Assumes gTacticalStatus.fEnemyInSector
BOOLEAN OnlyHostileCivsInSector()
{
	SOLDIERTYPE *pSoldier;
	INT32 i;
	BOOLEAN fHostileCivs = FALSE;

	//Look for any hostile civs.
	for( i = gTacticalStatus.Team[ CIV_TEAM ].bFirstID; i <= gTacticalStatus.Team[ CIV_TEAM ].bLastID; i++ )
	{
		pSoldier = MercPtrs[ i ];
		if( pSoldier->bActive && pSoldier->bInSector && pSoldier->stats.bLife )
		{
			if( !pSoldier->aiData.bNeutral )
			{
				fHostileCivs = TRUE;
				break;
			}
		}
	}
	if( !fHostileCivs )
	{ //No hostile civs, so return FALSE
		return FALSE;
	}
	//Look for anybody else hostile.  If found, return FALSE immediately.
	for( i = gTacticalStatus.Team[ ENEMY_TEAM ].bFirstID; i <= gTacticalStatus.Team[ ENEMY_TEAM ].bLastID; i++ )
	{
		pSoldier = MercPtrs[ i ];
		if( pSoldier->bActive && pSoldier->bInSector && pSoldier->stats.bLife )
		{
			if( !pSoldier->aiData.bNeutral )
			{
				return FALSE;
			}
		}
	}
	for( i = gTacticalStatus.Team[ CREATURE_TEAM ].bFirstID; i <= gTacticalStatus.Team[ CREATURE_TEAM ].bLastID; i++ )
	{
		pSoldier = MercPtrs[ i ];
		if( pSoldier->bActive && pSoldier->bInSector && pSoldier->stats.bLife )
		{
			if( !pSoldier->aiData.bNeutral )
			{
				return FALSE;
			}
		}
	}
	for( i = gTacticalStatus.Team[ MILITIA_TEAM ].bFirstID; i <= gTacticalStatus.Team[ MILITIA_TEAM ].bLastID; i++ )
	{
		pSoldier = MercPtrs[ i ];
		if( pSoldier->bActive && pSoldier->bInSector && pSoldier->stats.bLife )
		{
			if( !pSoldier->aiData.bNeutral )
			{
				return FALSE;
			}
		}
	}
	//We only have hostile civilians, don't allow time compression.
	return TRUE;
}

// Flugente check whether a team has nearby members that can be added to the current battle
// Note that this requires separate counts of teammembers in the sector and those that are actually fighting
// This currently does not exist for MILITIA_TEAM, making such a check relatively useless
BOOLEAN CheckPendingNonPlayerTeam( UINT8 usTeam )
{
	if( gbWorldSectorZ )
		return FALSE;

	SECTORINFO *pSector = &SectorInfo[SECTOR( gWorldSectorX, gWorldSectorY )];

	if ( usTeam == ENEMY_TEAM )
	{
		if ( (pSector->ubNumElites + pSector->ubNumTroops + pSector->ubNumAdmins + pSector->ubNumTanks + pSector->ubNumJeeps + pSector->ubNumRobots) > 
			 (pSector->ubElitesInBattle + pSector->ubTroopsInBattle + pSector->ubAdminsInBattle + pSector->ubTanksInBattle + pSector->ubJeepsInBattle + pSector->ubRobotsInBattle) )
			return TRUE;
	}

	for (GROUP *pGroup = gpGroupList; pGroup; pGroup = pGroup->next)
	{
		if ( pGroup->usGroupTeam == usTeam
			&& !pGroup->fVehicle 
			&& pGroup->ubSectorX == gWorldSectorX 
			&& pGroup->ubSectorY == gWorldSectorY )
		{
			if ( usTeam == ENEMY_TEAM )
			{
				if ( pGroup->ubGroupSize > pGroup->pEnemyGroup->ubElitesInBattle + pGroup->pEnemyGroup->ubTroopsInBattle + pGroup->pEnemyGroup->ubAdminsInBattle 
					 + pGroup->pEnemyGroup->ubTanksInBattle + pGroup->pEnemyGroup->ubJeepsInBattle + pGroup->pEnemyGroup->ubRobotsInBattle )
					return TRUE;
			}
			else if ( usTeam == MILITIA_TEAM )
			{
				if ( pGroup->ubGroupSize > pSector->ubNumberOfCivsAtLevel[GREEN_MILITIA] + pSector->ubNumberOfCivsAtLevel[REGULAR_MILITIA] + pSector->ubNumberOfCivsAtLevel[ELITE_MILITIA] )
					return TRUE;
			}
		}
	}

	return FALSE;
}

#ifdef JA2UB
void HandleBloodCatDeaths( SECTORINFO *pSector )
{
	//if the current sector is the first part of the town
	if( gWorldSectorX == 10 && gWorldSectorY == 9 && gbWorldSectorZ == 0 )
	{
		//if ALL the bloodcats are killed
		if( pSector->bBloodCats == 0 )
		{
			UINT8 bId1=-1;
			UINT8 bId2=-1;
			UINT8 bNum=0;

			SetFactTrue( FACT_PLAYER_KILLED_ALL_BETTYS_BLOODCATS );

			//Instantly have betties missing items show up
			//DailyCheckOnItemQuantities( TRUE );

			// Now have a merc say the killed bloodcat quote
			bNum = Get3RandomQualifiedMercs( &bId1, &bId2, NULL );

			//if there are some qualified mercs
			if( bNum != 0 )
			{
				//must make sure TEX doesnt say the quote
				if( bId1 != NOBODY && Menptr[ bId1 ].ubProfile != TEX_UB )
				{
					TacticalCharacterDialogue( &Menptr[ bId1 ], QUOTE_UB_HANDLE_BLOODCATDEATHS );
				}
				else if( bId2 != NOBODY && Menptr[ bId2 ].ubProfile != TEX_UB )
				{
					TacticalCharacterDialogue( &Menptr[ bId2 ], QUOTE_UB_HANDLE_BLOODCATDEATHS );
				}
			}
		}
	}
}
#endif


UINT16 NumTurncoatsOfClassInSector( INT16 sSectorX, INT16 sSectorY, UINT8 aSoldierClass )
{
	// HEADROCK: This is a TEMPORARY fix to avoid the assertion error. Not sure this is the best solution,
	// probably isn't. But I need this bit to work.
	if ( sSectorX < MINIMUM_VALID_X_COORDINATE ||
		sSectorX > MAXIMUM_VALID_X_COORDINATE ||
		sSectorY < MINIMUM_VALID_Y_COORDINATE ||
		sSectorY > MAXIMUM_VALID_Y_COORDINATE )
	{
		return ( 0 );
	}

	AssertGE( sSectorX, MINIMUM_VALID_X_COORDINATE );
	AssertLE( sSectorX, MAXIMUM_VALID_X_COORDINATE );
	AssertGE( sSectorY, MINIMUM_VALID_Y_COORDINATE );
	AssertLE( sSectorY, MAXIMUM_VALID_Y_COORDINATE );

	SECTORINFO* pSector = &SectorInfo[SECTOR( sSectorX, sSectorY )];

	UINT16 num = 0;

	switch ( aSoldierClass )
	{
	case SOLDIER_CLASS_ADMINISTRATOR:	num += pSector->ubNumAdmins_Turncoat;	break;
	case SOLDIER_CLASS_ARMY:            num += pSector->ubNumTroops_Turncoat; 	break;
	case SOLDIER_CLASS_ELITE:           num += pSector->ubNumElites_Turncoat;	break;
	default:							break;
	}

	GROUP* pGroup = gpGroupList;
	while ( pGroup )
	{
		if ( pGroup->usGroupTeam == ENEMY_TEAM && !pGroup->fVehicle && pGroup->ubSectorX == sSectorX && pGroup->ubSectorY == sSectorY )
		{
			switch ( aSoldierClass )
			{
			case SOLDIER_CLASS_ADMINISTRATOR:	num += pGroup->pEnemyGroup->ubNumAdmins_Turncoat;	break;
			case SOLDIER_CLASS_ARMY:            num += pGroup->pEnemyGroup->ubNumTroops_Turncoat; 	break;
			case SOLDIER_CLASS_ELITE:           num += pGroup->pEnemyGroup->ubNumElites_Turncoat;	break;
			default:							break;
			}
		}
		pGroup = pGroup->next;
	}

	return num;
}

BOOLEAN TurncoatsInSector( INT16 sSectorX, INT16 sSectorY )
{
	// HEADROCK: This is a TEMPORARY fix to avoid the assertion error. Not sure this is the best solution,
	// probably isn't. But I need this bit to work.
	if ( sSectorX < MINIMUM_VALID_X_COORDINATE ||
		sSectorX > MAXIMUM_VALID_X_COORDINATE ||
		sSectorY < MINIMUM_VALID_Y_COORDINATE ||
		sSectorY > MAXIMUM_VALID_Y_COORDINATE )
	{
		return ( 0 );
	}

	AssertGE( sSectorX, MINIMUM_VALID_X_COORDINATE );
	AssertLE( sSectorX, MAXIMUM_VALID_X_COORDINATE );
	AssertGE( sSectorY, MINIMUM_VALID_Y_COORDINATE );
	AssertLE( sSectorY, MAXIMUM_VALID_Y_COORDINATE );

	SECTORINFO* pSector = &SectorInfo[SECTOR( sSectorX, sSectorY )];
	
	if ( pSector->ubNumAdmins_Turncoat
		|| pSector->ubNumTroops_Turncoat
		|| pSector->ubNumElites_Turncoat )
		return TRUE;
	
	GROUP* pGroup = gpGroupList;
	while ( pGroup )
	{
		if ( pGroup->usGroupTeam == ENEMY_TEAM && !pGroup->fVehicle && pGroup->ubSectorX == sSectorX && pGroup->ubSectorY == sSectorY )
		{
			if ( pGroup->pEnemyGroup->ubNumAdmins_Turncoat
				|| pGroup->pEnemyGroup->ubNumTroops_Turncoat
				|| pGroup->pEnemyGroup->ubNumElites_Turncoat )
				return TRUE;
		}
		pGroup = pGroup->next;
	}

	return FALSE;
}

bool RemoveOneTurncoat( INT16 sSectorX, INT16 sSectorY, UINT8 aSoldierClass )
{
	// HEADROCK: This is a TEMPORARY fix to avoid the assertion error. Not sure this is the best solution,
	// probably isn't. But I need this bit to work.
	if ( sSectorX < MINIMUM_VALID_X_COORDINATE ||
		sSectorX > MAXIMUM_VALID_X_COORDINATE ||
		sSectorY < MINIMUM_VALID_Y_COORDINATE ||
		sSectorY > MAXIMUM_VALID_Y_COORDINATE )
	{
		return false;
	}

	AssertGE( sSectorX, MINIMUM_VALID_X_COORDINATE );
	AssertLE( sSectorX, MAXIMUM_VALID_X_COORDINATE );
	AssertGE( sSectorY, MINIMUM_VALID_Y_COORDINATE );
	AssertLE( sSectorY, MAXIMUM_VALID_Y_COORDINATE );

	SECTORINFO* pSector = &SectorInfo[SECTOR( sSectorX, sSectorY )];

	// count how many turncoats we have
	UINT16 num_static = 0;
	UINT16 num_groups = 0;

	switch ( aSoldierClass )
	{
	case SOLDIER_CLASS_ADMINISTRATOR:
		num_static = pSector->ubNumAdmins_Turncoat;
		break;
	case SOLDIER_CLASS_ARMY:
		num_static = pSector->ubNumTroops_Turncoat;
		break;
	case SOLDIER_CLASS_ELITE:
		num_static = pSector->ubNumElites_Turncoat;
		break;
	default:
		break;
	}

	GROUP* pGroup = gpGroupList;
	while ( pGroup )
	{
		if ( pGroup->usGroupTeam == ENEMY_TEAM && !pGroup->fVehicle && pGroup->ubSectorX == sSectorX && pGroup->ubSectorY == sSectorY )
		{
			switch ( aSoldierClass )
			{
			case SOLDIER_CLASS_ADMINISTRATOR:
				num_groups += pGroup->pEnemyGroup->ubNumAdmins_Turncoat;
				break;
			case SOLDIER_CLASS_ARMY:
				num_groups += pGroup->pEnemyGroup->ubNumTroops_Turncoat;
				break;
			case SOLDIER_CLASS_ELITE:
				num_groups += pGroup->pEnemyGroup->ubNumElites_Turncoat;
				break;
			default:
				break;
			}
		}
		pGroup = pGroup->next;
	}

	if ( num_static + num_groups )
	{
		if ( Chance( 100 * num_static / ( num_static + num_groups ) ) )
		{
			// add to garrison
			switch ( aSoldierClass )
			{
			case SOLDIER_CLASS_ADMINISTRATOR:
				pSector->ubNumAdmins_Turncoat--;
				return true;
				break;
			case SOLDIER_CLASS_ARMY:
				pSector->ubNumTroops_Turncoat--;
				return true;
				break;
			case SOLDIER_CLASS_ELITE:
				pSector->ubNumElites_Turncoat--;
				return true;
				break;
			default:
				break;
			}
		}
		else
		{
			GROUP* pGroup = gpGroupList;
			while ( pGroup )
			{
				if ( pGroup->usGroupTeam == ENEMY_TEAM && !pGroup->fVehicle && pGroup->ubSectorX == sSectorX && pGroup->ubSectorY == sSectorY )
				{
					switch ( aSoldierClass )
					{
					case SOLDIER_CLASS_ADMINISTRATOR:
						if ( pGroup->pEnemyGroup->ubNumAdmins_Turncoat && pGroup->ubGroupSize && pGroup->pEnemyGroup->ubNumAdmins )
						{
							pGroup->pEnemyGroup->ubNumAdmins_Turncoat--;
							pGroup->pEnemyGroup->ubNumAdmins--;
							pGroup->ubGroupSize--;
							return true;
						}
						break;
					case SOLDIER_CLASS_ARMY:
						if ( pGroup->pEnemyGroup->ubNumTroops_Turncoat && pGroup->ubGroupSize && pGroup->pEnemyGroup->ubNumTroops )
						{
							pGroup->pEnemyGroup->ubNumTroops_Turncoat--;
							pGroup->pEnemyGroup->ubNumTroops--;
							pGroup->ubGroupSize--;
							return true;
						}
						break;
					case SOLDIER_CLASS_ELITE:
						if ( pGroup->pEnemyGroup->ubNumElites_Turncoat && pGroup->ubGroupSize && pGroup->pEnemyGroup->ubNumElites )
						{
							pGroup->pEnemyGroup->ubNumElites_Turncoat--;
							pGroup->pEnemyGroup->ubNumElites--;
							pGroup->ubGroupSize--;
							return true;
						}
						break;
					default:
						break;
					}
				}
				pGroup = pGroup->next;
			}
		}
	}

	return false;
}

bool AddOneTurncoat( INT16 sSectorX, INT16 sSectorY, UINT8 aSoldierClass )
{
	// HEADROCK: This is a TEMPORARY fix to avoid the assertion error. Not sure this is the best solution,
	// probably isn't. But I need this bit to work.
	if ( sSectorX < MINIMUM_VALID_X_COORDINATE ||
		sSectorX > MAXIMUM_VALID_X_COORDINATE ||
		sSectorY < MINIMUM_VALID_Y_COORDINATE ||
		sSectorY > MAXIMUM_VALID_Y_COORDINATE )
	{
		return false;
	}

	AssertGE( sSectorX, MINIMUM_VALID_X_COORDINATE );
	AssertLE( sSectorX, MAXIMUM_VALID_X_COORDINATE );
	AssertGE( sSectorY, MINIMUM_VALID_Y_COORDINATE );
	AssertLE( sSectorY, MAXIMUM_VALID_Y_COORDINATE );

	SECTORINFO* pSector = &SectorInfo[SECTOR( sSectorX, sSectorY )];

	// count how many 'slots' we have for more turncoats, then add one at a random position
	UINT16 freeslots_static = 0;
	UINT16 freeslots_groups = 0;

	switch ( aSoldierClass )
	{
	case SOLDIER_CLASS_ADMINISTRATOR:
		if ( pSector->ubNumAdmins_Turncoat < pSector->ubNumAdmins )
			freeslots_static = pSector->ubNumAdmins - pSector->ubNumAdmins_Turncoat;
		break;
	case SOLDIER_CLASS_ARMY:
		if ( pSector->ubNumTroops_Turncoat < pSector->ubNumTroops )
			freeslots_static = pSector->ubNumTroops - pSector->ubNumTroops_Turncoat;
		break;
	case SOLDIER_CLASS_ELITE:
		if ( pSector->ubNumElites_Turncoat < pSector->ubNumElites )
			freeslots_static = pSector->ubNumElites - pSector->ubNumElites_Turncoat;
		break;
	default:
		break;
	}

	GROUP* pGroup = gpGroupList;
	while ( pGroup )
	{
		if ( pGroup->usGroupTeam == ENEMY_TEAM && !pGroup->fVehicle && pGroup->ubSectorX == sSectorX && pGroup->ubSectorY == sSectorY )
		{
			switch ( aSoldierClass )
			{
			case SOLDIER_CLASS_ADMINISTRATOR:
				if ( pGroup->pEnemyGroup->ubNumAdmins_Turncoat < pGroup->pEnemyGroup->ubNumAdmins )
					freeslots_groups += pGroup->pEnemyGroup->ubNumAdmins - pGroup->pEnemyGroup->ubNumAdmins_Turncoat;
				break;
			case SOLDIER_CLASS_ARMY:
				if ( pGroup->pEnemyGroup->ubNumTroops_Turncoat < pGroup->pEnemyGroup->ubNumTroops )
					freeslots_groups += pGroup->pEnemyGroup->ubNumTroops - pGroup->pEnemyGroup->ubNumTroops_Turncoat;
				break;
			case SOLDIER_CLASS_ELITE:
				if ( pGroup->pEnemyGroup->ubNumElites_Turncoat < pGroup->pEnemyGroup->ubNumElites )
					freeslots_groups += pGroup->pEnemyGroup->ubNumElites - pGroup->pEnemyGroup->ubNumElites_Turncoat;
				break;
			default:
				break;
			}
		}
		pGroup = pGroup->next;
	}

	if ( freeslots_static + freeslots_groups )
	{
		if ( Chance( 100 * freeslots_static / ( freeslots_static + freeslots_groups ) ) )
		{
			// add to garrison
			switch ( aSoldierClass )
			{
			case SOLDIER_CLASS_ADMINISTRATOR:
				pSector->ubNumAdmins_Turncoat++;
				return true;
				break;
			case SOLDIER_CLASS_ARMY:
				pSector->ubNumTroops_Turncoat++;
				return true;
				break;
			case SOLDIER_CLASS_ELITE:
				pSector->ubNumElites_Turncoat++;
				return true;
				break;
			default:
				break;
			}
		}
		else
		{
			GROUP* pGroup = gpGroupList;
			while ( pGroup )
			{
				if ( pGroup->usGroupTeam == ENEMY_TEAM && !pGroup->fVehicle && pGroup->ubSectorX == sSectorX && pGroup->ubSectorY == sSectorY )
				{
					switch ( aSoldierClass )
					{
					case SOLDIER_CLASS_ADMINISTRATOR:
						if ( pGroup->pEnemyGroup->ubNumAdmins_Turncoat < pGroup->pEnemyGroup->ubNumAdmins )
						{
							pGroup->pEnemyGroup->ubNumAdmins_Turncoat++;
							return true;
						}
						break;
					case SOLDIER_CLASS_ARMY:
						if ( pGroup->pEnemyGroup->ubNumTroops_Turncoat < pGroup->pEnemyGroup->ubNumTroops )
						{
							pGroup->pEnemyGroup->ubNumTroops_Turncoat++;
							return true;
						}
						break;
					case SOLDIER_CLASS_ELITE:
						if ( pGroup->pEnemyGroup->ubNumElites_Turncoat < pGroup->pEnemyGroup->ubNumElites )
						{
							pGroup->pEnemyGroup->ubNumElites_Turncoat++;
							return true;
						}
						break;
					default:
						break;
					}
				}
				pGroup = pGroup->next;
			}
		}
	}

	return false;
}

void CorrectTurncoatCount( INT16 sSectorX, INT16 sSectorY )
{
	// HEADROCK: This is a TEMPORARY fix to avoid the assertion error. Not sure this is the best solution,
	// probably isn't. But I need this bit to work.
	if ( sSectorX < MINIMUM_VALID_X_COORDINATE ||
		sSectorX > MAXIMUM_VALID_X_COORDINATE ||
		sSectorY < MINIMUM_VALID_Y_COORDINATE ||
		sSectorY > MAXIMUM_VALID_Y_COORDINATE )
	{
		return;
	}

	AssertGE( sSectorX, MINIMUM_VALID_X_COORDINATE );
	AssertLE( sSectorX, MAXIMUM_VALID_X_COORDINATE );
	AssertGE( sSectorY, MINIMUM_VALID_Y_COORDINATE );
	AssertLE( sSectorY, MAXIMUM_VALID_Y_COORDINATE );

	SECTORINFO* pSector = &SectorInfo[SECTOR( sSectorX, sSectorY )];

	if ( pSector->ubNumAdmins_Turncoat > pSector->ubNumAdmins )
	{
		pSector->ubNumTroops_Turncoat += pSector->ubNumAdmins_Turncoat - pSector->ubNumAdmins;
		pSector->ubNumAdmins_Turncoat = pSector->ubNumAdmins;
	}
	if ( pSector->ubNumTroops_Turncoat > pSector->ubNumTroops )
	{
		pSector->ubNumElites_Turncoat += pSector->ubNumTroops_Turncoat - pSector->ubNumTroops;
		pSector->ubNumTroops_Turncoat = pSector->ubNumTroops;
	}
	if ( pSector->ubNumElites_Turncoat > pSector->ubNumElites )
	{
		pSector->ubNumElites_Turncoat = pSector->ubNumElites;
	}

	GROUP* pGroup = gpGroupList;
	while ( pGroup )
	{
		if ( pGroup->usGroupTeam == ENEMY_TEAM && !pGroup->fVehicle && pGroup->ubSectorX == sSectorX && pGroup->ubSectorY == sSectorY )
		{
			if ( pGroup->pEnemyGroup->ubNumAdmins_Turncoat > pGroup->pEnemyGroup->ubNumAdmins )
			{
				pGroup->pEnemyGroup->ubNumTroops_Turncoat += pGroup->pEnemyGroup->ubNumAdmins_Turncoat - pGroup->pEnemyGroup->ubNumAdmins;
				pGroup->pEnemyGroup->ubNumAdmins_Turncoat = pGroup->pEnemyGroup->ubNumAdmins;
			}
			if ( pGroup->pEnemyGroup->ubNumTroops_Turncoat > pGroup->pEnemyGroup->ubNumTroops )
			{
				pGroup->pEnemyGroup->ubNumElites_Turncoat += pGroup->pEnemyGroup->ubNumTroops_Turncoat - pGroup->pEnemyGroup->ubNumTroops;
				pGroup->pEnemyGroup->ubNumTroops_Turncoat = pGroup->pEnemyGroup->ubNumTroops;
			}
			if ( pGroup->pEnemyGroup->ubNumElites_Turncoat > pGroup->pEnemyGroup->ubNumElites )
			{
				pGroup->pEnemyGroup->ubNumElites_Turncoat = pGroup->pEnemyGroup->ubNumElites;
			}
		}
		pGroup = pGroup->next;
	}
}
