// BZII Community Project Modified MPI DLL.  This class does certain things to make the AI
// team stronger.  It also handles portal functions, and sends enemy units to portals.
// This class's interaction functions (functions triggered by bzone.exe directly or
// indirectly) are called by functions of a similar class called Strategy01 (StratInstant.cpp).
#include "..\shared\SubMission.h"
#include <string.h>

/*
	InstantMission
	Just add water!!
*/

// #define _BZDEBUG // Use for coding and debugging phase

#define MAX_GOODIES 40
#define TEST_INSTANT 0
//#define MaxPortals 16	//@@@Centerline_FE_MPI
#define MaxPortals 24	//@@@Centerline_FE_MPI - increased to allow for larger maps that use all portal groups
#define MaxPortalUserTypes 35	//@@@NB_FE_MPI02

//@@@@@@NB_FE_MPI02 these are not used:
//const int myForce = 1;
//const int compForce = 2;
//const int difficulty = 2;

// scav limit controls
const int MaxCPUScavs=15;	//@@@NB_FE_MPI02 - scav limitation
const int MinCPUScavs=8;	//@@@NB_FE_MPI02 - scav limitation

// vehicle anti-freeze controls
const int MAX_COMBAT_UNITS = 72;	//@@@NB_FE_MPI02
const int MAX_HOLD_UNITS = 8;		//@@@NB_FE_MPI02

// FE MPI Difficulty Options
const int OPTION_LOW = 1;		//@@@NB_FE_MPI02
const int OPTION_NORMAL = 2;	//@@@NB_FE_MPI02
const int OPTION_HIGH = 3;		//@@@NB_FE_MPI02

// Ally Race Codes
const int ALLY_CERBERI = 1;		//@@@NB_FE_MPI02
const int ALLY_HADEAN = 2;		//@@@NB_FE_MPI02
const int ALLY_EDF = 3;			//@@@NB_FE_MPI02
const int ALLY_SCION = 4;		//@@@NB_FE_MPI02


//@@@NB_FE_MPI02 - modified to designate variant portal users
#define ODFArraySize 27
static char ODFType[ODFArraySize][20] =
{
	"vputank",
	"vpuatank",
	"vpuwalk",
	"vpuewalk",
	"vpuscout",
	"vpusent",
	"vpumisl",
	"vpuarch",
	"vpurckt",
	"vpuscav",
	"vpuserv",
	"vpumbike",
	"vpumort",
	"vputanku",
	"vpuatanku",
	"vpumislu",
	"vpurbomb",
	"vputurr",
	"vpuimbk2",
	"vpuirbmb2",
	"vpuirckt2",
	"vpuesct2",
	"vpuemisl2",
	"vpueatnk2",
	"vpufsct2",
	"vpufrbmb2",
	"vpufwalk2"
};


enum AIPType {
	AIPType0=0,
	AIPType1,
	AIPType2,
	AIPType3,
	AIPTypeA,
	AIPTypeL,
	AIPTypeS,
	MAX_AIP_TYPE,
};
const char *AIPTypeExtensions="0123als"; // AIPType above is offset in this string table

char CustomAIPNameBase[256];
static char TempODFName[64];
bool CheckedSVar3=false;
bool UseCustomAIPs;
int siege_switchtime;		//@@@NB_FE_MPI02
int iHold1Count;			//@@@NB_FE_MPI02
int iHold2Count;			//@@@NB_FE_MPI02
int iHold3Count;			//@@@NB_FE_MPI02
int iHold4Count;			//@@@NB_FE_MPI02
int *iUnitptr;				//@@@NB_FE_MPI02
int *iHold1ptr;				//@@@NB_FE_MPI02
int *iHold2ptr;				//@@@NB_FE_MPI02
int *iHold3ptr;				//@@@NB_FE_MPI02
int *iHold4ptr;				//@@@NB_FE_MPI02
float cordon_sanitaire;		//@@@NB_FE_MPI02

//static char Killer3ODF[33];		//@@@Centerline_FE_MPI - for Hard level
//static char Killer2ODF[33];		//@@@Centerline_FE_MPI - for Normal level

class instantMission : public SubMission {
public:
	// ______________________________________________________________________
	instantMission(void)
	{
		b_count = &b_last - &b_first - 1;
		b_array = &b_first + 1;

		f_count = &f_last - &f_first - 1;
		f_array = &f_first + 1;

		h_count = &h_last - &h_first - 1;
		h_array = &h_first + 1;

		i_count = &i_last - &i_first - 1;
		i_array = &i_first + 1;

		m_PortalUser = 0;
		PortalCount = 0;
		didInit = false;

		for (int i=0; i<MaxPortalUserTypes; i++)
		{
			PortalUserTypes[i] = -1;
		}

	}

	// Based on player races and type, set AIPlan
	void SetCPUAIPlan(const int CPUSide,const int HumanSide,AIPType Type);

	// And set up extra race-specific vehicles at pathpoints in the map.
	void SetupExtraVehicles(void);

	//@@@Centerline_FE_MPI - Function added by Centerline
	// Sets up extra random scrap pools at pathpoints in the map.
	void SetupRandomScrapPools(void);

	//@@@Centerline_FE_MPI - Function added by Centerline
	// Spawns the Killer units for the Rampage mode.
//	void SpawnKiller(void);

	virtual void AddObject(Handle h);
	virtual void DeleteObject(Handle h);
	virtual void Setup(void);
	virtual void CreateObjectives();
	virtual void TestObjectives();
	virtual void Execute(bool *TeamIsSetUp, Handle *RecyclerHandles);
	virtual void DoGenericStrategy(bool *TeamIsSetUp, Handle *RecyclerHandles);
	virtual EjectKillRetCodes PlayerEjected(void);
	virtual EjectKillRetCodes PlayerKilled(int KillersHandle);

	void PortalInit();
	void PortalFunctions();
	void SetPortalUsers();
	Handle GetPortalToUse(Handle PortalUser);
	char* RaceOdf(char Race, char* EndString);
	bool IsType (Handle h, char* EndString);
	bool DestinationPortal(void);

private:
	// bools
	bool
		b_first,
		start_done,
		inspect_bunker,
		second_objective,
		picking_up[MAX_GOODIES],
		captured[MAX_GOODIES],
		siege_on,
		anti_assault,
		late_game,
		early_game,
		have_armory,
		have_sbay,		//@@@NB_FE_MPI02
		have_techctr,	//@@@NB_FE_MPI02
		have_trainctr,	//@@@NB_FE_MPI02
		have_portals,	//@@@NB_FE_MPI02
		have_groupE,	//@@@NB_FE_MPI02
		sendEAttack,	//@@@NB_FE_MPI02
		drath_rush,		//@@@NB_FE_MPI02
		didInit,
		HadeanWalkerBuilt,
//		BuiltBomber,	//@@@Centerline_FE_MPI
		b_last;

	// floats
	float
		f_first,
		f,
		f_last;

	// handles
	Handle
		h_first,
		h,
		obj1,
		bunker,
		bunker2,
		player,
		foe1,
		foe2,
		foe3,
		walker,
		tug,
		recycler,
		enemy_recycler,
		powerup1,
		powerup2,
		powerup3,
		powerup4,
		hBomber,	//@@@NB_FE_MPI02
		hLastGT,	//@@@NB_FE_MPI02
		hPrevGT,	//@@@NB_FE_MPI02
		hTurr1,		//@@@NB_FE_MPI02
		hTurr2,		//@@@NB_FE_MPI02
		hTurr3,		//@@@NB_FE_MPI02
		hTurr4,		//@@@NB_FE_MPI02
		hTurr5,		//@@@NB_FE_MPI02
		hTurr6,		//@@@NB_FE_MPI02
		hTurr7,		//@@@Centerline_FE_MPI - increased count of startup units
		hTurr8,		//@@@Centerline_FE_MPI - increased count of startup units
		hTurr9,		//@@@Centerline_FE_MPI - increased count of startup units
		hTurr10,	//@@@Centerline_FE_MPI - increased count of startup units
		goodies[MAX_GOODIES],
		tuglist[MAX_GOODIES],  // keep track of tugs
		holding[MAX_GOODIES],
		CPUScavList[MaxCPUScavs],	//@@@NB_FE_MPI02 - scav limitation
		hCombatUnit[MAX_COMBAT_UNITS],		//@@@NB_FE_MPI02
		hHold1Units[MAX_HOLD_UNITS],		//@@@NB_FE_MPI02
		hHold2Units[MAX_HOLD_UNITS],		//@@@NB_FE_MPI02
		hHold3Units[MAX_HOLD_UNITS],		//@@@NB_FE_MPI02
		hHold4Units[MAX_HOLD_UNITS],		//@@@NB_FE_MPI02
		Portals[MaxPortals],
		UsedPortals[MaxPortalUserTypes],
		m_PortalUser,
		m_PortalToUse,
		groupEPortal,	//@@@NB_FE_MPI02
		groupETarget,	//@@@NB_FE_MPI02
		HadeanWalker,
		h_last;

	// integers
	int
		i_first,
		strat_team,
		i,
		siege_counter,
		assault_counter,
		next_wave,
		next_spawn,
		time_count,
		post_bunker,
		enemy_reinforcement_time,
		friend_reinforcement_time,
		end_counter,
		comp_team,
		powerup_counter,
		turn_counter,
//		myGoal,
		mySide,
		HumanSide,
		NumHumans,
//		difficulty,
		NumCPUScavs,			//@@@NB_FE_MPI02 - scav limitation
		iDiffLvl,				//@@@NB_FE_MPI02
		iScrapBstLvl,			//@@@NB_FE_MPI02
		alt_weapon,				//@@@NB_FE_MPI02
		iNextBomberAttack,		//@@@NB_FE_MPI02
		igroupETrigger,			//@@@NB_FE_MPI02
		iNextgroupEAttack,		//@@@NB_FE_MPI02
		groupETargetType,		//@@@NB_FE_MPI02
		groupERace,				//@@@NB_FE_MPI02
		PortalCount,
		m_PortalGroup,			//@@@NB_FE_MPI02
		PortalGroup[MaxPortals],
		PortalNumber[MaxPortals],	//@@@NB_FE_MPI02
		PortalUserTypes[MaxPortalUserTypes],
		UsedPortalsGroup[MaxPortalUserTypes],	//@@@NB_FE_MPI02
		PortalUserWaitCount,
//		iKillerToggle,	//@@@Centerline_FE_MPI
		i_last;
};


// And set up extra race-specific vehicles at pathpoints in the map.
// Function modified by BS-er to allow a 3rd ODF type to be specified in path names
// for the Hadean race.
// ______________________________________________________________________
void instantMission::SetupExtraVehicles(void)
{
	int pathCount;
	char **pathNames;
	GetAiPaths(pathCount, pathNames);
	unsigned long j,k;

	NumCPUScavs=0;	//@@@NB_FE_MPI02 - scav limitation

	for (int i = 0; i < pathCount; ++i)
	{
		char *Label = pathNames[i];
		if(strncmp(Label,"mpi",3)==0)
		{
			// Starts with MPI. Process it.

			const int MaxODFLen=32;
			char ScionStuff[MaxODFLen+1];
			char ISDFStuff[MaxODFLen+1];
			char HadeanStuff[MaxODFLen+1];

			// Prezap full string contents so we don't have to null-term later
			memset(ScionStuff,0,sizeof(ScionStuff));
			memset(ISDFStuff,0,sizeof(ISDFStuff));
			memset(HadeanStuff,0,sizeof(HadeanStuff));

			j=0;

			// Skip forward until an _
			while((Label[j] != '_') && (Label[j] != '\0'))
			{
				j++;
			}
			if(Label[j]=='\0')
			{
				continue; // Misformat! No _ found! Bail!
			}

			k=0;
			j++; // skip the _. Now, copy out scion stuff
			while((Label[j] != '_') && (Label[j] != '\0'))
			{
				if(k<MaxODFLen)
				{
					ScionStuff[k]=Label[j];
					k++;
				}
				j++;
			}

			if(Label[j]=='\0')
			{
				continue; // Misformat! No _ found! Bail!
			}

			k=0;
			j++; // skip the _. Now, copy out isdf stuff
			ISDFStuff[k]=Label[j]; // Compiler messup test?
			while((Label[j] != '_') && (Label[j] != '\0'))
			{
				if(k<MaxODFLen)
				{
					ISDFStuff[k]=Label[j];
					k++;
				}
				j++;
			}

			if(Label[j]=='\0')
			{
				continue; // Misformat! No _ found! Bail!
			}

			k=0;
			j++; // skip the _. Now, copy out isdf stuff
			HadeanStuff[k]=Label[j]; // Compiler messup test?
			while((Label[j] != '_') && (Label[j] != '\0'))
			{
				if(k<MaxODFLen)
				{
					HadeanStuff[k]=Label[j];
					k++;
				}
				j++;
			}


			// For the CPU?
			if(strncmp(Label,"mpic",4)==0)
			{
				if (mySide==1)  // CPU is Scion
				{
					BuildObject(ScionStuff,comp_team,Label);
				}
				else if (mySide==3)
				{
					BuildObject(HadeanStuff,comp_team,Label);
				}
				else
				{
					BuildObject(ISDFStuff,comp_team,Label);
				}
			}
			else if(strncmp(Label,"mpih",4)==0)
			{ // For the human side
				Handle h;
				if (HumanSide==1)  // Humans are Scion
				{
					h=BuildObject(ScionStuff,strat_team,Label);
				}
				//@@@Centerline_FE_MPI - changed this so that human team
				// startup units are correct when Hadean are selected per Natty
				//
				//else if (mySide==3)
				else if (HumanSide==3)  // Humans are Hadean
				{
					h=BuildObject(HadeanStuff,strat_team,Label);
				}
				else  // Humans are ISDF
				{
					h=BuildObject(ISDFStuff,strat_team,Label);
				}
				SetGroup(h,1);
			}
		}
	}
}


