Untitled diff
835 lignes
/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
// general ai for skirmish game
// general ai for skirmish game
/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
// Warzone2100, Pumpkin Studios,
// Warzone2100, Pumpkin Studios,
// alex lee.98/99.
// alex lee.98/99.
//
//
/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
//Tile in world units
//Tile in world units
#define	TILE					128
#define	TILE					128
#define	NONE					(-1)
#define	NONE					(-1)
// These are final rules of the lexical parser
// These are final rules of the lexical parser
#define	R_REQUEST_HELP			"help me"
#define	R_REQUEST_HELP			"help me"
#define	R_REQUEST_BEACON		"drop a beacon"
#define	R_REQUEST_BEACON		"drop a beacon"
#define	R_REPORT_SAFETY			"i'm ok"
#define	R_REPORT_SAFETY			"i'm ok"
#define R_REQUEST_ALLY			"ally me"
#define R_REQUEST_ALLY			"ally me"
// These are our own messages - lexical parser should be able to handle them
// These are our own messages - lexical parser should be able to handle them
#define M_REQUEST_HELP			"help me!!"
#define M_REQUEST_HELP			"help me!!"
#define M_REQUEST_BEACON		"drop a beacon"
#define M_REQUEST_BEACON		"drop a beacon"
#define M_AFFIRMATIVE_OK		"ok"
#define M_AFFIRMATIVE_OK		"ok"
#define M_AFFIRMATIVE_ROGER		"roger"
#define M_AFFIRMATIVE_ROGER		"roger"
#define M_ANNOYED				"bug off"
#define M_ANNOYED				"bug off"
#define M_HELPERS_KILLED		"that was all I had.."
#define M_HELPERS_KILLED		"that was all I had.."
#define M_HELP_NO_UNITS			"I don't have anything"
#define M_HELP_NO_UNITS			"I don't have anything"
#define	MAX_PROBABILITY			100
#define	MAX_PROBABILITY			100
// Base threat range in world units
// Base threat range in world units
#define	W_BASE_THREAT_RANGE		((17 + (mapWidth + mapHeight) / 2 / 35) * TILE)
#define	W_BASE_THREAT_RANGE		((17 + (mapWidth + mapHeight) / 2 / 35) * TILE)
#define ALL_ALLIES				-1
#define ALL_ALLIES				-1
#define	BASE_DEFEND_DURATION	(3 * 60)
#define	BASE_DEFEND_DURATION	(3 * 60)
// Delay before we repeat our request, in seconds
// Delay before we repeat our request, in seconds
#define HELP_REQUEST_INTERVAL	(3 * 60)
#define HELP_REQUEST_INTERVAL	(3 * 60)
//in secs
//in secs
#define BEACON_TIMEOUT			30
#define BEACON_TIMEOUT			30
#define	MAX_DROIDS				150
#define	MAX_DROIDS				150
//range for trucks to look for more oil
//range for trucks to look for more oil
#define MORE_OIL_RANGE			(10 * TILE)
#define MORE_OIL_RANGE			(10 * TILE)
//don't try to build on oil if there's threat within this range
//don't try to build on oil if there's threat within this range
#define	OIL_THREAT_RANGE		(9 * TILE)
#define	OIL_THREAT_RANGE		(9 * TILE)
#define	MAX_TRUCKS				12
#define	MAX_TRUCKS				15
#define	MIN_TRUCKS				5
#define	MIN_TRUCKS				12
//Enter power saving mode when lower than this
//Enter power saving mode when lower than this
#define	LOW_POWER				250
#define	LOW_POWER				250
//Target type values
//Target type values
#define	NO_TARGET_VALUE			0
#define	NO_TARGET_VALUE			0
#define	DROID_TARGET_VALUE		1
#define	DROID_TARGET_VALUE		1
#define	OTHER_TARGET_VALUE		2
#define	OTHER_TARGET_VALUE		2
#define	DEFENSE_TARGET_VALUE	3
#define	DEFENSE_TARGET_VALUE	3
#define	RESEARCH_TARGET_VALUE	4
#define	RESEARCH_TARGET_VALUE	4
#define	HQ_TARGET_VALUE			5
#define	HQ_TARGET_VALUE			5
#define	OIL_TARGET_VALUE		6
#define	OIL_TARGET_VALUE		6
#define	FACTORY_TARGET_VALUE	7
#define	FACTORY_TARGET_VALUE	7
#define	UNLIMITED 				(-1)
#define	UNLIMITED 				(-1)
#define	AA_THREAT_RANGE			(TILE * 12)
#define	AA_THREAT_RANGE			(TILE * 12)
#define	MAX_DEFENDERS_RADIUS	(TILE * 40)
#define	MAX_DEFENDERS_RADIUS	(TILE * 40)
#define	MAX_VTOL_DEFEND_RADIUS	(TILE * 25)
#define	MAX_VTOL_DEFEND_RADIUS	(TILE * 25)
// AI will remember max this number of structures
// AI will remember max this number of structures
#define	MAX_REBUILD_STRUCT		100
#define	MAX_REBUILD_STRUCT		100
//Total number of technology branches
//Total number of technology branches
#define	TECHS					2
#define	TECHS					2
//How many best templates to choose from when deciding what template to build
//How many best templates to choose from when deciding what template to build
#define	MAX_RANDOM_TEMPLATES	4
#define	MAX_RANDOM_TEMPLATES	6
private	int				me;			// player for this instance.
private	int				me;			// player for this instance.
public	int				tileExpand;			// rate of exploration
public	int				tileExpand;			// rate of exploration
public	int				numScouts[TECHS],maxScouts[TECHS];			// aim for...
public	int				numScouts[TECHS],maxScouts[TECHS];			// aim for...
public	int				numDefenders[TECHS],maxDefenders[TECHS];
public	int				numDefenders[TECHS],maxDefenders[TECHS];
public	int				numAttackers[TECHS],maxAttackers[TECHS];
public	int				numAttackers[TECHS],maxAttackers[TECHS];
public	int				numCyborgs[TECHS],maxCyborgs[TECHS];
public	int				numCyborgs[TECHS],maxCyborgs[TECHS];
public	int				branchDefault,branchVTOL,techCount[TECHS],maxVtolFacs[TECHS],maxIdleRes[TECHS],
public	int				branchDefault,branchVTOL,techCount[TECHS],maxVtolFacs[TECHS],maxIdleRes[TECHS],
						maxVTOLs[TECHS],numVtolTargets,vtolTargetWeight[10],numRebuildStat[TECHS];
						maxVTOLs[TECHS],numVtolTargets,vtolTargetWeight[10],numRebuildStat[TECHS];
public	RESEARCHSTAT	tech[TECHS][30];		//technology for different research branches
public	RESEARCHSTAT	tech[TECHS][30];		//technology for different research branches
public	STRUCTURESTAT	vtolTarget[10],rebuildStat[TECHS][2];
public	STRUCTURESTAT	vtolTarget[10],rebuildStat[TECHS][2];
// structures
// structures
private int				baseX,baseY,minx,miny,maxx,maxy;
private int				baseX,baseY,minx,miny,maxx,maxy;
public	int				numStructs,numIncendrys,numDefStructs,numExtraStructs[TECHS],numWallWeaps,numBaseStruct,numLightCyborgs,numFundamental;
public	int				numStructs,numIncendrys,numDefStructs,numExtraStructs[TECHS],numWallWeaps,numBaseStruct,numLightCyborgs,numFundamental;
private	STRUCTURESTAT	structChoice[5];
private	STRUCTURESTAT	structChoice[5];
public	STRUCTURESTAT	incendrys[8],structs[13],defStructs[26],extraStructs[TECHS][6],wallWeaps[11];
public	STRUCTURESTAT	incendrys[10],structs[13],defStructs[26],extraStructs[TECHS][6],wallWeaps[11];
public	STRUCTURESTAT	sensorTower,wall,cornerWall,resLab,powGen,playerHQ,lassat,factory,derrick,cybFactory,
public	STRUCTURESTAT	sensorTower,wall,cornerWall,resLab,powGen,playerHQ,lassat,factory,derrick,cybFactory,
						vtolDefStruct[5],vtolPad,vtolFactory,uplink,baseStruct[8];
						vtolDefStruct[9],vtolPad,vtolFactory,uplink,baseStruct[8];
public	STRUCTURESTAT	powModule,facModule,resModule,vtolModule;
public	STRUCTURESTAT	powModule,facModule,resModule,vtolModule;
public	int				extraStruct;
public	int				extraStruct;
// unit templates
// unit templates
public	int				numTemplates[TECHS];
public	int				numTemplates[TECHS];
public	TEMPLATE		tmpl[TECHS][70];
public	TEMPLATE		tmpl[TECHS][70];
private	TEMPLATE		tmplChoice[5];
private	TEMPLATE		tmplChoice[67];
public	TEMPLATE		cybTempl[10],superCyb[4],cybMechanic,cybEngineer,hovertruck;
public	TEMPLATE		cybTempl[7],superCyb[21],cybMechanic,cybEngineer,hovertruck;
public	TEMPLATE		vtols[18];
public	TEMPLATE		vtols[20];
public	int				numVtolTemplates;
public	int				numVtolTemplates;
public	TEMPLATE		sense[11];
public	TEMPLATE		sense[8];
public	int				numSenseTemplates;
public	int				numSenseTemplates;
public	TEMPLATE		constructor,repair;
public	TEMPLATE		constructor,repair[7];
public	int				numRepairUnits;
public	int				numRepairUnits;
public	int				numSensorUnits;
public	int				numRepairTemplates;
//defend
//defend
private GROUP			defendGroup;
private GROUP			defendGroup;
private bool			defendbusy;
private bool			defendbusy;
private BASEOBJ			defendObj;
private BASEOBJ			defendObj;
public  RESEARCHSTAT		nexusDefence;
public  RESEARCHSTAT		nexusDefence;
private  RESEARCHSTAT		research;
private  RESEARCHSTAT		research;
//build
//build
private GROUP			buildGroup;
private GROUP			buildGroup;
private int				buildX,buildY,buildX2,buildY2;
private int				buildX,buildY,buildX2,buildY2;
public	FEATURESTAT		oilRes;
public	FEATURESTAT		oilRes;
// scout
// scout
private GROUP			scoutGroup;
private GROUP			scoutGroup;
private int				scoutX,scoutY;
private int				scoutX,scoutY;
private int				scoutTLX,scoutTLY,scoutW,scoutH;
private int				scoutTLX,scoutTLY,scoutW,scoutH;
// attack
// attack
private GROUP			attackGroup;
private GROUP			attackGroup;
private BASEOBJ			attackObj,allOutAttack,vtolGrAttackObj[10];
private BASEOBJ			attackObj,allOutAttack,vtolGrAttackObj[39];
// vtols
// vtols
private GROUP			vtolDefendGr,vtolAttackGr[10];
private GROUP			vtolDefendGr,vtolAttackGr[10];
// generic
// generic
private STRUCTURE		structure,structure2,rebuildObj[100];
private STRUCTURE		structure,structure2,rebuildObj[100];
private DROID			droid;
private DROID			droid;
private FEATURE			feature;
private FEATURE			feature;
private BASEOBJ			baseobj,baseobj2;
private BASEOBJ			baseobj,baseobj2;
private int				count,count2,result,result2,tempx,tempy;
private int				count,count2,result,result2,tempx,tempy;
private bool			boolResult,boolResult2;
private bool			boolResult,boolResult2;
private bool			powerSave,_DEBUG,bRunning;
private bool			powerSave,_DEBUG,bRunning;
// Hopefully this will be at least as large as MAX_PLAYERS... Why can't I just use MAX_PLAYERS as the array size?!
// Hopefully this will be at least as large as MAX_PLAYERS... Why can't I just use MAX_PLAYERS as the array size?!
// P.S. And why can't I put a comment on the same line as a #define??!! Gah, who cares if the lua2 branch works, lets switch to it, anyway.
// P.S. And why can't I put a comment on the same line as a #define??!! Gah, who cares if the lua2 branch works, lets switch to it, anyway.
#define MAX_PLAYERS_HACK 17
#define MAX_PLAYERS_HACK 17
private	int				allianceTime[MAX_PLAYERS_HACK];
private	int				allianceTime[MAX_PLAYERS_HACK];
private int				sender,x,y,beaconX[8],beaconY[8],tBeacon[8],
private int				sender,x,y,beaconX[8],beaconY[8],tBeacon[8],
						tLastHelpRequest,lastHelpPlayer,tHelp,tHelpTimeout,helpX,helpY;
						tLastHelpRequest,lastHelpPlayer,tHelp,tHelpTimeout,helpX,helpY;
private string			message;
private string			message;
private	int				defendX,defendY,__defendRadiusUnused,tDefendStart,tDefendTimeout,
private	int				defendX,defendY,__defendRadiusUnused,tDefendStart,tDefendTimeout,
						defendMoveType,baseRange,curTech,numVtolAttackGroups,numAttackVtols,
						defendMoveType,baseRange,curTech,numVtolAttackGroups,numAttackVtols,
						numDefendVtols,rebuildStructX[MAX_REBUILD_STRUCT],rebuildStructY[MAX_REBUILD_STRUCT],countRebuildStruct;
						numDefendVtols,rebuildStructX[MAX_REBUILD_STRUCT],rebuildStructY[MAX_REBUILD_STRUCT],countRebuildStruct;