// Function modified by BS-er to invoke AIP plans that involve Hadeans.
// ______________________________________________________________________
void instantMission::SetCPUAIPlan(const int CPUSide,const int HumanSide,AIPType Type)
{
	if(!CheckedSVar3)
	{
		CheckedSVar3=true;
		const char *Contents=GetVarItemStr("network.session.svar3");
		if(Contents[0]== '\0')
		{
			UseCustomAIPs=false;
		}
		else
		{
			UseCustomAIPs=true;
			strncpy(CustomAIPNameBase,Contents,254);
		}
	}

	if((Type<0) || (Type >=MAX_AIP_TYPE))
	{
		Type=AIPType3; // Default
	}

	char AIPFile[512];
	unsigned long EOS; // End of string

	// Prezap contents of string, so that we can safely append
	// characters w/o worrying about having to re-terminate
	memset(AIPFile,0x00,512);

	if(!UseCustomAIPs)
	{
		if (CPUSide==1)
		{ // Scion
			strcpy(AIPFile,"scioninst");
			EOS=strlen(AIPFile);
			AIPFile[EOS]=AIPTypeExtensions[Type];

			if(HumanSide==1)
			{ // vs Scion
				EOS=strlen(AIPFile);
				AIPFile[EOS]='_';
			}
			else if (HumanSide==2)
			{
				EOS=strlen(AIPFile);
				AIPFile[EOS]='i';
			}
			else
			{
				EOS=strlen(AIPFile);
				AIPFile[EOS]='h';
			}

		} // CPU is Scion
		else if (CPUSide==2)
		{ // CPU is ISDF
			strcpy(AIPFile,"isdfinst");
			EOS=strlen(AIPFile);
			AIPFile[EOS]=AIPTypeExtensions[Type];
			
			if(HumanSide==2)
			{ // vs ISDF
				EOS=strlen(AIPFile);
				AIPFile[EOS]='_';
			} 
			else if (HumanSide==1)
			{
				EOS=strlen(AIPFile);
				AIPFile[EOS]='s';
			}
			else
			{
				EOS=strlen(AIPFile);
				AIPFile[EOS]='h';
			}
		} // CPU is ISDF case
		else
		{// CPU is Hadean
			strcpy(AIPFile,"hadeinst");
			EOS=strlen(AIPFile);
			AIPFile[EOS]=AIPTypeExtensions[Type];
			
			if(HumanSide==2)
			{ // vs ISDF
				EOS=strlen(AIPFile);
				AIPFile[EOS]='i';
			} 
			else if (HumanSide==1)
			{
				EOS=strlen(AIPFile);
				AIPFile[EOS]='s';
			}
			else
			{
				EOS=strlen(AIPFile);
				AIPFile[EOS]='_';
			}
		}
	} // !UseCustomAIPs
	else
	{
		// UseCustomAIPs
		strcpy(AIPFile,CustomAIPNameBase);

		EOS=strlen(AIPFile);
		if(CPUSide==1) // CPU Scion
		{
			AIPFile[EOS]='f';
		}
		else if (CPUSide==2)
		{
			AIPFile[EOS]='i';
		}
		else
		{
			AIPFile[EOS]='h';
		}

		if(HumanSide==1) // vs Human Scion
		{
			AIPFile[EOS+1]='f';
		}
		else if (HumanSide==2)
		{
			AIPFile[EOS+1]='i';
		}
		else
		{
			AIPFile[EOS+1]='h';
		}

		AIPFile[EOS+2]=AIPTypeExtensions[Type];
	}

	// Always tack on file extension
	strcat(AIPFile,".aip");
	SetPlan(AIPFile,comp_team);
}


// ______________________________________________________________________
void instantMission::Setup(void)
{
	/*
		Here's where you set the values at the start.  
	*/

	int iX;		//@@@NB_FE_MPI02

	start_done=false;
	time_count=1;
	inspect_bunker=false;
	second_objective=false;
	post_bunker=1;
	enemy_reinforcement_time=2000;
	friend_reinforcement_time=2500;
	end_counter=0;
	comp_team=6;
	strat_team=0;  // the default
	obj1=(-1);

	turn_counter=0;

	
	siege_on=false;
	anti_assault=false;
	siege_counter=0;
	assault_counter=0;		//@@@NB_FE_MPI02
	late_game=false;
	early_game=true;		//@@@NB_FE_MPI02
	have_armory=false;
	have_sbay=false;		//@@@NB_FE_MPI02
	have_techctr=false;		//@@@NB_FE_MPI02
	have_trainctr=false;	//@@@NB_FE_MPI02
	have_portals=false;		//@@@NB_FE_MPI02
	have_groupE=false;		//@@@NB_FE_MPI02
	alt_weapon=false;		//@@@NB_FE_MPI02
	sendEAttack=false;		//@@@NB_FE_MPI02
	drath_rush=false;		//@@@NB_FE_MPI02

	cordon_sanitaire=300.0f;	//@@@NB_FE_MPI02
	siege_switchtime=300;		//450;	//@@@NB_FE_MPI02
		
	powerup1=NULL;
	powerup2=NULL;
	powerup3=NULL;
	powerup4=NULL;

	for (int temp=0;temp<40;temp++)
	{
		goodies[temp]=NULL;
		picking_up[temp]=false;
		captured[temp]=false;
		tuglist[temp]=NULL;
		holding[temp]=NULL;
	}

	hBomber=NULL;	//@@@NB_FE_MPI02
	hTurr1=NULL;	//@@@NB_FE_MPI02
	hTurr2=NULL;	//@@@NB_FE_MPI02
	hTurr3=NULL;	//@@@NB_FE_MPI02
	hTurr4=NULL;	//@@@NB_FE_MPI02
	hTurr5=NULL;	//@@@NB_FE_MPI02
	hTurr6=NULL;	//@@@NB_FE_MPI02
	hTurr7=NULL;	//@@@Centerline_FE_MPI - increased count of startup units
	hTurr8=NULL;	//@@@Centerline_FE_MPI - increased count of startup units
	hTurr9=NULL;	//@@@Centerline_FE_MPI - increased count of startup units
	hTurr10=NULL;	//@@@Centerline_FE_MPI - increased count of startup units

	igroupETrigger=0;		//@@@NB_FE_MPI02
	iNextgroupEAttack=0;	//@@@NB_FE_MPI02
	groupETarget=NULL;		//@@@NB_FE_MPI02
	groupETargetType=0;		//@@@NB_FE_MPI02
	groupERace=0;			//@@@NB_FE_MPI02

	//@@@NB_FE_MPI02
	iUnitptr = hCombatUnit;
	for (iX=0; iX<MAX_COMBAT_UNITS; ++iX) {
		*(iUnitptr + iX)=NULL;
	}
	
	//@@@NB_FE_MPI02
	iHold1ptr = hHold1Units;
	iHold2ptr = hHold2Units;
	iHold3ptr = hHold3Units;
	iHold4ptr = hHold4Units;
	for (iX=0; iX<MAX_HOLD_UNITS; ++iX) {
		*(iHold1ptr + iX)=NULL;
		*(iHold2ptr + iX)=NULL;
		*(iHold3ptr + iX)=NULL;
		*(iHold4ptr + iX)=NULL;
	}

	NumHumans=CountPlayers();

	HadeanWalkerBuilt = false;

	//@@@NB_FE_MPI02
	iDiffLvl=GetVarItemInt("network.session.ivar30");
	switch (iDiffLvl)
	{
	case 2:		iDiffLvl=1;		break;
	case 1:		iDiffLvl=3;		break;
	default:	iDiffLvl=2;		break;
	}

	//@@@NB_FE_MPI02
	iScrapBstLvl=GetVarItemInt("network.session.ivar31");
	switch (iScrapBstLvl)
	{
	case 2:		iScrapBstLvl=1;		break;
	case 1:		iScrapBstLvl=3;		break;
	default:	iScrapBstLvl=2;		break;
	}
	

	/*

	//------------------------------------------------------------------------
	//@@@Centerline_FE_MPI - This section sets up the Rampage (Killer) options
	
	memset(Killer3ODF,0,sizeof(Killer3ODF));
	memset(Killer2ODF,0,sizeof(Killer2ODF));

	iKillerToggle = 0;
	iKillerToggle = GetVarItemInt("network.session.ivar35");
	switch (iKillerToggle)
	{
	case 2:
		{
			PrintConsoleMessage("Rampage Attacks are ON!");
			sprintf(Killer3ODF, "MPITalon2");
			sprintf(Killer2ODF, "MPITalon1");
		}
		break;

	case 1:
		{
			PrintConsoleMessage("Rampage Attacks are OFF!");
		}
		break;

	default:
		{
			PrintConsoleMessage("Rampage Attacks are set to RANDOM!");
			int iCheck = (int)GetRandomFloat(32000);
			iCheck = iCheck%5;
			if ((iCheck == 0) || (iCheck == 2) || (iCheck == 4))
			{
				sprintf(Killer2ODF, "MPITalon1");
				sprintf(Killer3ODF, "MPITalon2");
				//
				// Debug statement for Random setting
				//
				//PrintConsoleMessage("Rampage Attacks are ON!");
			}
			//else
			//{
				//
				// Debug statement for Random setting
				//
				//PrintConsoleMessage("Rampage Attacks are OFF!");
			//}
		}
		break;		
	}

	*/

	char tempstr[64];
	sprintf(tempstr, "Difficulty Level %01d", iDiffLvl);
	PrintConsoleMessage(tempstr);
	sprintf(tempstr, "Scrap Boost Level %01d", iScrapBstLvl);
	PrintConsoleMessage(tempstr);
	//------------------------------------------------------------------------
}


// This function is called when any object is added to the mission.
// Function modified by BS-er to account for Hadean race.
// ______________________________________________________________________
void instantMission::AddObject(Handle h)
{
	int iX;		//@@@NB_FE_MPI02

	if (turn_counter == 0)
	{
		// monitor what objects get built by the mpstrat dll
		if (GetTeamNum(h) == 1)
		{
			if (IsOdf(h, "ivrecy_m"))
			{
				HumanSide=2; // Player is EDF
				recycler = h;
			}
			else if (IsOdf(h, "fvrecy_m"))
			{
				HumanSide=1; // Player is Scion
				recycler = h;
			}
			else if (IsOdf(h, "evrecy_m"))
			{
				HumanSide=3; // Player is Hadean
				recycler = h;
			}

			int ShellRace=GetVarItemInt("network.session.ivar13");
			if(ShellRace == 0)
			{
				mySide=2; // Computer is EDF
			}
			else if (ShellRace == 1)
			{
				mySide=1; // Computer is Scion
			}
			else
			{
				mySide=3; // Computer is Hadean
			}
		}
	}

	if (GetTeamNum(h)==comp_team)
	{
		// See if this unit should go to a portal.
		// Cerberi handled in DoGenericStrategy
		if ((GetRace(h)!='c') || (GetRace(h)!='a'))
		{
			Handle TempHandle = GetPortalToUse(h);
			if (TempHandle != 0 && m_PortalUser == 0)
			{
				//PrintConsoleMessage("--- PortalUser Created");

				m_PortalUser = h;
				PortalUserWaitCount = 0;
				m_PortalToUse = TempHandle;
			}
			else
			{
				if (IsOdf(h,"evpumislu") || IsOdf(h,"ivpurckt")
					|| IsOdf(h,"fvpuarch"))
				{
					m_PortalGroup=0;
					m_PortalUser = h;
					PortalUserWaitCount = 0;
					m_PortalToUse = NULL;
				}
				else if (IsOdf(h,"evpuatank") || IsOdf(h,"ivpurbomb")
					|| IsOdf(h,"fvpurbomb"))
				{
					m_PortalGroup=1;
					m_PortalUser = h;
					PortalUserWaitCount = 0;
					m_PortalToUse = NULL;
				}
				else if (IsOdf(h,"evpuatanku") || IsOdf(h,"ivpuatank")
					|| IsOdf(h,"fvpuwalk"))
				{
					m_PortalGroup=2;
					m_PortalUser = h;
					PortalUserWaitCount = 0;
					m_PortalToUse = NULL;
				}

				//@@@Centerline_FE_MPI - Changed to include the turrets for this portal
				//                       group. 9/9/2003 - removed for testing.
				//else if (IsOdf(h,"ivpuewalk") || IsOdf(h,"ivpuwalk")
				//	|| IsOdf(h,"fvpuatank") || IsOdf(h,"evputurr")
				//	|| IsOdf(h,"ivputurr") || IsOdf(h,"fvputurr"))
				else if (IsOdf(h,"ivpuewalk") || IsOdf(h,"ivpuwalk")
					|| IsOdf(h,"fvpuatank"))
				{
					m_PortalGroup=3;
					m_PortalUser = h;
					PortalUserWaitCount = 0;
					m_PortalToUse = NULL;
				}
				else if (IsType(h,"vputank") || IsType(h,"vpuscout")
					|| IsType(h,"vpusent"))
				{
					m_PortalGroup=5;
					m_PortalUser = h;
					PortalUserWaitCount = 0;
					m_PortalToUse = NULL;
				}
				else if (IsType(h,"vpuscav") || IsType(h,"vpuserv")
					|| IsType(h,"vpumbike") || IsType(h,"vpumort")
					|| IsType(h,"vputanku"))
				{
					RemoveObject(h);
				}
			}
		}

		//@@@NB_FE_MPI02
		// Scav cleanup code suggested by Nathan Mates 7/20/01:
		if(IsType(h,"vscav"))
		{
			// Add new scav to list:
			if(NumCPUScavs<MaxCPUScavs) CPUScavList[NumCPUScavs++] = h;

			// Cleanup if number of scavs reaches maximum allowed: 
			if(NumCPUScavs>=MaxCPUScavs) {
				int i,j;

				for(i=0,j=0;i<MaxCPUScavs;i++) {
					// Make sure it's still present, on the CPU team, and a vehicle scav.
					if (IsAround(CPUScavList[i]) &&
						 (GetTeamNum(CPUScavList[i])==comp_team) &&
						 IsType(h,"vscav")) {

						// Oldest Scavs get to live. Hopefully, they're the
						// furthest from the recycler.
						if(j<MinCPUScavs)
							CPUScavList[j++]=CPUScavList[i];
						else {
							SetNoScrapFlagByHandle(CPUScavList[i]);
							RemoveObject(CPUScavList[i]);
						}
					}
				} // Loop over all CPU scavs.

				// Clean up rest of list.
				for(i=j;i<MaxCPUScavs;i++) CPUScavList[i]=0;
				NumCPUScavs=j;

			} // Cleanup time triggered.
		}
		else
		// Track all combat vehicles (except portal users):
		{
			if (IsType(h,"vtank") ||
				IsType(h,"vatank") ||
				IsType(h,"vwalk") ||
				IsOdf(h,"ivewalk") ||
				IsType(h,"vscout") ||
				IsType(h,"vsent") ||
				IsType(h,"varch") ||
				IsType(h,"vartl") ||
				IsType(h,"vmisl") ||
				IsType(h,"vrckt") ||
				IsType(h,"vmbike") ||
				IsType(h,"vmort") ||
				IsType(h,"vtanku") ||
				IsType(h,"vatanku") ||
				IsType(h,"vmislu") ||
				IsType(h,"vmislw") ||
				IsType(h,"vmorts") ||
				IsType(h,"vscoutu") ||
				IsType(h,"vtankf") ||
				IsType(h,"vtanks") ||
				IsType(h,"vatankl") ||
				IsType(h,"vatanks") ||
				IsType(h,"vrbomb"))
			{
				for (iX=0; iX<MAX_COMBAT_UNITS; ++iX) {
					if (*(iUnitptr+iX)==NULL) {
						*(iUnitptr+iX)=h;
						break;
					}
				}
			}
		}

		
		//SetSkill(h,difficulty+1);

		//@@@NB_FE_MPI02
		if (iDiffLvl==OPTION_LOW)
		{
			SetSkill(h,2);
		}
		else
		{
			if (NumHumans>2) SetSkill(h,3);
			else if (NumHumans>1)
			{
				if (mySide==1 && have_sbay) SetSkill(h,3);
				else if (mySide!=1 && have_armory) SetSkill(h,3);
			}
			else if (mySide==1 && have_armory) SetSkill(h,3);
			else if (mySide!=1 && have_sbay) SetSkill(h,3);
			else SetSkill(h,2);
		}


		if ((IsType(h,"barmo")) || (IsOdf(h,"fbstro")))
		{
			have_armory=true;
		}

		//@@@NB_FE_MPI02
		if ((IsType(h,"btrain")) || (IsOdf(h,"fbantm")))
		{
			have_trainctr=true;
		}

		//@@@NB_FE_MPI02
		if ((IsType(h,"btcen")) || (IsOdf(h,"fbover")))
		{
			have_techctr=true;
		}

		//@@@NB_FE_MPI02
		if ((IsType(h,"bsbay")) || (IsOdf(h,"fbdowe")))
		{
			have_sbay=true;
		}


		if (have_armory)
		{
			if (IsOdf(h,"ivtank") || IsOdf(h,"ivputank"))
			{
				GiveWeapon(h,"gspstab_c");
			} 
			else if (IsOdf(h,"ivscout") || IsOdf(h,"ivpuscout"))
			{
				//@@@NB_FE_MPI02
				GiveWeapon(h,"gchain_c");
				if (late_game) GiveWeapon(h,"gbchain_c");
			} 
			else if (IsOdf(h,"ivturr") || IsOdf(h,"ivputurr"))
			{
				//@@@NB_FE_MPI02
				GiveWeapon(h,"gchain_a");
				if (late_game) GiveWeapon(h,"gbchain_a");
			} 
			else if (IsOdf(h,"ivrckt") || IsOdf(h,"ivpurckt"))
			{
				//@@@NB_FE_MPI02
				if (late_game) GiveWeapon(h,"ghornet");
			} 
			
			else if (IsOdf(h,"fvtank") || IsOdf(h,"fvputank"))
			{
				//@@@NB_FE_MPI02
				GiveWeapon(h,"garc_c");
				GiveWeapon(h,"gdeflect");
				if (!early_game) 
				{ 
					GiveWeapon(h,"gabsorb");
				}
			} 
			else if (IsOdf(h,"fvscout") || IsOdf(h,"fvpuscout"))
			{
				//@@@NB_FE_MPI02
				GiveWeapon(h,"gdeflect");
				if (!early_game) 
				{ 
					GiveWeapon(h,"gabsorb");
				}
			} 
			else if (IsOdf(h,"fvsent") || IsOdf(h,"fvpusent"))
			{
				GiveWeapon(h,"gdeflect");
				if (!early_game) 
				{
					//@@@NB_FE_MPI02
					GiveWeapon(h,"gabsorb");
					if (alt_weapon && have_armory)
					{
						GiveWeapon(h,"gcrubex_c");
					}
					else
					{
						GiveWeapon(h,"ggauss_c");
					}
				}
			} 
			else if (IsOdf(h,"fvarch") || IsOdf(h,"fvpuarch"))
			{
				//@@@NB_FE_MPI02
				GiveWeapon(h,"gdeflect");
				if (!early_game) 
				{
					GiveWeapon(h,"gabsorb");
				}
			} 
			
			else if (IsOdf(h,"evtank") || IsOdf(h,"evputank"))
			{
				//@@@NB_FE_MPI02
				if (alt_weapon)
				{
					GiveWeapon(h,"gslagstab_c");
					GiveWeapon(h,"gslicer_c");
				}
			}
			else if (IsOdf(h,"evscout") || IsOdf(h,"evpuscout"))
			{
				//@@@NB_FE_MPI02
				if (alt_weapon) GiveWeapon(h,"gslicer_c");
			}
			else if (IsOdf(h,"evtanku") || IsOdf(h,"evputanku"))
			{
				//@@@NB_FE_MPI02
				if (alt_weapon && have_trainctr)
				{
					GiveWeapon(h,"gfbgun_c");
					GiveWeapon(h,"geburst_c");
				}
			}
			else if (IsOdf(h,"evturr") || IsOdf(h,"evputurr"))
			{
				//@@@NB_FE_MPI02
				if (alt_weapon) GiveWeapon(h,"gcphcg_a");
			}
			else if (IsOdf(h,"evmort") || IsOdf(h,"evpumort"))
			{
				//@@@NB_FE_MPI02
				if (have_techctr || late_game) GiveWeapon(h,"ghfire");
			}
		}
	
		//@@@NB_FE_MPI02
		//initial bomber attack
		if (IsOdf(h,"ivbomb")) 
		{
			Handle hTarget;
			hTarget = GetObjectByTeamSlot(strat_team,DLL_TEAM_SLOT_BOMBERBAY);
			if (!IsAround(hTarget)) 
			{
				hTarget = GetObjectByTeamSlot(strat_team,DLL_TEAM_SLOT_FACTORY);
				if (!IsAround(hTarget)) 
				{
					hTarget = GetObjectByTeamSlot(strat_team,DLL_TEAM_SLOT_RECYCLER);
				}
			}
			Attack(h,hTarget);
			hBomber = h;
			iNextBomberAttack = time_count + ((((time_count/10)%7)+8)*600);
		}
	}

	if (GetTeamNum(h)==strat_team)
	{
		if (IsType(h,"brecy_m"))
		{
			/*
				SetAip here based on turn_counter
			*/

			int stratchoice = turn_counter%2;

			switch (stratchoice)
			{
			case 0:
				//PrintConsoleMessage("Switching to AIP 1.");
				SetCPUAIPlan(mySide,HumanSide,AIPType1);
				break;
			case 1:
				//PrintConsoleMessage("Switching to AIP 3.");
				SetCPUAIPlan(mySide,HumanSide,AIPType3);
				break;
			case 2:
				//PrintConsoleMessage("Switching to AIP 2.");
				SetCPUAIPlan(mySide,HumanSide,AIPType2);
				break;
			}
		}


		/*

		//************************************************************
		// Check to see if the human team has built the bomber
		// and if so set the BuiltBomber flag so "Killer" routine
		// is triggered.
		//
		// Maybe look at having "Killer" routine attack a Hadean and
		// a Scion building in future revision.
		//
		else if (IsOdf(h,"ivbomb"))
		{
			Handle hTarget;
			hTarget = GetObjectByTeamSlot(strat_team,DLL_TEAM_SLOT_BOMBERBAY);
			if (IsAround(hTarget)) 
			{
				BuiltBomber = true;

				//Debug statement
				PrintConsoleMessage("Human team built bomber bay!");
			}
		}
		//**********************************************************

		*/
		
		//@@@NB_FE_MPI02
		else if ((IsType(h,"bfact")) || (IsOdf(h,"fbkiln"))) {
			if (igroupETrigger==0) {
				// set the alien attack trigger
				igroupETrigger = (turn_counter%2)+1;
			}
		}
		else if ((IsType(h,"barmo")) || (IsOdf(h,"fbstro"))) {
			if (iNextgroupEAttack==0 && igroupETrigger==1) {
				// initialize the alien attack interval
				iNextgroupEAttack = time_count+7200-((NumHumans-1)*900)+((time_count/10)%600);
			}
		}
		else if ((IsType(h,"bsbay")) || (IsOdf(h,"fbdowe"))) {
			if (iNextgroupEAttack==0 && igroupETrigger==2) {
				// initialize the alien attack interval
				iNextgroupEAttack = time_count+7200-((NumHumans-1)*900)+((time_count/10)%600);
			}
		}
		else if ((IsType(h,"bcbun")) || (IsOdf(h,"fbantm"))) {
			if (iNextgroupEAttack==0 && igroupETrigger==3) {
				// initialize the alien attack interval
				iNextgroupEAttack = time_count+7200-((NumHumans-1)*900)+((time_count/10)%600);
			}
		}
		
		else
		{
			if ((IsType(h,"vatank")) 
				|| (IsType(h,"vwalk"))
				|| (IsType(h,"vatanku"))		//@@@NB_FE_MPI02
				|| (IsType(h,"vatankl"))		//@@@NB_FE_MPI02
				|| (IsType(h,"vatanks"))		//@@@NB_FE_MPI02
				|| (IsOdf(h,"ivewalk")))	    //@@@NB_FE_MPI02
			{
				assault_counter++;

				//@@@NB_FE_MPI02
				if (anti_assault) {
					groupETarget=h;
					if ((IsType(h,"vatank")) 
						|| (IsType(h,"vatanku"))
						|| (IsType(h,"vatankl"))
						|| (IsType(h,"vatanks"))) 
					{
						groupETargetType=1;
					}
					else 
					{
						groupETargetType=2;
					}
					sendEAttack=true;
				}
			}

			//@@@NB_FE_MPI02
			else if ((IsOdf(h,"ibgtow")) || (IsOdf(h,"fbspir")) 
				|| (IsOdf(h,"ebgt2g")) || (IsOdf(h,"ebgt4g")))
			{
				if (iDiffLvl!=OPTION_LOW)
				{
					hPrevGT=hLastGT;
					hLastGT=h;

					groupETarget=h;
					groupETargetType=3;
					sendEAttack=true;
				}
			}
			else if (IsOdf(h,"ibpgen") || IsOdf(h,"ebpgen"))
			{
				if (iDiffLvl==OPTION_HIGH)
				{
					groupETarget=h;
					groupETargetType=4;
					sendEAttack=true;
				}
			}
			else if (IsOdf(h,"fblung") && ((time_count/10)%3==0))
			{
				if (iDiffLvl==OPTION_HIGH)
				{
					groupETarget=h;
					groupETargetType=4;
					sendEAttack=true;
				}
			}
		}

		//@@@NB_FE_MPI02
		// Set human team unit skill level:
		SetSkill(h,3);
	}	
}


// ______________________________________________________________________
void instantMission::DeleteObject(Handle h)
{
	int iX;		//@@@NB_FE_MPI02

	//@@@NB_FE_MPI02
	if (GetTeamNum(h)==strat_team) 
	{
		if ((IsType(h,"vatank")) 
			|| (IsType(h,"vwalk"))
			|| (IsType(h,"vatanku"))		//@@@NB_FE_MPI02
			|| (IsType(h,"vatankl"))		//@@@NB_FE_MPI02
			|| (IsType(h,"vatanks"))		//@@@NB_FE_MPI02
			|| (IsOdf(h,"ivewalk")))	//@@@NB_FE_MPI02
		{
			--assault_counter;
		}
	}


	//@@@NB_FE_MPI02
	if (GetTeamNum(h)==comp_team)
	{
		//reset armory switch if armory is destroyed
		if ((IsType(h,"barmo")) || (IsOdf(h,"fbstro"))) {
			have_armory=false;
		}

		//@@@NB_FE_MPI02
		else if ((IsType(h,"btrain")) || (IsOdf(h,"fbantm"))) {
			have_trainctr=false;
		}

		//@@@NB_FE_MPI02
		else if ((IsType(h,"btcen")) || (IsOdf(h,"fbover"))) {
			have_techctr=false;
		}

		//@@@NB_FE_MPI02
		else if ((IsType(h,"bsbay")) || (IsOdf(h,"fbdowe"))) {
			have_sbay=false;
		}

		//@@@NB_FE_MPI02
		else if (IsType(h,"vtank") ||
				IsType(h,"vatank") ||
				IsType(h,"vwalk") ||
				IsOdf(h,"ivewalk") ||
				IsType(h,"vscout") ||
				IsType(h,"vsent") ||
				IsType(h,"varch") ||
				IsType(h,"vartl") ||
				IsType(h,"vmisl") ||
				IsType(h,"vrckt") ||
				IsType(h,"vmbike") ||
				IsType(h,"vmort") ||
				IsType(h,"vtanku") ||
				IsType(h,"vatanku") ||
				IsType(h,"vmislu") ||
				IsType(h,"vmislw") ||
				IsType(h,"vmorts") ||
				IsType(h,"vscoutu") ||
				IsType(h,"vtankf") ||
				IsType(h,"vtanks") ||
				IsType(h,"vatankl") ||
				IsType(h,"vatanks") ||
				IsType(h,"vrbomb"))
		{
			for (iX=0; iX<MAX_COMBAT_UNITS; ++iX) {
				if (*(iUnitptr+iX)==h) {
					*(iUnitptr+iX)=NULL;
					break;
				}
			}
		}

	}


	// Make a sniped unit neutral
	Handle Shooter = GetWhoShotMe(h);
	if (IsPlayer(Shooter) && IsPerson(Shooter)
		 && (GetTeamNum(h)==comp_team) && !IsPerson(h))
	{
		SetTeamNum(h, 0);
	}
}