private	STRUCTURESTAT	rebuildStructStat[MAX_REBUILD_STRUCT];
private	STRUCTURESTAT	rebuildStructStat[MAX_REBUILD_STRUCT];
private STRUCTURESTAT		fundamentalBeingBuilt;
private STRUCTURESTAT		fundamentalBeingBuilt;
private int			order;	// callback global
private int			order;	// callback global
/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
// triggers.
// triggers.
#region triggers
#region triggers
trigger reachedTr				(CALL_DROID_REACH_LOCATION, me, ref droid, ref order);
trigger reachedTr				(CALL_DROID_REACH_LOCATION, me, ref droid, ref order);
trigger buildExpandTr				(every, 600);
trigger buildExpandTr				(every, 300);
trigger fortifyTr					(every,	1000);
trigger fortifyTr					(every,	400);
trigger upgradeStructuresTr			(every, 360);
trigger upgradeStructuresTr			(every, 50);
trigger conDroidsTr					(every, 900);	// was 1400
trigger conDroidsTr					(every, 200);	// was 1400
trigger repairDroidsTr				(every, 2600);
trigger repairDroidsTr				(every, 400);
trigger sensorDroidsTr				(every, 400);
trigger basedetailsTr				(every, 600	);
trigger basedetailsTr				(every, 600	);
trigger buildDerrickTr				(every, 80	);
trigger buildDerrickTr				(every, 80	);
trigger buildOilDefenseOrRetreatTr	(every, 120	);
trigger buildOilDefenseOrRetreatTr	(every, 200	);
trigger incendryTr					(every, 250 );
trigger incendryTr					(every, 120 );
trigger buildPowerGeneratorsTr		(every, 80	);
trigger buildPowerGeneratorsTr		(every, 80	);
trigger buildBaseTr					(every, 150	);
trigger buildBaseTr					(every, 150	);
trigger finishStructsTr				(every, 210);
trigger finishStructsTr				(every, 210);
trigger droidBuiltTr				(CALL_NEWDROID,me, ref droid,ref structure);
trigger droidBuiltTr				(CALL_NEWDROID,me, ref droid,ref structure);
trigger	structBuiltTr				(CALL_STRUCTBUILT, me, ref droid, ref structure);
trigger	structBuiltTr				(CALL_STRUCTBUILT, me, ref droid, ref structure);
trigger droidDestroyedTr			(CALL_DROID_DESTROYED,  me, ref droid);
trigger droidDestroyedTr			(CALL_DROID_DESTROYED,  me, ref droid);
trigger	structureDestroyedTr		(CALL_STRUCT_DESTROYED, me, ref structure);
trigger	structureDestroyedTr		(CALL_STRUCT_DESTROYED, me, ref structure);
trigger	rebuildStructureTr			(every, 50);
trigger	rebuildStructureTr			(every, 50);
trigger consolidateEventTr			(every,	3100);
trigger consolidateEventTr			(every,	3100);
trigger factoryEventTr				(every, 170	);
trigger factoryEventTr				(every, 90	);
trigger cyborgFactoryEventTr		(every, 170	);
trigger cyborgFactoryEventTr		(every, 90	);
trigger chooseScoutAreaTr			(every,	200	);
trigger chooseScoutAreaTr			(every,	200	);
trigger expandScoutAreaTr			(every,	600	);
trigger expandScoutAreaTr			(every,	600	);
trigger scoutMainTr					(every,	150	);
trigger scoutMainTr					(every,	150	);
trigger newObjectReportTr			(CALL_OBJ_SEEN, me, ref baseobj, ref baseobj2);
trigger newObjectReportTr			(CALL_OBJ_SEEN, me, ref baseobj, ref baseobj2);
trigger attackStuffTr				(every, 300	);
trigger attackStuffTr				(every, 200	);
trigger allOutAttackTr				(every, 4000);
trigger allOutAttackTr				(every, 2000);
trigger defendWatchTr				(CALL_STRUCT_ATTACKED, me, ref structure, ref baseobj);
trigger defendWatchTr				(CALL_STRUCT_ATTACKED, me, ref structure, ref baseobj);
trigger defendReturnTr				(every,	500	);
trigger defendReturnTr				(every,	100000 );
trigger doResearchTr				(CALL_RESEARCHCOMPLETED, ref research, ref structure, me);
trigger doResearchTr				(CALL_RESEARCHCOMPLETED, ref research, ref structure, me);
trigger vtolDefendTr				(CALL_STRUCT_ATTACKED, me, ref structure, ref baseobj);
trigger vtolDefendTr				(CALL_STRUCT_ATTACKED, me, ref structure, ref baseobj);
trigger vtolStructsTr				(every, 290);
trigger vtolStructsTr				(every, 600);
trigger buildVtolsTr				(every, 360);
trigger buildVtolsTr				(every, 180);
trigger vtolAttackTr				(every, 150);
trigger vtolAttackTr				(every, 10);
trigger vtolEnablerTr				(every, 700);
trigger vtolEnablerTr				(every, 700);
trigger takeoverTr					(CALL_UNITTAKEOVER, ref droid);
trigger takeoverTr					(CALL_UNITTAKEOVER, ref droid);
trigger useLassatTr					(every, 3000);
trigger useLassatTr					(every, 3000);
trigger reassignTr					(CALL_PLAYERLEFT,ref count);
trigger reassignTr					(CALL_PLAYERLEFT,ref count);
trigger formAllianceEventTr			(every,170);
trigger formAllianceEventTr			(every,170);
trigger breakAllianceEventTr		(every,3000);
trigger breakAllianceEventTr		(every,3000);
trigger difficultyModifierTr		(every,600);
trigger difficultyModifierTr		(every,600);
trigger humanAllianceTr				(CALL_ALLIANCEOFFER,ref count, ref count2);
trigger humanAllianceTr				(CALL_ALLIANCEOFFER,ref count, ref count2);
trigger multiMsgTr					(CALL_AI_MSG, me, ref sender, ref message);
trigger multiMsgTr					(CALL_AI_MSG, me, ref sender, ref message);
trigger	beaconTr					(CALL_BEACON, me, ref sender, ref x, ref y, ref message);
trigger	beaconTr					(CALL_BEACON, me, ref sender, ref x, ref y, ref message);
trigger consoleTr					(CALL_CONSOLE, ref sender, ref message);
trigger consoleTr					(CALL_CONSOLE, ref sender, ref message);
trigger watchBaseThreatTr			(every, 120);
trigger watchBaseThreatTr			(every, 120);
trigger manageAllyHelpTr			(every, 80);
trigger manageAllyHelpTr			(every, 80);
trigger everySec					(every, 10);
trigger everySec					(every, 10);
trigger manageDefendLocationTr		(every, 70);
trigger manageDefendLocationTr		(every, 70);
trigger startLevelTr				(CALL_START_NEXT_LEVEL);
trigger startLevelTr				(CALL_START_NEXT_LEVEL);
trigger chainloadTr				(wait, 1);
trigger chainloadTr				(wait, 1);
trigger slowloadTr				(wait, 13);
trigger slowloadTr				(wait, 13);
trigger checkResearchTr				(every, 400);
trigger checkResearchTr				(every, 50);
/* Events */
/* Events */
event	conDroids;
event	conDroids;
event	multiMsgEv;
event	multiMsgEv;
event	beaconEv;
event	beaconEv;
event	watchBaseThreat;
event	watchBaseThreat;
event	manageAllyHelp;
event	manageAllyHelp;
event	everySecEv;
event	everySecEv;
event	manageDefendLocationEv;
event	manageDefendLocationEv;
event	structureDestroyed;
event	structureDestroyed;
event	rebuildStructureEv;
event	rebuildStructureEv;
event	doResearch;
event	doResearch;
event	buildDerrick;
event	buildDerrick;
/* Function prototypes */
/* Function prototypes */
function bool haveBeacon(int _player);
function bool haveBeacon(int _player);
function bool beaconTimeout(int _player);
function bool beaconTimeout(int _player);
function void processCommand(string _message, int _sender, bool _bBlipMessage);
function void processCommand(string _message, int _sender, bool _bBlipMessage);
function bool haveHelpers();
function bool haveHelpers();
function bool attemptToHelp(int _playerToHelp, int _x, int _y);
function bool attemptToHelp(int _playerToHelp, int _x, int _y);
function void helpPlayer(int _playerToHelp, int _helpX, int _helpY);
function void helpPlayer(int _playerToHelp, int _helpX, int _helpY);
function bool canStopHelpingAlly();
function bool canStopHelpingAlly();
function void stopHelpingAlly();
function void stopHelpingAlly();
function bool helpingAlly();
function bool helpingAlly();
function bool helpAllyTimeout();
function bool helpAllyTimeout();
function void requestHelp(int _helpX, int _helpY);
function void requestHelp(int _helpX, int _helpY);
function void doRequestHelp(int _helpX, int _helpY);
function void doRequestHelp(int _helpX, int _helpY);
function bool allyBaseAtLoc(int _ally, int _x, int _y);
function bool allyBaseAtLoc(int _ally, int _x, int _y);
function void messagePlayer(int _playerToMessage, string _message, int _probability);
function void messagePlayer(int _playerToMessage, string _message, int _probability);
function void messagePlayerAddressed(int _playerToMessage, int _playersToAddress, string _message);
function void messagePlayerAddressed(int _playerToMessage, int _playersToAddress, string _message);
function bool canSeeAllies();
function bool canSeeAllies();
function bool baseInTrouble();
function bool baseInTrouble();
function string m_affirmative();
function string m_affirmative();
function void defendLocation(int _defendX, int _defendY, int _tDefendTimeout, bool _bMove);
function void defendLocation(int _defendX, int _defendY, int _tDefendTimeout, bool _bMove);
function void stopDefendingLocation();
function void stopDefendingLocation();
function bool defendingLocation();
function bool defendingLocation();
function bool defendLocationTimeout();
function bool defendLocationTimeout();
function bool friendlyPlayer(int _playerToCheck);
function bool friendlyPlayer(int _playerToCheck);
function void factoryBuildDroid(STRUCTURE _factory);
function void factoryBuildDroid(STRUCTURE _factory);
function void cybFactorBuildCyborg(STRUCTURE _factory);
function void cybFactorBuildCyborg(STRUCTURE _factory);
function void vtolFactoryBuildVtol(STRUCTURE _factory);
function void vtolFactoryBuildVtol(STRUCTURE _factory);
function bool insideBase(int _x, int _y);
function bool insideBase(int _x, int _y);
function int numAlliesInBase(bool _bVtols);
function int numAlliesInBase(bool _bVtols);
function int numEnemiesInBase(bool _bVtols);
function int numEnemiesInBase(bool _bVtols);
function bool defendingOwnBase();
function bool defendingOwnBase();
function int targetTypeValue(BASEOBJ _target);
function int targetTypeValue(BASEOBJ _target);
function int numBitsSet(int _integer);
function int numBitsSet(int _integer);
function int findResearch(int _searchStart, int _techTree);
function int findResearch(int _searchStart, int _techTree);
function bool upgradeFactory(DROID _truck, int _maxBuilders);
function bool upgradeFactory(DROID _truck, int _maxBuilders);
function bool upgradeVtolFactory(DROID _truck, int _maxBuilders);
function bool upgradeVtolFactory(DROID _truck, int _maxBuilders);
function bool upgradeResearch(DROID _truck, int _maxBuilders);
function bool upgradeResearch(DROID _truck, int _maxBuilders);
function bool upgradePowGen(DROID _truck, int _maxBuilders);
function bool upgradePowGen(DROID _truck, int _maxBuilders);
function void buildRearmPads();
function void buildRearmPads();
function int numEnemyAAInRange(int _x, int _y, int _range);
function int numEnemyAAInRange(int _x, int _y, int _range);
function BASEOBJ chooseVtolTarget(bool bExclusiveTarget);
function BASEOBJ chooseVtolTarget(bool bExclusiveTarget);
function int getVtolTargetWeight(BASEOBJ _target);
function int getVtolTargetWeight(BASEOBJ _target);
function bool vtolTargetAssigned(BASEOBJ _target);
function bool vtolTargetAssigned(BASEOBJ _target);
function int numBuildSameBuilding(STRUCTURESTAT _checkStat, int _x, int _y);
function int numBuildSameBuilding(STRUCTURESTAT _checkStat, int _x, int _y);
function int totalVtols();
function int totalVtols();
function bool needTank();
function bool needTank();
function void setTechBranch(int _tech);
function void setTechBranch(int _tech);
function DROID closestIdleTruck(int _x, int _y);
function DROID closestIdleTruck(int _x, int _y);
function void buildOnExactLocation(DROID _truck, int _x, int _y, STRUCTURESTAT _stat);
function void buildOnExactLocation(DROID _truck, int _x, int _y, STRUCTURESTAT _stat);
function void rebuildStructures();
function void rebuildStructures();
function BASEOBJ chooseVtolDefenceTarget(int _x, int _y, int _range, bool bExclusiveTarget);
function BASEOBJ chooseVtolDefenceTarget(int _x, int _y, int _range, bool bExclusiveTarget);
function int numGroupSameOrder(GROUP _group, int _orderIndex);
function int numGroupSameOrder(GROUP _group, int _orderIndex);
function void rearrangeAttackVtols();
function void rearrangeAttackVtols();
function int numStructBusyByType(STRUCTURESTAT _busyStructType);
function int numStructBusyByType(STRUCTURESTAT _busyStructType);
function bool aiResponsibleForPlayer(int _player);
function bool aiResponsibleForPlayer(int _player);
function void reassignAI();
function void reassignAI();
function void shutDownAI();
function void shutDownAI();
function bool buildUnit(TEMPLATE _tankTemplate, STRUCTURE _factory, STRUCTURESTAT _factoryType, bool _bIdleOnly);
function bool buildUnit(TEMPLATE _tankTemplate, STRUCTURE _factory, STRUCTURESTAT _factoryType, bool _bIdleOnly);
function STRUCTURE findIdleStructure(STRUCTURESTAT _structType, bool _bIdleOnly);
function STRUCTURE findIdleStructure(STRUCTURESTAT _structType, bool _bIdleOnly);
#endregion triggers
#endregion triggers
/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
// HouseKeeping
// HouseKeeping
event initialisedEvent(CALL_GAMEINIT)
event initialisedEvent(CALL_GAMEINIT)
{
{
	local int player;
	local int player;
	// initialise
	// initialise
	me = getPlayer("Nexus");
	me = getPlayer("Nexus");
	_DEBUG = FALSE;
	_DEBUG = FALSE;
	dbgMsgOn(me, _DEBUG);
	dbgMsgOn(me, _DEBUG);
	extraStruct = 0;
	extraStruct = 0;
	numRepairUnits = 0;
	numRepairUnits = 0;
	numSensorUnits = 0;
	allOutAttack = NULLOBJECT;
	allOutAttack = NULLOBJECT;
	tLastHelpRequest = -1;	//when we requested help for the last time
	tLastHelpRequest = -1;	//when we requested help for the last time
	lastHelpPlayer = -1;		//we are not currently helping anyone
	lastHelpPlayer = -1;		//we are not currently helping anyone
	tHelp = -1;					//when we started helping last time
	tHelp = -1;					//when we started helping last time
	tHelpTimeout = -1;			//time when help times out
	tHelpTimeout = -1;			//time when help times out
	helpX = -1;
	helpX = -1;
	helpY = -1;
	helpY = -1;
	defendX = -1;
	defendX = -1;
	defendY = -1;
	defendY = -1;
	tDefendStart = -1;
	tDefendStart = -1;
	tDefendTimeout = -1;
	tDefendTimeout = -1;
	defendMoveType = -1;		//move or scout
	defendMoveType = -1;		//move or scout
	baseRange = 4 * TILE;
	baseRange = 4 * TILE;
	// set current research branch
	// set current research branch
	setTechBranch(-1);
	setTechBranch(-1);
	numVtolAttackGroups = 10;
	numVtolAttackGroups = 10;
	numAttackVtols = 10;	//num vtols in an attack group
	numAttackVtols = 10;	//num vtols in an attack group
	numDefendVtols = 5;	//num vtols in an attack group
	numDefendVtols = 5;	//num vtols in an attack group
	// setup build group - all initial droids are in buildgroup!
	// setup build group - all initial droids are in buildgroup!
	groupAddArea(buildGroup, me, 0, 0, (mapWidth*128), (mapHeight*128));
	groupAddArea(buildGroup, me, 0, 0, (mapWidth*128), (mapHeight*128));
	// note where our base is.
	// note where our base is.
	getPlayerStartPosition(me, ref baseX, ref baseY);
	getPlayerStartPosition(me, ref baseX, ref baseY);
	// defence.
	// defence.
	defendbusy = FALSE;
	defendbusy = FALSE;
	// setup scouts
	// setup scouts
	structure = getStructure(factory, me);
	structure = getStructure(factory, me);
	if(structure != NULLOBJECT)
	if(structure != NULLOBJECT)
	{
	{
		scoutTLX		= structure.x;
		scoutTLX		= structure.x;
		scoutTLY		= structure.y;
		scoutTLY		= structure.y;
	}
	}
	else
	else
	{
	{
		scoutTLX		= baseX;
		scoutTLX		= baseX;
		scoutTLY		= baseY;
		scoutTLY		= baseY;
	}
	}
	scoutW			= 256;
	scoutW			= 256;
	scoutH			= 256;
	scoutH			= 256;
	scoutX			= scoutTLX;
	scoutX			= scoutTLX;
	scoutY			= scoutTLY;
	scoutY			= scoutTLY;
	// clear the alliance array...
	// clear the alliance array...
	player = 0;
	player = 0;
	while (player != MAX_PLAYERS)
	while (player != MAX_PLAYERS)
	{
	{
		allianceTime[player] = 0;
		allianceTime[player] = 0;
		player = player + 1;
		player = player + 1;
	}
	}
	fundamentalBeingBuilt = derrick;	// to avoid ever being null
	fundamentalBeingBuilt = derrick;	// to avoid ever being null
	if(aiResponsibleForPlayer(me))
	if(aiResponsibleForPlayer(me))
	{
	{
		bRunning = true;
		bRunning = true;
	}
	}
	else
	else
	{
	{
		bRunning = false;
		bRunning = false;
		shutDownAI();
		shutDownAI();
	}
	}
}
}
// check whether we have at least one structure of that type
// check whether we have at least one structure of that type
function bool haveStructure(STRUCTURESTAT type) 
function bool haveStructure(STRUCTURESTAT type) 
{
{
	return getStructure(type, me) != NULLOBJECT;
	return getStructure(type, me) != NULLOBJECT;
}
}
// check if we are getting any income
// check if we are getting any income
function bool havePowerSource()
function bool havePowerSource()
{
{
	// we don't check buildings being finished here
	// we don't check buildings being finished here
	return haveStructure(powGen) and haveStructure(derrick);
	return haveStructure(powGen) and haveStructure(derrick);
}
}
// I am not sure why we need this hack, but the AI can still end up not researching anything at times
// I am not sure why we need this hack, but the AI can still end up not researching anything at times
event checkResearch(checkResearchTr)
event checkResearch(checkResearchTr)
{
{
	setEventTrigger(doResearch, chainloadTr);
	setEventTrigger(doResearch, chainloadTr);
}
}
function void dbgPlr(string message)
function void dbgPlr(string message)
{
{
	setEventTrigger(doResearch, chainloadTr);
	setEventTrigger(doResearch, chainloadTr);
	if (me == selectedPlayer)
	if (me == selectedPlayer)
	{
	{
		console(message);
		console(message);
	}
	}
}
}
function void dbgObj(DROID obj, string message)
function void dbgObj(DROID obj, string message)
{
{
	if (obj.selected)
	if (obj.selected)
	{
	{
		console(message);
		console(message);
	}
	}
}
}
function bool conCanHelp(DROID mydroid, int bx, int by)
function bool conCanHelp(DROID mydroid, int bx, int by)
{
{
	return (mydroid.order != DORDER_HELPBUILD and mydroid.order != DORDER_BUILD and mydroid.order != DORDER_LINEBUILD and droidCanReach(mydroid, bx, by));
	return (mydroid.order != DORDER_HELPBUILD and mydroid.order != DORDER_BUILD and mydroid.order != DORDER_LINEBUILD and droidCanReach(mydroid, bx, by));
}
}
// Build something in main base, grab trucks to do it within tiles range
// Build something in main base, grab trucks to do it within tiles range
function bool grabTrucksAndBuild(int range, STRUCTURESTAT bstats, int maxBlockingTiles)
function bool grabTrucksAndBuild(int range, STRUCTURESTAT bstats, int maxBlockingTiles)
{
{
	local DROID	mydroid, closestDroid;
	local DROID	mydroid, closestDroid;
	local int	closestDist, currDist, numHelpDroids, tilerange, bx, by;
	local int	closestDist, currDist, numHelpDroids, tilerange, bx, by;
	initIterateGroup(buildGroup);				// find idle droids in build group.
	initIterateGroup(buildGroup);				// find idle droids in build group.
	mydroid = iterateGroup(buildGroup);
	mydroid = iterateGroup(buildGroup);
	closestDist = 99999;
	closestDist = 99999;
	closestDroid = NULLOBJECT;
	closestDroid = NULLOBJECT;
	numHelpDroids = 0;
	numHelpDroids = 0;
	tilerange = range * TILE;
	tilerange = range * TILE;
	while (mydroid != NULLOBJECT)
	while (mydroid != NULLOBJECT)
	{
	{
		if (conCanHelp(mydroid, baseX, baseY))
		if (conCanHelp(mydroid, baseX, baseY))
		{
		{
			bx = baseX;
			bx = baseX;
			by = baseY;
			by = baseY;
			if (pickDroidStructLocation(mydroid, bstats, ref bx, ref by, me, maxBlockingTiles))
			if (pickDroidStructLocation(mydroid, bstats, ref bx, ref by, me, maxBlockingTiles))
			{
			{
				currDist = distBetweenTwoPoints(bx, by, mydroid.x, mydroid.y);
				currDist = distBetweenTwoPoints(bx, by, mydroid.x, mydroid.y);
				if (currDist < tilerange)
				if (currDist < tilerange)
				{
				{
					orderDroidStatsLoc(mydroid, DORDER_BUILD, bstats, bx, by);	// close, so help build it
					orderDroidStatsLoc(mydroid, DORDER_BUILD, bstats, bx, by);	// close, so help build it
					numHelpDroids = numHelpDroids + 1;
					numHelpDroids = numHelpDroids + 1;
				}
				}
				else if (currDist < closestDist)
				else if (currDist < closestDist)
				{
				{
					closestDroid = mydroid;	// record this droid as being closest so far
					closestDroid = mydroid;	// record this droid as being closest so far
					closestDist = currDist;
					closestDist = currDist;
				}
				}
			}
			}
		}
		}
		mydroid = iterateGroup(buildGroup);
		mydroid = iterateGroup(buildGroup);
	}
	}
	if (numHelpDroids == 0 and closestDroid != NULLOBJECT)	// found none within help radius, so force someone to go long distance traveling
	if (numHelpDroids == 0 and closestDroid != NULLOBJECT)	// found none within help radius, so force someone to go long distance traveling
	{
	{
		orderDroidStatsLoc(closestDroid, DORDER_BUILD, bstats, bx, by);	// you, book a plane ticket and go!
		orderDroidStatsLoc(closestDroid, DORDER_BUILD, bstats, bx, by);	// you, book a plane ticket and go!
		return true;
		return true;
	}
	}
	return (numHelpDroids > 0);
	return (numHelpDroids > 0);
}
}
event arrived(reachedTr)
event arrived(reachedTr)
{
{
	local bool found;
	local bool found;
	local STRUCTURESTAT myChoice;
	local STRUCTURESTAT myChoice;
	if (droid.droidType == DROID_CONSTRUCT or droid.droidType == DROID_CYBORG_CONSTRUCT)
	if (droid.droidType == DROID_CONSTRUCT or droid.droidType == DROID_CYBORG_CONSTRUCT)
	{
	{
		dbgObj(droid, "Failed to build where we should - attempt to screw up enemy oil derrick");
		dbgObj(droid, "Failed to build where we should - attempt to screw up enemy oil derrick");
		// Check if at oil well, and it was taken by enemy
		// Check if at oil well, and it was taken by enemy
		structure = structureBuiltInRange(derrick, droid.x, droid.y, (5 * 128), -1);
		structure = structureBuiltInRange(derrick, droid.x, droid.y, (5 * 128), -1);
		if (structure != NULLOBJECT)
		if (structure != NULLOBJECT)
		{
		{
			if (not friendlyPlayer(structure.player) and droid.health == 100)
			if (not friendlyPlayer(structure.player) and droid.health == 100)
			{
			{
				// Ok, at enemy derrick, and nobody has hurt us yet. Start being nasty.
				// Ok, at enemy derrick, and nobody has hurt us yet. Start being nasty.
				count = 0;
				count = 0;
				found = false;
				found = false;
				// find simplest/cheapest one available to build
				// find simplest/cheapest one available to build
				while (count < numDefStructs and not found)
				while (count < numDefStructs and not found)
				{
				{
					if (isStructureAvailable(defStructs[count], me))
					if (isStructureAvailable(defStructs[count], me))
					{
					{
						found = true;
						found = true;
					}
					}
					else
					else
					{
					{
						count++;
						count++;
					}
					}
				}
				}
				if (found)
				if (found)
				{
				{
					buildX = droid.x;
					buildX = droid.x;
					buildY = droid.y;
					buildY = droid.y;
					if (pickDroidStructLocation(droid, defStructs[count], ref buildX, ref buildY, me, -1))
					if (pickDroidStructLocation(droid, defStructs[count], ref buildX, ref buildY, me, -1))
					{
					{
						orderDroidStatsLoc(droid, DORDER_BUILD, defStructs[count], buildX, buildY);
						orderDroidStatsLoc(droid, DORDER_BUILD, defStructs[count], buildX, buildY);
					}
					}
					else
					else
					{
					{
						dbgObj(droid, "Wanted to be nasty, but found nowhere to build defense");
						dbgObj(droid, "Wanted to be nasty, but found nowhere to build defense");
						orderDroid(droid, DORDER_RTB);		// nothing more to do here.
						orderDroid(droid, DORDER_RTB);		// nothing more to do here.
					}
					}
				}
				}
				else
				else
				{
				{
					dbgObj(droid, "Wanted to be nasty, but had nothing nasty to build - returning to base");
					dbgObj(droid, "Wanted to be nasty, but had nothing nasty to build - returning to base");
					orderDroid(droid, DORDER_RTB);		// oh, well. nothing more to do here.
					orderDroid(droid, DORDER_RTB);		// oh, well. nothing more to do here.
				}
				}
				exit;
				exit;
			}
			}
			else if (droid.health < 100 and !insideBase(droid.x, droid.y))
			else if (droid.health < 100 and !insideBase(droid.x, droid.y))
			{
			{
				orderDroid(droid, DORDER_RTR);		// bolt back to base now!
				orderDroid(droid, DORDER_RTR);		// bolt back to base now!
				exit;
				exit;
			}
			}
		}
		}
	}
	}
}
}
event buildFundamentals(inactive)
event buildFundamentals(inactive)
{
{
	count = 0;
	count = 0;
	while (count < numFundamental)
	while (count < numFundamental)
	{
	{
		// check that struct.
		// check that struct.
		structure = getStructure(structs[count], me);
		structure = getStructure(structs[count], me);
		if (structure == NULLOBJECT)				// if missing build it.
		if (structure == NULLOBJECT)				// if missing build it.
		{
		{
			if (isStructureAvailable(structs[count], me))
			if (isStructureAvailable(structs[count], me))
			{
			{
				if (grabTrucksAndBuild(12, structs[count], 0))
				if (grabTrucksAndBuild(12, structs[count], 0))
				{
				{
					exit;	// no need to check more
					exit;	// no need to check more
				}
				}
			}
			}
		}
		}
		count = count + 1;
		count = count + 1;
	}
	}
	fundamentalBeingBuilt = derrick;
	fundamentalBeingBuilt = derrick;
	setEventTrigger(buildFundamentals, inactive);
	setEventTrigger(buildFundamentals, inactive);
}
}
event startLevel(startLevelTr)
event startLevel(startLevelTr)
{
{
	setEventTrigger(buildFundamentals, slowloadTr);
	setEventTrigger(buildFundamentals, slowloadTr);
	setEventTrigger(conDroids, chainloadTr);
	setEventTrigger(conDroids, chainloadTr);
	setEventTrigger(doResearch, chainloadTr);
	setEventTrigger(doResearch, chainloadTr);
	setEventTrigger(buildDerrick, slowloadTr);
	setEventTrigger(buildDerrick, slowloadTr);
	setEventTrigger(startLevel, inactive);
	setEventTrigger(startLevel, inactive);
}
}
// decide what technology branch we will use
// decide what technology branch we will use
function void setTechBranch(int _tech)
function void setTechBranch(int _tech)
{
{
	local float		_y2,_y1,_x2,_x1,_a,_y,_m,_rnd,_mapSize;
	local float		_y2,_y1,_x2,_x1,_a,_y,_m,_rnd,_mapSize;
	_mapSize = (float)((mapWidth + mapHeight) / 2);
	_mapSize = (float)((mapWidth + mapHeight) / 2);
	if(_tech != -1)
	if(_tech != -1)
	{
	{
		curTech = _tech;
		curTech = _tech;
	}
	}
	else
	else
	{
	{
		//probability to choose vtol branch for map size 90 = 0; probability for map size 200 = 45
		//probability to choose vtol branch for map size 90 = 0; probability for map size 200 = 45
		//build a linear function: y = ((y2 - y1) / (x2 - x1)) * x + a depending on two values given (short: y = mx+a)
		//build a linear function: y = ((y2 - y1) / (x2 - x1)) * x + a depending on two values given (short: y = mx+a)
		_x1 = 90.0; _y1 = 0.0;
		_x1 = 90.0; _y1 = 0.0;
		_x2 = 200.0; _y2 = 45.0;
		_x2 = 200.0; _y2 = 45.0;
		_m = ((_y2 - _y1) / (_x2 - _x1));
		_m = ((_y2 - _y1) / (_x2 - _x1));
		_a = -(_m * _x1);
		_a = -(_m * _x1);
		//calculate probability for the current map
		//calculate probability for the current map
		_y = _m * _mapSize + _a;
		_y = _m * _mapSize + _a;
		dbg("_m = " & _m & ", a = " & _a, me);
		dbg("_m = " & _m & ", a = " & _a, me);
		_rnd = (float)random(100);
		_rnd = (float)random(100);
		if(_rnd  < _y)
		if(_rnd  < _y)
		{
		{
			curTech = branchVTOL;
			curTech = branchVTOL;
			dbg("going air (" & _y & "/" & _rnd & ")", me);
			dbg("going air (" & _y & "/" & _rnd & ")", me);
		}
		}
		else
		else
		{
		{
			curTech = branchDefault;
			curTech = branchDefault;
			dbg("going land (" & _y & "/" & _rnd & ")", me);
			dbg("going land (" & _y & "/" & _rnd & ")", me);
		}
		}
	}
	}
}
}
/* returns TRUE if AI is responsible for the _player */
/* returns TRUE if AI is responsible for the _player */
function bool aiResponsibleForPlayer(int _player)
function bool aiResponsibleForPlayer(int _player)
{
{
	if(not _DEBUG and ((_player == selectedPlayer) or not myResponsibility(_player)))
	if(not _DEBUG and ((_player == selectedPlayer) or not myResponsibility(_player)))
	{
	{
		return FALSE;
		return FALSE;
	}
	}
	return TRUE;
	return TRUE;
}
}
/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
// keep details about the size and postion of the ai players base
// keep details about the size and postion of the ai players base
event basedetails(basedetailsTr)
event basedetails(basedetailsTr)
{
{
	// clear old extremities.
	// clear old extremities.
	maxy = 0;
	maxy = 0;
	maxx = 0;
	maxx = 0;
	miny = (mapHeight*128);
	miny = (mapHeight*128);
	minx = (mapWidth*128);
	minx = (mapWidth*128);
	baseRange = 4 * TILE;
	baseRange = 4 * TILE;
	// now find the extremities of our vital structures.
	// now find the extremities of our vital structures.
	count = 0;
	count = 0;
	while(count < numBaseStruct)
	while(count < numBaseStruct)
	{
	{
		initEnumStruct(FALSE,baseStruct[count],me,me);
		initEnumStruct(FALSE,baseStruct[count],me,me);
		structure= enumStruct();
		structure= enumStruct();
		while(structure != NULLOBJECT)
		while(structure != NULLOBJECT)
		{
		{
			if(structure.x < minx)
			if(structure.x < minx)
			{
			{
				minx = structure.x;
				minx = structure.x;
			}
			}
			if(structure.x > maxx)
			if(structure.x > maxx)
			{
			{
				maxx = structure.x;
				maxx = structure.x;
			}
			}
			if(structure.y < miny)
			if(structure.y < miny)
			{
			{
				miny = structure.y;
				miny = structure.y;
			}
			}
			if(structure.y > maxy)
			if(structure.y > maxy)
			{
			{
				maxy = structure.y;
				maxy = structure.y;
			}
			}
			result = distBetweenTwoPoints(baseX, baseY, structure.x, structure.y);
			result = distBetweenTwoPoints(baseX, baseY, structure.x, structure.y);
			if(result > baseRange){
			if(result > baseRange){
				baseRange = result;
				baseRange = result;
			}
			}
			structure= enumStruct();
			structure= enumStruct();
		}
		}
		count = count + 1;
		count = count + 1;
	}
	}
	result = 3 * 128;
	result = 3 * 128;
	minx = minx - result;
	minx = minx - result;
	maxx = maxx + result;
	maxx = maxx + result;
	miny = miny - result;
	miny = miny - result;
	maxy = maxy + result;
	maxy = maxy + result;
	baseRange = baseRange + (4 * 128);
	baseRange = baseRange + (4 * 128);
}
}
/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
// structure building rules
// structure building rules
// build derricks on oil.
// build derricks on oil.
event buildDerrick(buildDerrickTr)
event buildDerrick(buildDerrickTr)
{
{
	local bool	foundOne, _same;
	local bool	foundOne, _same;
	local FEATURE	_oil, _closestOil;
	local FEATURE	_oil, _closestOil;
	local int	_bestDist, _newDist;
	local int	_bestDist, _newDist;
	local DROID	_search;
	local DROID	_search;
	// what if we can't waste power on building derricks because we don't have a gen yet?
	// what if we can't waste power on building derricks because we don't have a gen yet?
	if (playerPower(me) < 300 and haveStructure(derrick) and not haveStructure(powGen))
	if (playerPower(me) < 300 and haveStructure(derrick) and not haveStructure(powGen))
	{
	{
		setEventTrigger(buildDerrick, slowloadTr);
		setEventTrigger(buildDerrick, slowloadTr);
		exit;
		exit;
	}
	}
	_bestDist = 99999;
	_bestDist = 99999;
	_closestOil = NULLOBJECT;
	_closestOil = NULLOBJECT;
	foundOne = false;
	foundOne = false;
	initIterateGroup(buildGroup);				// find all units in build group
	initIterateGroup(buildGroup);				// find all units in build group
	droid = iterateGroup(buildGroup);
	droid = iterateGroup(buildGroup);
	while (droid != NULLOBJECT && !foundOne)
	while (droid != NULLOBJECT && !foundOne)
	{
	{
		if (droid.order != DORDER_BUILD and droid.order != DORDER_LINEBUILD and droid.order != DORDER_HELPBUILD)
		if (droid.order != DORDER_BUILD and droid.order != DORDER_LINEBUILD and droid.order != DORDER_HELPBUILD)
		{
		{
			foundOne = true;
			foundOne = true;
		}
		}
		else
		else
		{
		{
			droid = iterateGroup(buildGroup);
			droid = iterateGroup(buildGroup);
		}
		}
	}
	}
	if (droid != NULLOBJECT)
	if (droid != NULLOBJECT)
	{
	{
		initGetFeature(oilRes, -1, me);
		initGetFeature(oilRes, -1, me);
		_oil = getFeatureB(me);
		_oil = getFeatureB(me);
		while (_oil != NULLOBJECT)
		while (_oil != NULLOBJECT)
		{
		{
			_newDist = distBetweenTwoPoints(droid.x, droid.y, _oil.x, _oil.y);
			_newDist = distBetweenTwoPoints(droid.x, droid.y, _oil.x, _oil.y);
			_same = false;
			_same = false;
			if (_newDist < _bestDist and droidCanReach(droid, _oil.x, _oil.y))	// this one is closer
			if (_newDist < _bestDist and droidCanReach(droid, _oil.x, _oil.y))	// this one is closer
			{
			{
				if (!threatInRange(me, _oil.x, _oil.y, OIL_THREAT_RANGE, FALSE))
				if (!threatInRange(me, _oil.x, _oil.y, OIL_THREAT_RANGE, FALSE))
				{
				{
					initIterateGroup(buildGroup);				// find all units in build group.
					initIterateGroup(buildGroup);				// find all units in build group.
					_search = iterateGroup(buildGroup);
					_search = iterateGroup(buildGroup);
					foundOne = false;
					foundOne = false;
					while (_search != NULLOBJECT && !foundOne)
					while (_search != NULLOBJECT && !foundOne)
					{
					{
						if (_search.orderx == _oil.x and _search.ordery == _oil.y and _search != droid)
						if (_search.orderx == _oil.x and _search.ordery == _oil.y and _search != droid)
						{
						{
							_same = true;
							_same = true;
							foundOne = true;
							foundOne = true;
						}
						}
						_search = iterateGroup(buildGroup);
						_search = iterateGroup(buildGroup);
					}
					}
					if (!_same)	// do not go to same spot as another droid
					if (!_same)	// do not go to same spot as another droid
					{
					{
						_bestDist = _newDist;
						_bestDist = _newDist;
						_closestOil = _oil;
						_closestOil = _oil;
					}
					}
				}
				}
			}
			}
			_oil = getFeatureB(me);
			_oil = getFeatureB(me);
		}
		}
		if (_closestOil != NULLOBJECT)
		if (_closestOil != NULLOBJECT)
		{
		{
			orderDroidStatsLoc(droid, DORDER_BUILD, derrick, _closestOil.x, _closestOil.y); // build a derick
			orderDroidStatsLoc(droid, DORDER_BUILD, derrick, _closestOil.x, _closestOil.y); // build a derick
			if (idleGroup(buildGroup) > 0)
			if (idleGroup(buildGroup) > 0)
			{
			{
				setEventTrigger(buildDerrick, slowloadTr);	// do it again for next droid
				setEventTrigger(buildDerrick, slowloadTr);	// do it again for next droid
				exit;
				exit;
			}
			}
		}
		}
	}
	}
	setEventTrigger(buildDerrick, buildDerrickTr);
	setEventTrigger(buildDerrick, buildDerrickTr);
}
}
/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
// if idle and derrick in range and no defense then build defense, else ret to base .
// if idle and derrick in range and no defense then build defense, else ret to base .
event buildOilDefenseOrRetreat(buildOilDefenseOrRetreatTr)
event buildOilDefenseOrRetreat(buildOilDefenseOrRetreatTr)
{
{
	local	int		_numBuilders,_maxBuilders;
	local	int		_numBuilders,_maxBuilders;
	_maxBuilders = 1;
	_maxBuilders = 1;
	// check idle.
	// check idle.
	initIterateGroup(buildGroup);					// find idle droids in build group.
	initIterateGroup(buildGroup);					// find idle droids in build group.
	droid = iterateGroup(buildGroup);
	droid = iterateGroup(buildGroup);
	while(droid != NULLOBJECT)
	while(droid != NULLOBJECT)
	{
	{
		if (droid.order != DORDER_BUILD and droid.order != DORDER_LINEBUILD and droid.order != DORDER_HELPBUILD)
		if (droid.order != DORDER_BUILD and droid.order != DORDER_LINEBUILD and droid.order != DORDER_HELPBUILD)
		{
		{
			// if in range of a derrick
			// if in range of a derrick
			structure = structureBuiltInRange(derrick, droid.x, droid.y, (5*128), me);
			structure = structureBuiltInRange(derrick, droid.x, droid.y, (5*128), me);
			// if inside base limits then presume ok..
			// if inside base limits then presume ok..
			if( structure != NULLOBJECT)
			if( structure != NULLOBJECT)
			{
			{
				if((structure.x > minx) and (structure.y > miny) and (structure.x < maxx) and (structure.y <maxy))
				if((structure.x > minx) and (structure.y > miny) and (structure.x < maxx) and (structure.y <maxy))
				{
				{
					structure = NULLOBJECT;
					structure = NULLOBJECT;
				}
				}
			}
			}
			if(structure != NULLOBJECT)
			if(structure != NULLOBJECT)
			{
			{
				buildX = structure.x;
				buildX = structure.x;
				buildY = structure.y;
				buildY = structure.y;
				// not many defenses nearby
				// not many defenses nearby
				if(numFriendlyWeapStructsInRange(me, buildX, buildY, (3*128), FALSE) < 2)
				if(numFriendlyWeapStructsInRange(me, buildX, buildY, (3*128), FALSE) < 2)
				{
				{
					count = numDefStructs - 1;							//pick a struct to build..
					count = numDefStructs - 1;							//pick a struct to build..
					count2 = 0;
					count2 = 0;
					while( (count2 < 5) and (count >= 0) )
					while( (count2 < 5) and (count >= 0) )
					{
					{
						if( isStructureAvailable(defStructs[count],me))
						if( isStructureAvailable(defStructs[count],me))
						{
						{
							structChoice[count2] = defStructs[count];
							structChoice[count2] = defStructs[count];
							count2 = count2 + 1;
							count2 = count2 + 1;
						}
						}
						count = count - 1;
						count = count - 1;
					}
					}
					count =0;
					count =0;
					if(count2 > 0)
					if(count2 > 0)
					{
					{
						count = random(count2);						 //count = choice!
						count = random(count2);						 //count = choice!
						// pick a location
						// pick a location
						boolResult = pickDroidStructLocation(droid, structChoice[count], ref buildX, ref buildY, me, -1);
						boolResult = pickDroidStructLocation(droid, structChoice[count], ref buildX, ref buildY, me, -1);
						_numBuilders = numBuildSameBuilding(NULLSTRUCTURESTAT, buildX, buildY);
						_numBuilders = numBuildSameBuilding(NULLSTRUCTURESTAT, buildX, buildY);
						if((boolResult == TRUE) and (_numBuilders < _maxBuilders) and droidCanReach(droid, buildX, buildY))
						if((boolResult == TRUE) and (_numBuilders < _maxBuilders) and droidCanReach(droid, buildX, buildY))
						{
						{
							// build it.
							// build it.
							orderDroidStatsLoc(droid, DORDER_BUILD,structChoice[count], buildX,buildY);
							orderDroidStatsLoc(droid, DORDER_BUILD,structChoice[count], buildX,buildY);
							_numBuilders++;
							_numBuilders++;
						}
						}
					}
					}
				}
				}
				else
				else
				{
				{
					structure = structureBuiltInRange(playerHQ, droid.x, droid.y, (5*128), me);
					structure = structureBuiltInRange(playerHQ, droid.x, droid.y, (5*128), me);
					if(structure == NULLOBJECT)
					if(structure == NULLOBJECT)
					{
					{
						if(!insideBase(droid.x, droid.y))
						if(!insideBase(droid.x, droid.y))
						{
						{
							orderDroid(droid,DORDER_RTB);				// return to base;
							orderDroid(droid,DORDER_RTB);				// return to base;
						}
						}
					}
					}
				}
				}
			}
			}
			else
			else
			{
			{
				structure = structureBuiltInRange(playerHQ, droid.x, droid.y, (5*128), me);
				structure = structureBuiltInRange(playerHQ, dr
				if(structure == NULLOBJECT)
				{
					if(!insideBase(droid.x, droid.y))
					{
						orderD