// ______________________________________________________________________
void instantMission::CreateObjectives()
{
}


// ______________________________________________________________________
void instantMission::TestObjectives()
{
	// game end conditions will be handled by the strat code
}


// This function is called every 0.1 seconds.  Due to the net code, its effects on
// the game can be delayed by up to 2 seconds.
// ______________________________________________________________________
void instantMission::Execute(bool *TeamIsSetUp, Handle *RecyclerHandles)
{
	int iX;	//@@@NB_FE_MPI02
	bool dead_portal=false;	//@@@NB_FE_MPI02

	if (!didInit)
	{
		PortalInit();		// Initialize all portals.
		SetPortalUsers();	// Set up the portal user types.
		didInit = true;
	}

	player=GetPlayerHandle();
	turn_counter++;

	//@@@ set random variables here
	alt_weapon = ((((turn_counter/10)%2)==1) ? true : false);	//@@@NB_FE_MPI02

	DoGenericStrategy(TeamIsSetUp, RecyclerHandles);

	// General portal transport.
	if (have_portals) PortalFunctions();	//@@@NB_FE_MPI02

	// If a portal user has been created then send him to his designated portal.
	if (m_PortalUser != 0)
	{
		if (have_portals)	//@@@NB_FE_MPI02
		{
			// Give the unit 1 second after creation, then command it to the portal.
			if (++PortalUserWaitCount > 10)
			{
				if (IsAround(m_PortalToUse))
				{
					Goto(m_PortalUser, m_PortalToUse, 1);
					m_PortalUser = 0;
				}
				else
				{
					dead_portal=true;	//@@@NB_FE_MPI02
				}
			}
		}

		//@@@NB_FE_MPI02
		if (!have_portals || dead_portal)
		{
			switch (m_PortalGroup)
			{
			case 0: 
				Goto(m_PortalUser, "hold1");
				if (!IsType(m_PortalUser,"vputurr"))
				{
					for (iX=0; iX<MAX_HOLD_UNITS; ++iX) {
						if (*(iHold1ptr+iX)==NULL || !IsAround(*(iHold1ptr+iX))) {
							*(iHold1ptr+iX)=m_PortalUser;
							break;
						}
					}
				}
				break;
			case 1: 
				Goto(m_PortalUser, "hold2");
				if (!IsType(m_PortalUser,"vputurr"))
				{
					for (iX=0; iX<MAX_HOLD_UNITS; ++iX) {
						if (*(iHold2ptr+iX)==NULL || !IsAround(*(iHold2ptr+iX))) {
							*(iHold2ptr+iX)=m_PortalUser;
							break;
						}
					}
				}
				break;
			case 2: 
				Goto(m_PortalUser, "hold3");
				if (!IsType(m_PortalUser,"vputurr"))
				{
					for (iX=0; iX<MAX_HOLD_UNITS; ++iX) {
						if (*(iHold3ptr+iX)==NULL || !IsAround(*(iHold3ptr+iX))) {
							*(iHold3ptr+iX)=m_PortalUser;
							break;
						}
					}
				}
				break;
			case 3: 
				Goto(m_PortalUser, "hold4");
				if (!IsType(m_PortalUser,"vputurr"))
				{
					for (iX=0; iX<MAX_HOLD_UNITS; ++iX) {
						if (*(iHold4ptr+iX)==NULL || !IsAround(*(iHold4ptr+iX))) {
							*(iHold4ptr+iX)=m_PortalUser;
							break;
						}
					}
				}
				break;
			case 4: RemoveObject(m_PortalUser); break;	// Cerberi
			default:
				if (IsType(m_PortalUser,"vpuscout") || IsType(m_PortalUser,"vpusent"))
				{
					Patrol(m_PortalUser,"patrolBase1");
				}
				else if (IsType(m_PortalUser,"vputank"))
				{
					Patrol(m_PortalUser,"patrolBase2");
				}
				else
				{
					Handle hTarget;
					hTarget=GetObjectByTeamSlot(1, (((turn_counter/10)%5)+1));
					if (!IsAround(hTarget)) 
					{
						hTarget = GetObjectByTeamSlot(strat_team,DLL_TEAM_SLOT_RECYCLER);
						if (!IsAround(hTarget)) 
						{
							hTarget = GetObjectByTeamSlot(strat_team,DLL_TEAM_SLOT_FACTORY);
						}
					}
					Attack(m_PortalUser, hTarget);
				}
				break;
			}
			m_PortalUser = 0;
		}
	}
}


//Function modified by BS-er to account for Hadeans.
// ______________________________________________________________________
void instantMission::DoGenericStrategy(bool *TeamIsSetUp, Handle *RecyclerHandles)
{
	int iX;		//@@@NB_FE_MPI02
	
	time_count++;
	
	if (!start_done)
	{
		strat_team=1;

		start_done=true;


		//@@@NB_FE_MPI02
		// Reset team colors:
		ClearTeamColor(strat_team);
		if ((HumanSide==1) && (mySide==1)) { // Both Teams Scion
			SetTeamColor(comp_team, 31, 127, 95);  //green
		}
		else if ((HumanSide==2) && (mySide==2)) { // Both Teams EDF
			SetTeamColor(comp_team, 31, 95, 127);  //blue
		}
		else if ((HumanSide==3) && (mySide==3)) { // Both Teams Hadean
			SetTeamColor(comp_team, 127, 64, 0);  //red
		}
		else {
			ClearTeamColor(comp_team);
		}


		//@@@!NB_FE_MPI02
		// Set Ally Race
		switch (HumanSide)
		{
		case 1:	//Scion
			switch (mySide)
			{
			case 1:		groupERace=ALLY_EDF;		break;
			case 2:		groupERace=ALLY_HADEAN;		break;
			case 3:		groupERace=ALLY_CERBERI;	break;
			default:	groupERace=ALLY_CERBERI;	break;
			}
			break;
		case 2:	//EDF
			switch (mySide)
			{
			case 1:		groupERace=ALLY_HADEAN;		break;
			case 2:		groupERace=ALLY_SCION;		break;
			case 3:		groupERace=ALLY_CERBERI;	break;
			default:	groupERace=ALLY_CERBERI;	break;
			}
			break;
		case 3:	//Hadean
			switch (mySide)
			{
			case 1:		groupERace=ALLY_EDF;		break;
			case 2:		groupERace=ALLY_SCION;		break;
			case 3:		groupERace=ALLY_CERBERI;	break;
			default:	groupERace=ALLY_CERBERI;	break;
			}
			break;
		default:	groupERace=ALLY_CERBERI;	break;
		}


		SetupExtraVehicles();
		
		//@@@Centerline_FE_MPI - Added this call to build the random scrap pools
		SetupRandomScrapPools();

		// get Instant My Side
		if (mySide==1)
		{ // CPU is Scion
			enemy_recycler=BuildObject("fvrecy",comp_team,"RecyclerEnemy");
			TeamIsSetUp[comp_team]=true;
			RecyclerHandles[comp_team]=enemy_recycler;

			hTurr1 = BuildObject("fvturr",comp_team,"turretEnemy1");
			hTurr2 = BuildObject("fvturr",comp_team,"turretEnemy2");
			hTurr3 = BuildObject("fvturr",comp_team,"turretEnemy3");
			hTurr4 = BuildObject("fvturr",comp_team,"turretEnemy4");
			hTurr5 = BuildObject("fvturr",comp_team,"turretEnemy5");
			hTurr6 = BuildObject("fvturr",comp_team,"turretEnemy6");
			hTurr7 = BuildObject("fvturr",comp_team,"turretEnemy7");	//@@@Centerline_FE_MPI - increased count of startup units
			hTurr8 = BuildObject("fvturr",comp_team,"turretEnemy8");	//@@@Centerline_FE_MPI - increased count of startup units
			hTurr9 = BuildObject("fvturr",comp_team,"turretEnemy9");	//@@@Centerline_FE_MPI - increased count of startup units
			hTurr10 = BuildObject("fvturr",comp_team,"turretEnemy10");	//@@@Centerline_FE_MPI - increased count of startup units

			BuildObject("fvturr",comp_team,"gtow1");
			BuildObject("fvturr",comp_team,"gtow2");
			BuildObject("fvturr",comp_team,"gtow3");
			BuildObject("fvturr",comp_team,"gtow4");
			BuildObject("fvturr",comp_team,"gtow5");

			BuildObject("fvscout",comp_team,"scoutEnemy1");
			BuildObject("fvscout",comp_team,"scoutEnemy2");
			BuildObject("fvscout",comp_team,"scoutEnemy3");
			BuildObject("fvscout",comp_team,"scoutEnemy4");
			BuildObject("fvscout",comp_team,"scoutEnemy5");

			BuildObject("fvtank",comp_team,"tankEnemy1");
			BuildObject("fvtank",comp_team,"tankEnemy2");
			BuildObject("fvtank",comp_team,"tankEnemy3");

			BuildObject("fbjamm",comp_team,"jamm1");
			BuildObject("fbjamm",comp_team,"jamm2");
		}
		else if (mySide==2)
		{ // CPU is EDF
			enemy_recycler=BuildObject("ivrecy",comp_team,"RecyclerEnemy");
			TeamIsSetUp[comp_team]=true;
			RecyclerHandles[comp_team]=enemy_recycler;

			hTurr1 = BuildObject("ivturr",comp_team,"turretEnemy1");
			hTurr2 = BuildObject("ivturr",comp_team,"turretEnemy2");
			hTurr3 = BuildObject("ivturr",comp_team,"turretEnemy3");
			hTurr4 = BuildObject("ivturr",comp_team,"turretEnemy4");
			hTurr5 = BuildObject("ivturr",comp_team,"turretEnemy5");
			hTurr6 = BuildObject("ivturr",comp_team,"turretEnemy6");
			hTurr7 = BuildObject("ivturr",comp_team,"turretEnemy7");	//@@@Centerline_FE_MPI - increased count of startup units
			hTurr8 = BuildObject("ivturr",comp_team,"turretEnemy8");	//@@@Centerline_FE_MPI - increased count of startup units
			hTurr9 = BuildObject("ivturr",comp_team,"turretEnemy9");	//@@@Centerline_FE_MPI - increased count of startup units
			hTurr10 = BuildObject("ivturr",comp_team,"turretEnemy10");	//@@@Centerline_FE_MPI - increased count of startup units

			BuildObject("ivturr",comp_team,"gtow1");
			BuildObject("ivturr",comp_team,"gtow2");
			BuildObject("ivturr",comp_team,"gtow3");
			BuildObject("ivturr",comp_team,"gtow4");
			BuildObject("ivturr",comp_team,"gtow5");

			BuildObject("ivscout",comp_team,"scoutEnemy1");
			BuildObject("ivscout",comp_team,"scoutEnemy2");
			BuildObject("ivscout",comp_team,"scoutEnemy3");
			BuildObject("ivscout",comp_team,"scoutEnemy4");
			BuildObject("ivscout",comp_team,"scoutEnemy5");

			BuildObject("ivtank",comp_team,"tankEnemy1");
			BuildObject("ivtank",comp_team,"tankEnemy2");
			BuildObject("ivtank",comp_team,"tankEnemy3");
		}
		else
		{ // CPU is Hadean
			enemy_recycler=BuildObject("evrecy",comp_team,"RecyclerEnemy");
			TeamIsSetUp[comp_team]=true;
			RecyclerHandles[comp_team]=enemy_recycler;

			hTurr1 = BuildObject("evturr",comp_team,"turretEnemy1");
			hTurr2 = BuildObject("evturr",comp_team,"turretEnemy2");
			hTurr3 = BuildObject("evturr",comp_team,"turretEnemy3");
			hTurr4 = BuildObject("evturr",comp_team,"turretEnemy4");
			hTurr5 = BuildObject("evturr",comp_team,"turretEnemy5");
			hTurr6 = BuildObject("evturr",comp_team,"turretEnemy6");
			hTurr7 = BuildObject("evturr",comp_team,"turretEnemy7");	//@@@Centerline_FE_MPI - increased count of startup units
			hTurr8 = BuildObject("evturr",comp_team,"turretEnemy8");	//@@@Centerline_FE_MPI - increased count of startup units
			hTurr9 = BuildObject("evturr",comp_team,"turretEnemy9");	//@@@Centerline_FE_MPI - increased count of startup units
			hTurr10 = BuildObject("evturr",comp_team,"turretEnemy10");	//@@@Centerline_FE_MPI - increased count of startup units


			BuildObject("evturr",comp_team,"gtow1");
			BuildObject("evturr",comp_team,"gtow2");
			BuildObject("evturr",comp_team,"gtow3");
			BuildObject("evturr",comp_team,"gtow4");
			BuildObject("evturr",comp_team,"gtow5");

			BuildObject("evscout",comp_team,"scoutEnemy1");
			BuildObject("evscout",comp_team,"scoutEnemy2");
			BuildObject("evscout",comp_team,"scoutEnemy3");
			BuildObject("evscout",comp_team,"scoutEnemy4");
			BuildObject("evscout",comp_team,"scoutEnemy5");

			BuildObject("evtank",comp_team,"tankEnemy1");
			BuildObject("evtank",comp_team,"tankEnemy2");
			BuildObject("evtank",comp_team,"tankEnemy3");
		}

		int grp=GetFirstEmptyGroup();			
		SetGroup(recycler,grp);

		SetCPUAIPlan(mySide,HumanSide,AIPType0);

		if (mySide==1) // CPU is Scion
			BuildObject("fvscav",comp_team,"ScavengerEnemy");
		else if (mySide==2) // CPU is EDF
			BuildObject("ivscav",comp_team,"ScavengerEnemy");
		else // CPU is Hadean
			BuildObject("evscav",comp_team,"ScavengerEnemy");

		// power ups?
		BuildObject("apammo",0,"ammo1");
		BuildObject("apammo",0,"ammo2");
		BuildObject("apammo",0,"ammo3");
		BuildObject("aprepa",0,"repair1");
		BuildObject("aprepa",0,"repair2");
		BuildObject("aprepa",0,"repair3");

		SetScrap(comp_team,60);
		SetScrap(1,40);
	} // end if start_done not true

	/*
	if (time_count%enemy_reinforcement_time==0)
	{
		if (compForce>0)
		{
			AddScrap(comp_team,10);
		}
	}
	*/

	if ((time_count%100)==0)
	{ // Evaluate this every 10 seconds
		NumHumans=CountPlayers();
	}


	//if (time_count%(30-(compForce*10)-NumHumans+1)==0)  // this speeds up resources
	//	AddScrap(comp_team,1);

	//@@@NB_FE_MPI02
	int iScrapBoostInt = (300-((NumHumans-1)*50));
	if (iScrapBoostInt < 100) iScrapBoostInt = 100;
	if (time_count%iScrapBoostInt==0)
	{
		AddScrap(comp_team,(iDiffLvl*iScrapBstLvl*3)+(NumHumans*iScrapBstLvl*2));

		if (have_sbay) AddScrap(comp_team,(iDiffLvl*iScrapBstLvl));
		if (have_trainctr) AddScrap(comp_team,(iDiffLvl*iScrapBstLvl*2));
		if (have_techctr) AddScrap(comp_team,(iDiffLvl*iScrapBstLvl*3));
	}


	if (time_count%friend_reinforcement_time==0)
	{
		// power ups?
		BuildObject("apammo",0,"ammo1");
		BuildObject("apammo",0,"ammo2");
		BuildObject("apammo",0,"ammo3");
		BuildObject("aprepa",0,"repair1");
		BuildObject("aprepa",0,"repair2");
		BuildObject("aprepa",0,"repair3");

	}


	//@@@NB_FE_MPI02
	//dispatch holding groups
	if (time_count%1200==0)
	{
		iHold1Count=0;
		iHold2Count=0;
		iHold3Count=0;
		iHold4Count=0;

		// Count holding units
		for (iX=0; iX<MAX_HOLD_UNITS; ++iX) {
			if (*(iHold1ptr+iX)!=NULL) {
				if (IsAround(*(iHold1ptr+iX))) ++iHold1Count;
				else *(iHold1ptr+iX)=NULL;
			}
			if (*(iHold2ptr+iX)!=NULL) {
				if (IsAround(*(iHold2ptr+iX))) ++iHold2Count;
				else *(iHold2ptr+iX)=NULL;
			}
			if (*(iHold3ptr+iX)!=NULL) {
				if (IsAround(*(iHold3ptr+iX))) ++iHold3Count;
				else *(iHold3ptr+iX)=NULL;
			}
			if (*(iHold4ptr+iX)!=NULL) {
				if (IsAround(*(iHold4ptr+iX))) ++iHold4Count;
				else *(iHold4ptr+iX)=NULL;
			}
		}

		// Dispatch holding units
		if (iHold1Count>2)
		{
			for (iX=0; iX<MAX_HOLD_UNITS; ++iX) {
				if (*(iHold1ptr+iX)!=NULL) {
					if (IsAround(*(iHold1ptr+iX))) {
						Handle hTarget;
						hTarget=GetObjectByTeamSlot(1, ((iX%5)+1));
						if (!IsAround(hTarget)) {
							hTarget = GetObjectByTeamSlot(strat_team,DLL_TEAM_SLOT_RECYCLER);
							if (!IsAround(hTarget)) hTarget = GetObjectByTeamSlot(strat_team,DLL_TEAM_SLOT_FACTORY);
						}
						Attack(*(iHold1ptr+iX), hTarget);
					}
					else *(iHold1ptr+iX)=NULL;
				}
			}
		}

		if (iHold2Count>2)
		{
			for (iX=0; iX<MAX_HOLD_UNITS; ++iX) {
				if (*(iHold2ptr+iX)!=NULL) {
					if (IsAround(*(iHold2ptr+iX))) {
						Handle hTarget;
						hTarget=GetObjectByTeamSlot(1, ((iX%5)+1));
						if (!IsAround(hTarget)) {
							hTarget = GetObjectByTeamSlot(strat_team,DLL_TEAM_SLOT_RECYCLER);
							if (!IsAround(hTarget)) hTarget = GetObjectByTeamSlot(strat_team,DLL_TEAM_SLOT_FACTORY);
						}
						Attack(*(iHold2ptr+iX), hTarget);
					}
					else *(iHold2ptr+iX)=NULL;
				}
			}
		}

		if (iHold3Count>1)
		{
			for (iX=0; iX<MAX_HOLD_UNITS; ++iX) {
				if (*(iHold3ptr+iX)!=NULL) {
					if (IsAround(*(iHold3ptr+iX))) {
						Handle hTarget;
						hTarget=GetObjectByTeamSlot(1, ((iX%5)+1));
						if (!IsAround(hTarget)) {
							hTarget = GetObjectByTeamSlot(strat_team,DLL_TEAM_SLOT_RECYCLER);
							if (!IsAround(hTarget)) hTarget = GetObjectByTeamSlot(strat_team,DLL_TEAM_SLOT_FACTORY);
						}
						Attack(*(iHold3ptr+iX), hTarget);
					}
					else *(iHold3ptr+iX)=NULL;
				}
			}
		}

		if (iHold4Count>1)
		{
			for (iX=0; iX<MAX_HOLD_UNITS; ++iX) {
				if (*(iHold4ptr+iX)!=NULL) {
					if (IsAround(*(iHold4ptr+iX))) {
						Handle hTarget;
						hTarget=GetObjectByTeamSlot(1, ((iX%5)+1));
						if (!IsAround(hTarget)) {
							hTarget = GetObjectByTeamSlot(strat_team,DLL_TEAM_SLOT_RECYCLER);
							if (!IsAround(hTarget)) hTarget = GetObjectByTeamSlot(strat_team,DLL_TEAM_SLOT_FACTORY);
						}
						Attack(*(iHold4ptr+iX), hTarget);
					}
					else *(iHold4ptr+iX)=NULL;
				}
			}
		}
	}


	//@@@NB_FE_MPI02
	//dispatch bomber attack
	if ((mySide==2) && (IsAround(hBomber)) && (time_count==iNextBomberAttack)) { 
		Handle hTarget=NULL;
		if (((time_count/10)%5)>2) {
			if (IsAround(hLastGT)) hTarget=hLastGT;
			else if (IsAround(hPrevGT)) hTarget=hPrevGT;
		}
		if (hTarget==NULL) {
			switch ((time_count/10)%5) {
			case 0:
				hTarget = GetObjectByTeamSlot(strat_team,DLL_TEAM_SLOT_BOMBERBAY);
				if (!IsAround(hTarget)) {
					hTarget = GetObjectByTeamSlot(strat_team,DLL_TEAM_SLOT_FACTORY);
					if (!IsAround(hTarget)) {
						hTarget = GetObjectByTeamSlot(strat_team,DLL_TEAM_SLOT_RECYCLER);
					}
				}
				break;
			case 1:
				hTarget = GetObjectByTeamSlot(strat_team,DLL_TEAM_SLOT_BOMBERBAY);
				if (!IsAround(hTarget)) {
					hTarget = GetObjectByTeamSlot(strat_team,DLL_TEAM_SLOT_RECYCLER);
					if (!IsAround(hTarget)) {
						hTarget = GetObjectByTeamSlot(strat_team,DLL_TEAM_SLOT_FACTORY);
					}
				}
				break;
			default:
				hTarget=GetNearestEnemy(hBomber);
				if (!hTarget) {
					hTarget = GetObjectByTeamSlot(strat_team,DLL_TEAM_SLOT_TRAINING);
					if (!IsAround(hTarget)) {
						hTarget = GetObjectByTeamSlot(strat_team,DLL_TEAM_SLOT_ARMORY);
						if (!IsAround(hTarget)) {
							hTarget = GetObjectByTeamSlot(strat_team,DLL_TEAM_SLOT_FACTORY);
							if (!IsAround(hTarget)) {
								hTarget = GetObjectByTeamSlot(strat_team,DLL_TEAM_SLOT_RECYCLER);
							}
						}
					}
				}
				break;
			}
		}

		Attack(hBomber,hTarget);

		if (!siege_on) {
			iNextBomberAttack = time_count + ((((time_count/10)%7)+8)*600);
		} else {
			iNextBomberAttack = time_count + ((((time_count/10)%7)+8)*300);
		}
	}


	// AIP switch logic
	if (!siege_on)
	{
		Handle enemy=GetNearestEnemy(enemy_recycler);

		//@@@NB_FE_MPI02
		//if (GetDistance(enemy,enemy_recycler)<300.0f)
		if (GetDistance(enemy,enemy_recycler)<=cordon_sanitaire) {
			if (siege_counter>0) {
				siege_counter++;	// under siege
			}
			else if (!IsPlayer(enemy)) {
				siege_counter++;	// under siege
			}
		}
		else {
			siege_counter=0;
		}

		//@@@NB_FE_MPI02
		//if (siege_counter>450)
		if (siege_counter>siege_switchtime)
		{ // 45 sec, if we don't change the sim rate :-)
			siege_on=true;
			early_game=false;
			anti_assault=false;
			late_game=false;

			//PrintConsoleMessage("Switching to Anti-Siege.");

			SetCPUAIPlan(mySide,HumanSide,AIPTypeS);

			//@@@NB_FE_MPI02
			if (iNextgroupEAttack>0) iNextgroupEAttack = time_count+100;

			//@@@NB_FE_MPI02
			//replace lost turrets
			if (!IsAround(hTurr1)) {
				if (mySide==1) hTurr1 = BuildObject("fvturr",comp_team,"turretEnemy1");
				if (mySide==2) hTurr1 = BuildObject("ivturr",comp_team,"turretEnemy1");
				if (mySide==3) hTurr1 = BuildObject("evturr",comp_team,"turretEnemy1");
			}
			if (!IsAround(hTurr2)) {
				if (mySide==1) hTurr2 = BuildObject("fvturr",comp_team,"turretEnemy2");
				if (mySide==2) hTurr2 = BuildObject("ivturr",comp_team,"turretEnemy2");
				if (mySide==3) hTurr2 = BuildObject("evturr",comp_team,"turretEnemy2");
			}
			if (!IsAround(hTurr3)) {
				if (mySide==1) hTurr3 = BuildObject("fvturr",comp_team,"turretEnemy3");
				if (mySide==2) hTurr3 = BuildObject("ivturr",comp_team,"turretEnemy3");
				if (mySide==3) hTurr3 = BuildObject("evturr",comp_team,"turretEnemy3");
			}
			if (!IsAround(hTurr4)) {
				if (mySide==1) hTurr4 = BuildObject("fvturr",comp_team,"turretEnemy4");
				if (mySide==2) hTurr4 = BuildObject("ivturr",comp_team,"turretEnemy4");
				if (mySide==3) hTurr4 = BuildObject("evturr",comp_team,"turretEnemy4");
			}
			if (!IsAround(hTurr5)) {
				if (mySide==1) hTurr5 = BuildObject("fvturr",comp_team,"turretEnemy5");
				if (mySide==2) hTurr5 = BuildObject("ivturr",comp_team,"turretEnemy5");
				if (mySide==3) hTurr5 = BuildObject("evturr",comp_team,"turretEnemy5");
			}
			if (!IsAround(hTurr6)) {
				if (mySide==1) hTurr6 = BuildObject("fvturr",comp_team,"turretEnemy6");
				if (mySide==2) hTurr6 = BuildObject("ivturr",comp_team,"turretEnemy6");
				if (mySide==3) hTurr6 = BuildObject("evturr",comp_team,"turretEnemy6");
			}
			if (!IsAround(hTurr7)) {	//@@@Centerline_FE_MPI - increased count of startup units
				if (mySide==1) hTurr7 = BuildObject("fvturr",comp_team,"turretEnemy7");
				if (mySide==2) hTurr7 = BuildObject("ivturr",comp_team,"turretEnemy7");
				if (mySide==3) hTurr7 = BuildObject("evturr",comp_team,"turretEnemy7");
			}
			if (!IsAround(hTurr8)) {	//@@@Centerline_FE_MPI - increased count of startup units
				if (mySide==1) hTurr8 = BuildObject("fvturr",comp_team,"turretEnemy8");
				if (mySide==2) hTurr8 = BuildObject("ivturr",comp_team,"turretEnemy8");
				if (mySide==3) hTurr8 = BuildObject("evturr",comp_team,"turretEnemy8");
			}
			if (!IsAround(hTurr9)) {	//@@@Centerline_FE_MPI - increased count of startup units
				if (mySide==1) hTurr9 = BuildObject("fvturr",comp_team,"turretEnemy9");
				if (mySide==2) hTurr9 = BuildObject("ivturr",comp_team,"turretEnemy9");
				if (mySide==3) hTurr9 = BuildObject("evturr",comp_team,"turretEnemy9");
			}
			if (!IsAround(hTurr10)) {	//@@@Centerline_FE_MPI - increased count of startup units
				if (mySide==1) hTurr10 = BuildObject("fvturr",comp_team,"turretEnemy10");
				if (mySide==2) hTurr10 = BuildObject("ivturr",comp_team,"turretEnemy10");
				if (mySide==3) hTurr10 = BuildObject("evturr",comp_team,"turretEnemy10");
			}

		
			//@@@NB_FE_MPI02
			// Send combat vehicles to patrol or hold:
			for (iX=0; iX<MAX_COMBAT_UNITS; ++iX) {
				if (*(iUnitptr+iX)!=NULL) {
					if (IsAround(*(iUnitptr+iX))) {
						if (IsType(h,"vscout") ||
							IsType(h,"vscoutu") ||
							IsType(h,"vsent"))
						{
							Patrol(*(iUnitptr+iX),"patrolBase1");
						}
						else if (IsType(h,"vtank") ||
							IsType(h,"vmisl") ||
							IsType(h,"varch") ||
							IsType(h,"vmort") ||
							IsType(h,"vtanku") ||
							IsType(h,"vmislw") ||
							IsType(h,"vmorts") ||
							IsType(h,"vtankf") ||
							IsType(h,"vtanks") ||
							IsType(h,"vmislu"))
						{
							Patrol(*(iUnitptr+iX),"patrolBase2");
						}
						else if (IsType(h,"vatank") ||
							IsType(h,"vwalk") ||
							IsOdf(h,"ivewalk") ||
							IsType(h,"vartl") ||
							IsType(h,"vrckt") ||
							IsType(h,"vmbike") ||
							IsType(h,"vatanku") ||
							IsType(h,"vatankl") ||
							IsType(h,"vatanks") ||
							IsType(h,"vrbomb"))
						{
							switch (iX%3)
							{
								case 0:		Goto(*(iUnitptr+iX), "hold1"); break;
								case 1:		Goto(*(iUnitptr+iX), "hold2"); break;
								case 2:		Goto(*(iUnitptr+iX), "hold3"); break;
								default:	Goto(*(iUnitptr+iX), "hold1"); break;
							}
						}
					}
					else {
						// the unit died somewhere, clear the wreckage
						*(iUnitptr+iX)=NULL;
					}
				}
			}


			//@@@NB_FE_MPI02
			//if isdf, dispatch the bomber immediately, if it exists
			if ((mySide==2) && (IsAround(hBomber))) { 
				Handle hTarget;
				hTarget = GetObjectByTeamSlot(strat_team,DLL_TEAM_SLOT_RECYCLER);
				if (!IsAround(hTarget)) {
					hTarget = GetObjectByTeamSlot(strat_team,DLL_TEAM_SLOT_FACTORY);
				}
				Attack(hBomber,hTarget);
				iNextBomberAttack = time_count + ((((time_count/10)%7)+8)*300);
			}
		}
	}  // !siege_on
	else
	{
		Handle enemy=GetNearestEnemy(enemy_recycler);

		//@@@NB_FE_MPI02
		//if (GetDistance(enemy,enemy_recycler)>301.0f)
		if (GetDistance(enemy,enemy_recycler)>cordon_sanitaire)
		{
			//			SetPlan("scioninstl.aip",comp_team);
			siege_on=false;
			early_game=false;
			anti_assault=false;
			late_game=true;

			//PrintConsoleMessage("Switching to Late Game.");

			SetCPUAIPlan(mySide,HumanSide,AIPTypeL);

			//@@@NB_FE_MPI02
			if (iNextgroupEAttack>0) iNextgroupEAttack = time_count+100;
			if (iDiffLvl!=OPTION_LOW) drath_rush=true;

			//@@@NB_FE_MPI02
			// Send combat vehicles to attack:
			for (iX=0; iX<MAX_COMBAT_UNITS; ++iX) {
				if (*(iUnitptr+iX)!=NULL) {
					if (IsAround(*(iUnitptr+iX))) {
						Handle hTarget;
						hTarget=GetObjectByTeamSlot(1, ((iX%5)+1));
						if (!IsAround(hTarget)) 
						{
							hTarget = GetObjectByTeamSlot(strat_team,DLL_TEAM_SLOT_RECYCLER);
							if (!IsAround(hTarget)) 
							{
								hTarget = GetObjectByTeamSlot(strat_team,DLL_TEAM_SLOT_FACTORY);
							}
						}
						Attack(*(iUnitptr+iX), hTarget);
					}
					else {
						// the unit died somewhere, no ghosts allowed
						*(iUnitptr+iX)=NULL;
					}
				}
			}

		}
	}  // siege_on

	// assault_test
	if ((early_game || late_game) && (assault_counter>2))
	{
		anti_assault=true;
		early_game=false;
		late_game=false;
		siege_on=false;

		//PrintConsoleMessage("Switching to Anti-Assault.");

		SetCPUAIPlan(mySide,HumanSide,AIPTypeA);

		//@@@NB_FE_MPI02
		if (iNextgroupEAttack>0) iNextgroupEAttack = time_count+100;

		//@@@NB_FE_MPI02
		// Send combat vehicles to attack:
		for (iX=0; iX<MAX_COMBAT_UNITS; ++iX) {
			if (*(iUnitptr+iX)!=NULL) {
				if (IsAround(*(iUnitptr+iX))) {
					Handle hTarget;
					hTarget=GetObjectByTeamSlot(1, ((iX%5)+1));
					if (!IsAround(hTarget)) 
					{
						hTarget = GetObjectByTeamSlot(strat_team,DLL_TEAM_SLOT_RECYCLER);
						if (!IsAround(hTarget)) 
						{
							hTarget = GetObjectByTeamSlot(strat_team,DLL_TEAM_SLOT_FACTORY);
						}
					}
					Attack(*(iUnitptr+iX), hTarget);
				}
				else {
					// the unit died somewhere, out of sight, out of mind
					*(iUnitptr+iX)=NULL;
				}
			}
		}
	} else
	{
		if (anti_assault && (assault_counter<3))
		{
			anti_assault=false;
			early_game=false;
			late_game=true;
			siege_on=false;

			//PrintConsoleMessage("Switching to Late Game.");

			SetCPUAIPlan(mySide,HumanSide,AIPTypeL);
			
			//@@@NB_FE_MPI02
			// Send combat vehicles to attack:
			for (iX=0; iX<MAX_COMBAT_UNITS; ++iX) {
				if (*(iUnitptr+iX)!=NULL) {
					if (IsAround(*(iUnitptr+iX))) {
						Handle hTarget;
						hTarget=GetObjectByTeamSlot(1, ((iX%5)+1));
						if (!IsAround(hTarget)) 
						{
							hTarget = GetObjectByTeamSlot(strat_team,DLL_TEAM_SLOT_RECYCLER);
							if (!IsAround(hTarget)) 
							{
								hTarget = GetObjectByTeamSlot(strat_team,DLL_TEAM_SLOT_FACTORY);
							}
						}
						Attack(*(iUnitptr+iX), hTarget);
					}
					else {
						// the unit died somewhere, sweep away the debris
						*(iUnitptr+iX)=NULL;
					}
				}
			}
		}
	}

	//@@@NB_FE_MPI02
	// build alien off-map reinforcements
	//
	//@@@Centerline_FE_MPI - modified to check if a DestinationPortal exists before we make
	// more units. If no DestinationPortal exists for groupE then we shouldn't build anymore
	// units.
	//
	//if (have_groupE && IsAround(groupEPortal))
	if (have_groupE && IsAround(groupEPortal) && DestinationPortal())
	{
		Handle hTemp;
		int tmpint;
		int iX;

		if (sendEAttack)
		{
			if (groupETargetType==1)	// assault tank
			{
				//PrintConsoleMessage("Cerberi should attack tank.");

				if (groupERace==ALLY_CERBERI) hTemp=BuildObject("cvpurbomb", comp_team, "groupE");
				else if (groupERace==ALLY_HADEAN) hTemp=BuildObject("avpuemisl2", comp_team, "groupE");
				else if (groupERace==ALLY_EDF) hTemp=BuildObject("avpuirbmb2", comp_team, "groupE");
				else if (groupERace==ALLY_SCION) hTemp=BuildObject("avpufrbmb2", comp_team, "groupE");
				Goto(hTemp, groupEPortal, 1);

				for (iX=0; iX<(NumHumans+1); iX++) {
					if ((turn_counter/10)%(2+iX)>0) {
						if (groupERace==ALLY_CERBERI) hTemp=BuildObject("cvputank", comp_team, "groupE");
						else if (groupERace==ALLY_HADEAN) hTemp=BuildObject("avpuemisl2", comp_team, "groupE");
						else if (groupERace==ALLY_EDF) hTemp=BuildObject("avpuirbmb2", comp_team, "groupE");
						else if (groupERace==ALLY_SCION) hTemp=BuildObject("avpufrbmb2", comp_team, "groupE");
						Goto(hTemp, groupEPortal, 1);
					}
				}
			}
			else if (groupETargetType==2)	// walker
			{
				//PrintConsoleMessage("Cerberi should attack walker.");

				//@@@Centerline_FE_MPI - Reenabled the cvpuwalk and disabled the cvpurbomb
				if (groupERace==ALLY_CERBERI) hTemp=BuildObject("cvpuwalk", comp_team, "groupE");
				//if (groupERace==ALLY_CERBERI) hTemp=BuildObject("cvpurbomb", comp_team, "groupE");

				else if (groupERace==ALLY_HADEAN) hTemp=BuildObject("avpueatnk2", comp_team, "groupE");
				else if (groupERace==ALLY_EDF) hTemp=BuildObject("avpuirckt2", comp_team, "groupE");
				else if (groupERace==ALLY_SCION) hTemp=BuildObject("avpufwalk2", comp_team, "groupE");
				Goto(hTemp, groupEPortal, 1);

				for (iX=0; iX<(NumHumans+1); iX++) {
					if ((turn_counter/10)%(2+iX)>0) {
						if (groupERace==ALLY_CERBERI) hTemp=BuildObject("cvputank", comp_team, "groupE");
						else if (groupERace==ALLY_HADEAN) hTemp=BuildObject("avpuemisl2", comp_team, "groupE");
						else if (groupERace==ALLY_EDF) hTemp=BuildObject("avpuirbmb2", comp_team, "groupE");
						else if (groupERace==ALLY_SCION) hTemp=BuildObject("avpufrbmb2", comp_team, "groupE");
						Goto(hTemp, groupEPortal, 1);
					}
				}
			}
			else if (groupETargetType==3)	// tower
			{
				//PrintConsoleMessage("Cerberi should attack tower.");

				if (iDiffLvl==OPTION_HIGH)
				{
					if (late_game || anti_assault) {
						if (groupERace==ALLY_CERBERI) hTemp=BuildObject("cvpurbomb", comp_team, "groupE");
						else if (groupERace==ALLY_HADEAN) hTemp=BuildObject("avpuemisl2", comp_team, "groupE");
						else if (groupERace==ALLY_EDF) hTemp=BuildObject("avpuirbmb2", comp_team, "groupE");
						else if (groupERace==ALLY_SCION) hTemp=BuildObject("avpufrbmb2", comp_team, "groupE");
						Goto(hTemp, groupEPortal, 1);
					}
					else {
						if (groupERace==ALLY_CERBERI) hTemp=BuildObject("cvputank", comp_team, "groupE");
						else if (groupERace==ALLY_HADEAN) hTemp=BuildObject("avpuemisl2", comp_team, "groupE");
						else if (groupERace==ALLY_EDF) hTemp=BuildObject("avpuirbmb2", comp_team, "groupE");
						else if (groupERace==ALLY_SCION) hTemp=BuildObject("avpufrbmb2", comp_team, "groupE");
						Goto(hTemp, groupEPortal, 1);
					}
				}

				if (!IsOdf(groupETarget,"ebgt2g")) {
					//if (groupERace==ALLY_CERBERI) hTemp=BuildObject("cvpuatank", comp_team, "groupE");
					if (groupERace==ALLY_CERBERI) hTemp=BuildObject("cvpurbomb", comp_team, "groupE");
					else if (groupERace==ALLY_HADEAN) hTemp=BuildObject("avpuemisl2", comp_team, "groupE");
					else if (groupERace==ALLY_EDF) hTemp=BuildObject("avpuirbmb2", comp_team, "groupE");
					else if (groupERace==ALLY_SCION) hTemp=BuildObject("avpufrbmb2", comp_team, "groupE");
					Goto(hTemp, groupEPortal, 1);
				}

				if (groupERace==ALLY_HADEAN) hTemp=BuildObject("avpuesct2", comp_team, "groupE");
				else if (groupERace==ALLY_EDF) hTemp=BuildObject("avpuimbk2", comp_team, "groupE");
				else if (groupERace==ALLY_SCION) hTemp=BuildObject("avpufsct2", comp_team, "groupE");
				if (groupERace!=ALLY_CERBERI) Goto(hTemp, groupEPortal, 1);

				for (iX=0; iX<(NumHumans+2); iX++) {
					if ((turn_counter/10)%(2+iX)>0) {
						if (groupERace==ALLY_CERBERI) hTemp=BuildObject("cvpuscout", comp_team, "groupE");
						else if (groupERace==ALLY_HADEAN) hTemp=BuildObject("avpuesct2", comp_team, "groupE");
						else if (groupERace==ALLY_EDF) hTemp=BuildObject("avpuimbk2", comp_team, "groupE");
						else if (groupERace==ALLY_SCION) hTemp=BuildObject("avpufsct2", comp_team, "groupE");
						Goto(hTemp, groupEPortal, 1);
					}
				}
			}
			else if (groupETargetType==4)	// power
			{
				//PrintConsoleMessage("Cerberi should attack power.");

				if (late_game || anti_assault) {
					if (groupERace==ALLY_CERBERI) hTemp=BuildObject("cvpurbomb", comp_team, "groupE");
					else if (groupERace==ALLY_HADEAN) hTemp=BuildObject("avpuemisl2", comp_team, "groupE");
					else if (groupERace==ALLY_EDF) hTemp=BuildObject("avpuirbmb2", comp_team, "groupE");
					else if (groupERace==ALLY_SCION) hTemp=BuildObject("avpufrbmb2", comp_team, "groupE");
					Goto(hTemp, groupEPortal, 1);
				}

				if (groupERace==ALLY_HADEAN) hTemp=BuildObject("avpuesct2", comp_team, "groupE");
				else if (groupERace==ALLY_EDF) hTemp=BuildObject("avpuimbk2", comp_team, "groupE");
				else if (groupERace==ALLY_SCION) hTemp=BuildObject("avpufsct2", comp_team, "groupE");
				if (groupERace!=ALLY_CERBERI) Goto(hTemp, groupEPortal, 1);

				for (iX=0; iX<(NumHumans+1); iX++) {
					if ((turn_counter/10)%(3+iX)>0) {
						if (groupERace==ALLY_CERBERI) hTemp=BuildObject("cvpuscout", comp_team, "groupE");
						else if (groupERace==ALLY_HADEAN) hTemp=BuildObject("avpuesct2", comp_team, "groupE");
						else if (groupERace==ALLY_EDF) hTemp=BuildObject("avpuimbk2", comp_team, "groupE");
						else if (groupERace==ALLY_SCION) hTemp=BuildObject("avpufsct2", comp_team, "groupE");
						Goto(hTemp, groupEPortal, 1);
					}
				}
			}
			sendEAttack=false;
		}

		if (time_count==iNextgroupEAttack)
		{
			//PrintConsoleMessage("Cerberi should attack base.");

			// Drath rush
			if (drath_rush && (iDiffLvl==OPTION_HIGH))
			{
				for (iX=0; iX<(NumHumans+2); iX++) {
					if ((turn_counter/10)%(2+iX)>0) {
						//@@@Centerline_FE_MPI - Reenabled the cvpuwalk and disabled the cvpurbomb
						if (groupERace==ALLY_CERBERI) hTemp=BuildObject("cvpuwalk", comp_team, "groupE");
						//if (groupERace==ALLY_CERBERI) hTemp=BuildObject("cvpurbomb", comp_team, "groupE");
						
						else if (groupERace==ALLY_HADEAN) hTemp=BuildObject("avpueatnk2", comp_team, "groupE");
						else if (groupERace==ALLY_EDF) hTemp=BuildObject("avpuirckt2", comp_team, "groupE");
						else if (groupERace==ALLY_SCION) hTemp=BuildObject("avpufwalk2", comp_team, "groupE");
						Goto(hTemp, groupEPortal, 1);
					}
				}
				drath_rush=false;
			}

			if (iDiffLvl==OPTION_HIGH)
			{
				for (iX=0; iX<(NumHumans+1); iX++) {
					if ((turn_counter/10)%(3+iX)>0) {
						//@@@Centerline_FE_MPI - Reenabled the cvpuwalk and disabled the cvpurbomb
						if (groupERace==ALLY_CERBERI) hTemp=BuildObject("cvpuwalk", comp_team, "groupE");
						//if (groupERace==ALLY_CERBERI) hTemp=BuildObject("cvpurbomb", comp_team, "groupE");

						else if (groupERace==ALLY_HADEAN) hTemp=BuildObject("avpueatnk2", comp_team, "groupE");
						else if (groupERace==ALLY_EDF) hTemp=BuildObject("avpuirckt2", comp_team, "groupE");
						else if (groupERace==ALLY_SCION) hTemp=BuildObject("avpufwalk2", comp_team, "groupE");
						Goto(hTemp, groupEPortal, 1);
					}
				}
			}

			if (iDiffLvl==OPTION_NORMAL)
			{
				for (iX=0; iX<(NumHumans+1); iX++) {
					if ((turn_counter/10)%(3+iX)>0) {
						//if (groupERace==ALLY_CERBERI) hTemp=BuildObject("cvpuatank", comp_team, "groupE");
						if (groupERace==ALLY_CERBERI) hTemp=BuildObject("cvpurbomb", comp_team, "groupE");
						else if (groupERace==ALLY_HADEAN) hTemp=BuildObject("avpuemisl2", comp_team, "groupE");
						else if (groupERace==ALLY_EDF) hTemp=BuildObject("avpuirbmb2", comp_team, "groupE");
						else if (groupERace==ALLY_SCION) hTemp=BuildObject("avpufrbmb2", comp_team, "groupE");
						Goto(hTemp, groupEPortal, 1);
					}
				}
			}

			if (NumHumans>1) {
				for (iX=0; iX<(NumHumans-1); iX++) {
					if ((turn_counter/10)%(2+iX)>0) {
						if (groupERace==ALLY_CERBERI) hTemp=BuildObject("cvpurbomb", comp_team, "groupE");
						else if (groupERace==ALLY_HADEAN) hTemp=BuildObject("avpuemisl2", comp_team, "groupE");
						else if (groupERace==ALLY_EDF) hTemp=BuildObject("avpuirbmb2", comp_team, "groupE");
						else if (groupERace==ALLY_SCION) hTemp=BuildObject("avpufrbmb2", comp_team, "groupE");
						Goto(hTemp, groupEPortal, 1);
					}
				}
			}

			if (groupERace==ALLY_HADEAN) hTemp=BuildObject("avpuesct2", comp_team, "groupE");
			else if (groupERace==ALLY_EDF) hTemp=BuildObject("avpuimbk2", comp_team, "groupE");
			else if (groupERace==ALLY_SCION) hTemp=BuildObject("avpufsct2", comp_team, "groupE");
			if (groupERace!=ALLY_CERBERI) Goto(hTemp, groupEPortal, 1);

			for (iX=0; iX<(NumHumans+1); iX++) {
				if ((turn_counter/10)%(3+iX)>0) {
					if (groupERace==ALLY_CERBERI) hTemp=BuildObject("cvpuscout", comp_team, "groupE");
					else if (groupERace==ALLY_HADEAN) hTemp=BuildObject("avpuesct2", comp_team, "groupE");
					else if (groupERace==ALLY_EDF) hTemp=BuildObject("avpuimbk2", comp_team, "groupE");
					else if (groupERace==ALLY_SCION) hTemp=BuildObject("avpufsct2", comp_team, "groupE");
					Goto(hTemp, groupEPortal, 1);
				}
			}
	
			if (early_game) tmpint=6600;
			else tmpint=5400;
			if (iDiffLvl==OPTION_LOW) tmpint = tmpint+3000; 
			tmpint = tmpint-((NumHumans-1)*900);
			tmpint = tmpint+((time_count/10)%600);
			if (siege_on) tmpint = tmpint/2;
			iNextgroupEAttack = time_count+tmpint;
		}
	}

	TestObjectives();

//	if (BuiltBomber) SpawnKiller();
}


// ______________________________________________________________________
EjectKillRetCodes instantMission::PlayerEjected(void)
{
	return DoEjectPilot;

}


// ______________________________________________________________________
EjectKillRetCodes instantMission::PlayerKilled(int KillersHandle)
{
	return DoEjectPilot;  // Game over, man.
}


// This function initializes all portals that are labelled PortalA0 ,
// PortalB1 etc. up to PortalF9.
// Function by BS-er
// _________________________________________________________________
void instantMission::PortalInit()
{
	char PortalLabel[10] = "PortalA0";
	Handle TempHandle;
	PortalCount = 0;

	for (int i=0; i<10; i++)
	{
		for (int j=0; j<6; j++)
		{
			PortalLabel[6] = 'A' + j;
			TempHandle = GetHandle(PortalLabel);
			if (IsAround(TempHandle))
			{
				Vector PortalPos;
				GetPosition(TempHandle, PortalPos);
				Handle Nav = BuildObject("ibnav",0,PortalPos);
				SetObjectiveName(Nav, "Portal");
				Portals[PortalCount] = TempHandle;
				PortalGroup[PortalCount] = j;
				PortalNumber[PortalCount] = PortalLabel[7] - 48;	//@@@NB_FE_MPI02

				//@@@NB_FE_MPI02
				if (PortalGroup[PortalCount]==4) 
				{
					have_groupE=true;
					if (PortalNumber[PortalCount]==0) 
					{
						groupEPortal=Portals[PortalCount];
					}
				}
/*
#ifdef _BZDEBUG
				//PrintConsoleMessage("----------");
				char tmpstr[64];
				sprintf(tmpstr, "PortalInit: %s", PortalLabel);
				PrintConsoleMessage(tmpstr);
				//sprintf(tmpstr, "PortalGroup: %d", PortalGroup[PortalCount]);
				//PrintConsoleMessage(tmpstr);
				//sprintf(tmpstr, "PortalNumber: %d", PortalNumber[PortalCount]);
				//PrintConsoleMessage(tmpstr);
#endif
*/
				++PortalCount;
				if (PortalCount >= MaxPortals)
				{
					return;
				}
			}
		}
		PortalLabel[6] = 'A';
		PortalLabel[7]++;
	}

	if (PortalCount > 0) have_portals = true;	//@@@NB_FE_MPI02
}


// This function teleports any object within range of a registered portal.
// It must be called by the Execute function in order to teleport
// objects as necessary.  It is specifically designed to not teleport
// pilots or empty vehicles.
// Function by BS-er
// _________________________________________________________________
void instantMission::PortalFunctions()
{
	int iX;	//@@@NB_FE_MPI02
	bool good_to_go;	//@@@NB_FE_MPI02

	for (int i=0; i<PortalCount; i++)
	{
		good_to_go=true;

		if (IsAround(Portals[i]))
		{
			int PortalTeam = GetTeamNum(Portals[i]);
			Handle NearVehicle = GetNearestObject(Portals[i]);

			if (NearVehicle>0  && !IsOdf(NearVehicle, "ibnav"))
			{
				good_to_go=false;

				//@@@NB_FE_MPI02
				// Teleport only portal user vehicles assigned to the portal group
				for (int n=0; n<MaxPortalUserTypes; n++)
				{
					int TypeIndex = PortalUserTypes[n];
					if (TypeIndex>=0 && IsType(NearVehicle,ODFType[TypeIndex]))
					{
/*
#ifdef _BZDEBUG
						//PrintConsoleMessage("----------");
						char tmpstr[64];
						sprintf(tmpstr, "PortalGroup: %d", PortalGroup[i]);
						PrintConsoleMessage(tmpstr);
						sprintf(tmpstr, "UsedPortalsGroup: %d", UsedPortalsGroup[n]);
						PrintConsoleMessage(tmpstr);
#endif
*/
						if (UsedPortalsGroup[n]==PortalGroup[i])
						{
							good_to_go = true;
							n=MaxPortalUserTypes;	// break the loop
						}
					}
				}
			}

			if ((good_to_go) && (IsWithin(NearVehicle,Portals[i], 15)))
			{
				Vector PortalPos;
				Vector ObjectPos;
				Vector Front;

				GetPosition(NearVehicle, ObjectPos);
				GetPosition(Portals[i], PortalPos);

				if (ObjectPos.y < PortalPos.y + 7.0)
				{
					int j = i;

					for (int k=0; k<PortalCount-1; k++)
					{
						if (++j >= PortalCount)
						{
							j=0;
						}

						if ((PortalGroup[i] == PortalGroup[j]) && IsAround(Portals[j]))
						{
/*
#ifdef _BZDEBUG
							if (IsOdf(NearVehicle, "ibnav")) PrintConsoleMessage("--- Teleporting Nav Beacon");
							PrintConsoleMessage("--- Teleporting PortalUser");
#endif
*/
							int NearVehicleTeam = GetTeamNum(NearVehicle);

							GetPosition(Portals[j], PortalPos);

							GetFront(NearVehicle, Front);
							PortalPos.x += Front.x * 30.0f;
							PortalPos.z += Front.z * 30.0f;

							Front.x *= 8.0f;
							Front.z *= 8.0f;

							if ((PortalTeam == 0) || (PortalTeam == NearVehicleTeam) ||
								IsAlly(NearVehicle, Portals[i]))
							{
								SetVectorPosition(NearVehicle, PortalPos);
							}
							else
							{
								Front.x *= -3;
								Front.z *= -3;
							}
							SetVelocity(NearVehicle, Front);

							if (IsPlayer(NearVehicle))
							{
								if (GetLocalPlayerTeamNumber() == NearVehicleTeam)
								{
									SetColorFade(1.0,1.0,32767);
									StartSoundEffect("teleport.wav");
								}
							}
							else
							{
								Stop(NearVehicle,0);

								if (!IsOdf(NearVehicle, "ibnav"))
								{
/*
#ifdef _BZDEBUG
									PrintConsoleMessage("--- Dispatching PortalUser");
#endif
*/
									//@@@NB_FE_MPI02
									switch (PortalGroup[j]) 
									{
									case 0: 
										Goto(NearVehicle, "hold1");
										if (!IsType(NearVehicle,"vputurr"))
										{
											for (iX=0; iX<MAX_HOLD_UNITS; ++iX) {
												if (*(iHold1ptr+iX)==NULL || !IsAround(*(iHold1ptr+iX))) {
													*(iHold1ptr+iX)=NearVehicle;
													break;
												}
											}
										}
										break;
									case 1: 
										Goto(NearVehicle, "hold2");
										if (!IsType(NearVehicle,"vputurr"))
										{
											for (iX=0; iX<MAX_HOLD_UNITS; ++iX) {
												if (*(iHold2ptr+iX)==NULL || !IsAround(*(iHold2ptr+iX))) {
													*(iHold2ptr+iX)=NearVehicle;
													break;
												}
											}
										}
										break;
									case 2: 
										Goto(NearVehicle, "hold3");
										if (!IsType(NearVehicle,"vputurr"))
										{
											for (iX=0; iX<MAX_HOLD_UNITS; ++iX) {
												if (*(iHold3ptr+iX)==NULL || !IsAround(*(iHold3ptr+iX))) {
													*(iHold3ptr+iX)=NearVehicle;
													break;
												}
											}
										}
										break;
									case 3: 
										Goto(NearVehicle, "hold4");
										if (!IsType(NearVehicle,"vputurr"))
										{
											for (iX=0; iX<MAX_HOLD_UNITS; ++iX) {
												if (*(iHold4ptr+iX)==NULL || !IsAround(*(iHold4ptr+iX))) {
													*(iHold4ptr+iX)=NearVehicle;
													break;
												}
											}
										}
										break;
									case 4:	//Cerberi attack squads
										if (IsAround(groupETarget)) 
										{
											Attack(NearVehicle, groupETarget);
										}
										else
										{
											Handle hTarget;
											hTarget=GetObjectByTeamSlot(1, (((turn_counter/10)%5)+1));
											if (!IsAround(hTarget)) 
											{
												hTarget = GetObjectByTeamSlot(strat_team,DLL_TEAM_SLOT_RECYCLER);
												if (!IsAround(hTarget)) 
												{
													hTarget = GetObjectByTeamSlot(strat_team,DLL_TEAM_SLOT_FACTORY);
												}
											}
											Attack(NearVehicle, hTarget);
										}
										break;
									case 5:	// Patrol squads
										switch (PortalNumber[j])
										{
										case 0: Patrol(NearVehicle, "portalPatrol0"); break;
										case 1: Patrol(NearVehicle, "portalPatrol1"); break;
										case 2: Patrol(NearVehicle, "portalPatrol2"); break;
										case 3: Patrol(NearVehicle, "portalPatrol3"); break;
										case 4: Patrol(NearVehicle, "portalPatrol4"); break;
										case 5: Patrol(NearVehicle, "portalPatrol5"); break;
										case 6: Patrol(NearVehicle, "portalPatrol6"); break;
										case 7: Patrol(NearVehicle, "portalPatrol7"); break;
										case 8: Patrol(NearVehicle, "portalPatrol8"); break;
										case 9: Patrol(NearVehicle, "portalPatrol9"); break;
										}
										break;
									default:
										switch ((turn_counter/10)%3)
										{
										case 0: Goto(NearVehicle, "hold1"); break;
										case 1: Goto(NearVehicle, "hold2"); break;
										case 2: Goto(NearVehicle, "hold3"); break;
										default: Goto(NearVehicle, "hold4"); break;
										}
									}
								}
							}
							k = PortalCount; // Force this loop to terminate
						}
					}
				}
			}
		}
	}
}


// This function looks for all objects labelled PortalUserA thru PortalUserZ,
// and designates those ODF types to go to the portal nearest that object.
// It then deletes the objects, sice their only purpose was to tell the DLL
// what ODF is associated with what which portal.
// Function by BS-er
// _________________________________________________________________
void instantMission::SetPortalUsers()
{
	char PortalUserLabel[20] = "PortalUserA";

	for (int i=0; i<MaxPortalUserTypes; i++)
	{
		Handle PortalUser = GetHandle(PortalUserLabel);
		if(IsAround(PortalUser))
		{
			char Race = GetRace(PortalUser);

			for (int j=0; j<ODFArraySize; j++)
			{
				if (IsType(PortalUser, ODFType[j]))
				{
					PortalUserTypes[i] = j;
					UsedPortals[i] = GetNearestBuilding(PortalUser);
					
					//@@@NB_FE_MPI02
					for (int n=0; n<MaxPortals; n++)
					{
						if (UsedPortals[i]==Portals[n])
						{
							UsedPortalsGroup[i] = PortalGroup[n];
/*
#ifdef _BZDEBUG
							//PrintConsoleMessage("----------");
							char tmpstr[64];
							sprintf(tmpstr, "SetPortalUser: %s", PortalUserLabel);
							PrintConsoleMessage(tmpstr);
							//sprintf(tmpstr, "PortalUserTypes: %d", PortalUserTypes[i]);
							//PrintConsoleMessage(tmpstr);
							//sprintf(tmpstr, "UsedPortalsGroup Set: %d", UsedPortalsGroup[i]);
							//PrintConsoleMessage(tmpstr);
#endif
*/
							break;
						}
					}
					RemoveObject(PortalUser);
				}
			}
		}
		PortalUserLabel[10]++;
		if (i==26) PortalUserLabel[10]='1';	//@@@NB_FE_MPI02
	}
}


// This function checks to see if the object is supposed to use
// a portal, and if so, returns the portal he is supposed to use.
// Function by BS-er
// _________________________________________________________________
Handle instantMission::GetPortalToUse(Handle PortalUser)
{
	for (int i=0; i<MaxPortalUserTypes; i++)
	{
		int TypeIndex = PortalUserTypes[i];
		if (TypeIndex>=0 && IsType(PortalUser,ODFType[TypeIndex]))
		{
/*
#ifdef _BZDEBUG
			PrintConsoleMessage("--- GetPortalToUse ---");
			char tmpstr[64];
			sprintf(tmpstr, "UsedPortalsGroup: %d", UsedPortalsGroup[i]);
			PrintConsoleMessage(tmpstr);
			sprintf(tmpstr, "PortalUserTypes: %d", PortalUserTypes[i]);
			PrintConsoleMessage(tmpstr);
#endif
*/
			m_PortalGroup = UsedPortalsGroup[i];

			//@@@NB_FE_MPI02
			// Make sure there is a live destination portal in the group:
			for (int j=0; j<PortalCount; j++) {
				if (Portals[j] != UsedPortals[i]) {
					if ((m_PortalGroup == PortalGroup[j]) && IsAround(Portals[j]))
					{
						// Do not allow non-Cerberi to use portal group E:
						if (UsedPortals[i]!=groupEPortal) {
							return UsedPortals[i];
						}
					}
				}
			}
		}
	}

	return 0;
}


// Function by BS-er
// ______________________________________________________________________
char* instantMission::RaceOdf(char Race, char* EndString)
{
	sprintf(TempODFName, "%c%s", Race, EndString);
	return TempODFName;
}


// Function by BS-er
// ______________________________________________________________________
bool instantMission::IsType (Handle h, char* EndString)
{
	return IsOdf(h,RaceOdf(GetRace(h), EndString));
}




//@@@Centerline_FE_MPI - Function added by Centerline
// Sets up extra random scrap pools at pathpoints in the map.
// Looks for mpipathpoints in the form "RandomPool_X_Y_ODF"
// where Y:1..iMaxPoolGroups and X:1..iMaxPoolLocations
// and ODF = the ODF name of the scrap pool object we should build.
// If the ODF name is "NONE" and that path point is the one randomly
// selected to be built for the group -- then no scrap pool will be
// built for that scrap pool group.
// ______________________________________________________________________
void instantMission::SetupRandomScrapPools(void)
{
	enum PoolTags
	{
		MPIPathPoint=0,
		ODF,
		MaxPoolTags,
	};
	
	const int iMaxPoolGroups = 9;		// Maximum number of pools to be placed - don't exceed "MaxValueLen" number of digits
	const int iMaxPoolLocations = 9;	// Maximum random locations for any one pool - don't exceed "MaxValueLen" number of digits
	const int MaxODFLen=32;
	const int MaxValueLen=1;			// Maximum allowed number of digits in pool group and pool locations
										// if you increase this you must modify code.
	const int MaxPathName=64;			// Maximum allowed number of characters in a pathpoint name

	int x,y;
	int Locations;
	int pathCount;

	unsigned long j,k;

	char TempLabel[MaxPathName+1];
	char RandomPools[iMaxPoolGroups+1][iMaxPoolLocations+1][MaxPoolTags+1][MaxPathName+1];

	char **pathNames;

	GetAiPaths(pathCount, pathNames);

	// Pre-fill the RandomPools array with null characters
	for (x = 1; x < iMaxPoolGroups + 1; x++)
	{
		for (y = 1; y < iMaxPoolLocations + 1; y++)
		{
			RandomPools[x][y][MPIPathPoint][0] = '\0';
			RandomPools[x][y][ODF][0] = '\0';
		}
	}

	// Parse out the path points to find valid pool locations
	for (int i = 0; i < pathCount; ++i)
	{
		char *Label = pathNames[i];
		if(strncmp(Label,"RandomPool",10)==0)
		{
			// Starts with "RandomPool" so process it.

			char TempPoolODF[MaxODFLen+1];
			char TempPoolGroup[MaxValueLen];
			char TempPoolLocation[MaxValueLen];

			// Prezap full string contents so we don't have to null-term later
			memset(TempPoolODF,0,sizeof(TempPoolODF));
			memset(TempPoolGroup,0,sizeof(TempPoolGroup));
			memset(TempPoolLocation,0,sizeof(TempPoolLocation));

			j=0;

			// Skip forward until an _
			while((Label[j] != '_') && (Label[j] != '\0'))
			{
				j++;
			}
			if(Label[j]=='\0')
			{
				continue; // Misformat! No _ found! Bail!
			}

			k=0;
			j++; // skip the _. Now, copy out X value
			while((Label[j] != '_') && (Label[j] != '\0'))
			{
				if(k<MaxValueLen)
				{
					TempPoolGroup[k]=Label[j];
					k++;
				}
				j++;
			}

			if(Label[j]=='\0')
			{
				continue; // Misformat! No _ found! Bail!
			}

			k=0;
			j++; // skip the _. Now, copy out Y value
			TempPoolLocation[k]=Label[j]; // Compiler messup test?
			while((Label[j] != '_') && (Label[j] != '\0'))
			{
				if(k<MaxValueLen)
				{
					TempPoolLocation[k]=Label[j];
					k++;
				}
				j++;
			}

			if(Label[j]=='\0')
			{
				continue; // Misformat! No _ found! Bail!
			}

			k=0;
			j++; // skip the _. Now, copy out pool ODF
			TempPoolODF[k]=Label[j]; // Compiler messup test?
			while((Label[j] != '_') && (Label[j] != '\0'))
			{
				if(k<MaxODFLen)
				{
					TempPoolODF[k]=Label[j];
					k++;
				}
				j++;
			}


			// Fill the array with all possible build points
			if ((TempPoolGroup[0] != '\0') && (TempPoolLocation[0] != '\0')
				&& (TempPoolODF[0] != '\0'))

			{
				x = TempPoolGroup[0] - 48;
				y = TempPoolLocation[0] - 48;

				memset(TempLabel,0,sizeof(TempLabel));

				strncpy (TempLabel, Label, MaxPathName);
				strncpy (RandomPools[x][y][MPIPathPoint], TempLabel, MaxPathName+1);
				strncpy (RandomPools[x][y][ODF], TempPoolODF, MaxODFLen+1);

				//
				// ****************************************************************
				// *                                                              *
				// * Debug section to put a nav at every detected pool path point *
				// *                                                              *
				// ****************************************************************
				//
				//Handle Nav = BuildObject("ibnav",1,TempLabel);
				//SetObjectiveName(Nav, TempLabel);
			}
		}
	}


	// Now figure out which pools to build and do it.
	x = 0;
	y = 0;


	for (x = 1; x < iMaxPoolGroups + 1; x++)
	{
		Locations = 0;

		for (y = 1; y < iMaxPoolLocations + 1; y++)
		{
			if (RandomPools[x][y][MPIPathPoint][0] != '\0')
			{
				Locations++;
			}
		}

		if (Locations > 0)
		{
			y = (int)GetRandomFloat(32000);
			y = y%Locations+1;
		
			if (RandomPools[x][y][ODF] != "NONE")
			{
				BuildObject(RandomPools[x][y][ODF], 0, RandomPools[x][y][MPIPathPoint]);
			}
		}
	}
}


//@@@Centerline_FE_MPI - Function added by Centerline
// Checks to see if GroupE has a destination portal. Everything else checks
// to see if PortalE0 exists but not if there is somewhere to go. If the
// human team demolishes the destination portals then GroupE will overbuild
// and lag the game. This check should be used in conjunction with the build
// routine to ensure we don't build any new units after all destination
// portals are demolished.
// ______________________________________________________________________
bool instantMission::DestinationPortal(void)
{
	bool HaveDestinationPortal=false;

	for (int j=0; j<PortalCount; j++)
	{
		if (PortalGroup[j] == 4)
		{
			if (PortalNumber[j] > 0 && IsAround(Portals[j]))
			{
				HaveDestinationPortal=true;
			}
		}
	}

	return HaveDestinationPortal;
}

/*

//@@@Centerline_FE_MPI - Function added by Centerline
// Builds an attack unit when the human team builds the bomber.
// Unit built depends on skill level and scrap boost.
// Path points are Killer1, Killer2 and Killer3.  One of them is
// chosen randomly as the spawn location.  Unit is then ordered
// to attack the bomber bay.
// 
// The ODFs are setup in in the "SETUP" section
//
// ______________________________________________________________________
void instantMission::SpawnKiller(void)
{
	// debug statement
	PrintConsoleMessage("Entering Rampage routine.");

	char tempstr[64];

	Handle hTarget;
	hTarget = GetObjectByTeamSlot(strat_team,DLL_TEAM_SLOT_BOMBERBAY);
	if (IsAround(hTarget)) 
	{
		int Killer = (time_count%3)+1;
		Handle hKiller;
		hKiller = NULL;
		Vector vSpawnPoint;
		Vector vKiller;

		char KillerPathPoint[33];
		memset(KillerPathPoint,0,sizeof(KillerPathPoint));

		// debug statement
		sprintf(KillerPathPoint, "Killer%01d", Killer);
		PrintConsoleMessage(KillerPathPoint);

		hKiller = BuildObject("ibnav", 0, KillerPathPoint);
		vSpawnPoint = GetPosition(hKiller);
		RemoveObject(hKiller);

		
		switch (iDiffLvl)
		{
			case OPTION_NORMAL:
			{
				if (Killer2ODF[0]!= '\0')
				{
					// debug statement
					PrintConsoleMessage("Spawning at Normal Difficutly");

					for (int i=0; i < (iScrapBstLvl+1); i++)
					{
						// debug statement
						sprintf(tempstr, "Spawning Rampage Unit: %01d", i+1);
						PrintConsoleMessage(tempstr);

						vKiller = vSpawnPoint;
						vKiller.x += ((i*10.0f) * portable_cos(float(i)));
						vKiller.z += ((i*10.0f) * portable_sin(float(i)));

						vKiller.y = TerrainFindFloor(vKiller.x,vKiller.z);

						//vKiller.y += (i * 20.0f)

						hKiller = BuildObject(Killer2ODF, comp_team, vKiller);
						SetSkill(hKiller,3);
						SetRandomHeadingAngle(hKiller);
					
						Attack(hKiller,hTarget);

						Handle Nav = BuildObject("ibnav", 0, vKiller);
						sprintf(tempstr, "Rampage Unit: %01d", i+1);
						SetObjectiveName(Nav, tempstr);
					}
				}
				break;
			}

			case OPTION_HIGH:
			{
				if (Killer3ODF[0]!= '\0')
				{
					for (int i=0; i < (iScrapBstLvl*2); i++)
					{
						// debug statement
						sprintf(tempstr, "Spawning Rampage Unit: %01d", i+1);
						PrintConsoleMessage(tempstr);

						vKiller = vSpawnPoint;

						vKiller.x += ((i*10.0f) * portable_cos(float(i)));
						vKiller.z += ((i*10.0f) * portable_sin(float(i)));
						vKiller.y = TerrainFindFloor(vKiller.x,vKiller.z);

						//vKiller.y += (i * 20.0f)

						hKiller = BuildObject(Killer3ODF, comp_team, vKiller);
						SetSkill(hKiller,3);
						SetRandomHeadingAngle(hKiller);
					
						Attack(hKiller,hTarget);

						Handle Nav = BuildObject("ibnav", 0, vKiller);
						sprintf(tempstr, "Rampage Unit: %01d", i+1);
						SetObjectiveName(Nav, tempstr);
					}
				}
				break;
			}

			case OPTION_LOW:
			{
				PrintConsoleMessage("On EASY and you build a bomber bay?!");
				break;
			}
		}
	
	}
	BuiltBomber = false;

	// debug statement
	PrintConsoleMessage("Exiting Rampage routine.");
}		

*/

// ______________________________________________________________________
SubMission * BuildSubMission(void)
{
	return new instantMission();
}
