6
/* Should be used with GAME_TIME_IN_SECS, not with gameTime */
8
#define MINUTE (SECOND * 60)
10
/* How many seconds it takes to cross a tile */
11
#define TILE_TRAVEL_TIME 1
13
/* Defines for debug watch window */
14
#define WATCH_DEBUG_REINF 0
15
#define WATCH_DEBUG_RESEARCH 1
16
#define WATCH_DEBUG_CMDS 2
18
/* 10 secs are equivalent to 1 droid */
19
#define SECONDS_PER_DROID 10
21
/* Max AA defenses to build on base perimeter, when enemy base location is known */
22
#define MAX_BASE_PERIM_AA_DEF 7
23
#define MAX_BASE_PERIM_RANGE (TILE * 6)
25
/* Max AA defenses to build near loc attacked by enemy vtols, when enemy base location is unknown */
26
#define MAX_INBASE_AA_DEF 6
27
#define INBASE_AA_DEF_MAX_RANGE (TILE * 4)
29
/* Max game time when we build scouts, stop afterwards */
30
#define SCOUT_BUILD_TIME (MINUTE * 8)
32
/* How much time to wait until we start building tanks */
33
#define MIN_DELAY_INITIAL_TANKS (MINUTE * 2)
34
#define MAX_DELAY_INITIAL_TANKS (MINUTE * 8)
36
/* How fast a single unit costing 215 power kills another single unit with the same cost - 1 per minute - rough approxomation */
37
#define DEFAULT_KILLER_COST 215
38
#define UNIT_KILL_RATE (1 / MINUTE)
39
#define DEFAULT_UNITS_PTS 130
41
/* min number of reinforcements to use when helping ally */
42
#define MIN_HELPING_ALLY_REINF 5
44
#define MIN_COUNTERATTACKERS 6
45
#define MIN_OIL_DEFENDERS 8
47
/* Commanders stuff */
48
#define MAX_COMMANDERS 10
49
#define CMD_INIT_CAPACITY 6
50
#define MAX_CMD_ASSIGN_DIST (TILE * 25)
52
/* How many repairs to build for repairing attack units */
53
#define NUM_REPAIRS_FOR_CMD 5
54
#define MAX_CMD_REPAIRERS (MAX_COMMANDERS * NUM_REPAIRS_FOR_CMD)
56
#define MAX_DEFEND_REPAIRERS 7
58
/* Max distance a repair unit can stay away from the commander it is assigned to */
59
#define MAX_REP_DIST_FROM_CMD (TILE * 4)
61
/* Max distance a repair unit can stay away from the commander while it is repairing some droid */
62
#define MAX_REP_DIST_FROM_CMD_WHILE_REP (TILE * 12)
64
/* How many defenders are rapired by a single repair unit */
65
#define NUM_DEFENDERS_PER_REPAIRER 4
67
/* Choose randomly from this number of available templates */
68
#define MAX_CHOICE_DROIDS 3
69
#define MAX_CHOICE_LIGHT_CYB 2
71
/* All objects inside this base range are treated as if they were belonging to the base */
72
#define COUNT_BASE_OBJECTS_RANGE max((35 * TILE), (baseRange + defendCorridor))
74
/* How useless a base defense is compared to a normal unit */
75
#define STR_UNIT_DEFENSE_FACTOR 4
77
/* Whether to leave additional base defenders when attacking */
78
#define NO_BASE_DEFENDERS false
79
#define PROGRESSIVE_DEFENDERS (!NO_BASE_DEFENDERS)
80
#define MIN_DEFENDERS 3
82
/* For minDefenders calculation: how many seconds a defender single unit can hold on, before main force comes back to the base to help defending it */
83
#define UNIT_HOLD_SECS 8
85
/* Max number of group iteration thet can take place at the same time */
86
#define MAX_GROUP_ITERATE_BUCKET 5
88
/* How many trucks to use when upgrading certain structures */
89
#define MAX_POWGEN_UPGRADE_TRUCKS 2
90
#define MAX_FACTORY_UPGRADE_TRUCKS 3
94
/* Min research facilities to use when researching */
95
#define F_MIN_ACTIVE_RES_FAC (2.5)
97
#define GAME_TIME_IN_SECS (gameTime / 10)
100
#define LEGO_PHASE_LEN (MINUTE * 5)
101
#define STARTUP_PHASE_LEN (SECOND * 4)
103
#define MIN_DEF_OIL_TIME (MINUTE * 4)
106
#define MAX_BUILDERS 15
108
#define CHECK_OIL_THREAT_RANGE (TILE * 12)
110
// time to wait until derrick is recognized being under siege
111
#define MIN_TIME_OIL_ATTACKED_DELAY (SECOND * 8)
112
#define MAX_TIME_OIL_NOT_ATTACKED (MIN_TIME_OIL_ATTACKED_DELAY + (SECOND * 15))
114
#define THROW_DICE random(100)
116
/* Reinforcements: What range to use when counting enemies for threat assessing */
117
#define REINF_ENEMY_COUNT_RANGE (TILE * 12)
121
// max range to look for further oil when finished building an oil derrick
122
#define NEXT_OIL_RANGE (TILE * 11)
126
/* Chance to start attacking enemy oil after finished defending own oil derrick */
127
#define CHANCE_COUNTER_OIL 40
128
#define MAX_COUNTER_OIL_DISTANCE (TILE * 12)
130
/* How many remembered oil defense location to use for a single oil derrick */
131
#define MAX_OIL_DEFENSES_SIDES 3
132
#define MIN_OIL_RECALL_PRIORITY 3
133
#define DEFENSE_DIST_FROM_OIL (TILE * 3)
135
/* Max/min number of oil defenses for a single stored defense location */
136
#define MAX_OIL_DEFENSES_PER_LOC 8
137
#define MIN_OIL_DEFENSES_PER_LOC 5
139
// range of oil defenses for a single stored oil defense location
140
#define OIL_DEFENSES_RANGE (TILE * 5)
142
// try to cover all oil defenses with this range
143
#define RANGE_ALL_OIL_DEFENSES (OIL_DEFENSES_RANGE + DEFENSE_DIST_FROM_OIL)
145
//max number of trucks that can build defenses for a single oi lderrick
146
#define MAX_TRUCKS_PER_OIL_DEFENSE 1
148
// Whether to build defenses for derricks located in the base
149
#define DEFEND_BASE_DERRICKS false
153
// range of base defenses
154
#define BASE_DEFENSES_RANGE (TILE * 5)
156
//max number of recalled base defend locations to build defenses at
157
#define MAX_BASE_DEFENSE_LOCATIONS 5
159
#define MIN_BASE_RECALL_PRIORITY 1
161
#define MAX_BASE_DEFEND_LOCS 7
163
#define MAX_BASE_DEFENSES_PER_LOC 7
164
#define MIN_BASE_DEFENSES_PER_LOC 5
166
#define NUM_BASE_DEF_LOC_TRUCKS 1
168
// trucks to use for the same location when base is in danger
169
#define MAX_BASE_DEF_LOC_TRUCKS 3
172
#define REACHED_DEST_RANGE (TILE * 17)
173
#define REACHED_DEF_OIL_RANGE (TILE * 10)
175
/* Weights for choose an enemy */
176
#define W_LOST_UNITS 0.6
178
#define W_BASE_DISTANCE 0.4
179
#define AVERAGE_UNIT_COST 250
181
//2 units for 50 tiles
182
#define TILE_TRAVEL_COST 10.0
185
/* (inverted) Add every nth tank to a scout group, lowest priority when a lot of map is revealed already */
186
#define MIN_SCOUTS_PRIORITY 7
187
#define MAX_SCOUTS_PRIORITY 1
189
/* Number of oil scouts */
190
#define MIN_OIL_SCOUTS 0
191
#define MAX_OIL_SCOUTS 5
193
/* Use MAX_SCOUTS_PRIORITY when SCOUT_MIN_OIL_RES are visible and
194
* MIN_SCOUTS_PRIORITY when SCOUT_MAX_OIL_RES are visible, interpolate between
196
#define MAP_REVEAL_FAC_LBOUND 0.0
197
#define MAP_REVEAL_FAC_UBOUND 1.0
198
#define MAP_REVEAL_MIN_OIL_RES 0.0
199
#define MAP_REVEAL_MAX_OIL_RES 16.0
201
#define TAUNT_SUCCESS 0
202
#define TAUNT_FAILURE 1
203
#define TAUNT_POSSESSION_LOSS 2
204
#define TAUNT_GAME_LOSS 3
205
#define TAUNT_BASE_DEFENSE 4
206
#define TAUNT_BASE_OK 5
207
#define TAUNT_REDISCOVERED_BASE 6
208
#define TAUNT_LOST_BASE 7
214
// reason why we attacked someone
215
#define ATTACK_BASE 1
216
#define ATTACK_COUNTER_ARTY 2
220
public int player,numLego,numTemplates[2],numBaseStructs,numDef,numRes[2],
221
numGatewayDef,numAA,numRepairTmpl,maxDamageLevels,damageLevel[4],
222
numBranches,techTanks,techAir,numVtolTemplates,numVitalStructs,
223
numMinimalStruct[10],maxVitalBuilders[10],numCmdTmpl,numTruckTmpl,
224
numBBTempl,numLightCyborgs,numTankATWeapons,numTankPropulsions,
226
public WEAPON tankATWeapon[20];
227
public PROPULSION tankPropulsion[5];
228
public BODY tankBody[15];
229
public TEMPLATE truck[3],tmpl[2][50],tmplOK[8],tmplBB[3],tmplRep[5],
230
vtoltmpl[2][5],tmplCmd[4],cybEngineer,cybMechanic,cybTempl[6];
231
public STRUCTURESTAT fac,derrick,powGen,vtolfac,resFac,powMod,facMod,resMod,cmdCenter,
232
baseStructs[10],def[10],gatewayDef[6],wall,AA[5],HQ,uplink,lasSat,
233
minimalStruct[10],cybfac;
234
public STRUCTURESTAT ArgStrStat0; //is private
235
public FEATURESTAT oilRes,ArgFeatStat0;
237
public RESEARCHSTAT research[3][60],resBB,resCmd;
238
public BODY viperBody;
239
public WEAPON weaponBB;
240
public BRAIN cmdTurret;
242
//-----------------------
244
private TEMPLATE tempTmpl;
245
private int count,count2,count3,count4,result,result2,result3,result4,ArgInt0,ArgInt1,ArgInt2,
246
ArgInt3,retInt,retInt2,_retInt,scoutX,scoutY,range,x,y;
247
private int temp,temp2,temp3,temp4,temp5,temp6,enemyScoutStep,enemyScoutX,enemyScoutY,
248
enemyScoutRange,maxEnemyScouts,minEnemyScouts,numOilDef,minOilDef,
249
tempX,tempY,numEnemyScouts,intOK[10],best,maxBaseDef,minBaseDef,
250
numBaseDef,reinfTime,maxReinfTime,sendForceX,sendForceY,helpTime,
251
maxHelpTime,state,stNone,stAttacking,stDefendingBase,stHelpingAlly,stJoiningForces,
252
stTakingOil,stDefendingOil,tState,timeGuardPos,maxTimeGuardPos,numOilAttackers,
253
collectX,collectY,minOilAttackers,
254
collectTime,maxCollectTime,stCollecting,numTakeOil,maxTakeOil,countTakeOil,
255
lastState,lastEnemy,lastStateTemp,lastEnemyTemp,maxBaseEnemies,defendX,defendY,timeSaveExperience,
256
maxTimeSaveExperience,tempResult,tempResult2,dist,dist2,dist3,defWeight,
257
weightDistFactor,_dist,_dist2,tLastBaseDefense,maxInitialBaseDef,curInitialBaseDef,maxInitialDefSites,
258
vstate,lastvState,counterEnemy,maxStateTime,maxBaseDefendDefLocTrucks,
259
realEnemyScoutX,realEnemyScoutY;
260
private bool bResult,bResult2,bResult3,bTempResult,alert,bigMap,ally[8],
261
bTemp,bTemp2,bEnemyScoutHor,bEnemyScoutToRight,
262
bEnemyScoutToBottom,seeBase[8],noBaseTargets,haveBB,haveCommandTech,bCanUseCommanders,
263
bLearn,knowBase[8],lowMilitary,DEBUG_ALL,DEBUG_MSG,DEBUG_OBSERVE,modifierOn,bNotifiedReadyAttack,
264
ArgBool0,ArgBool1,hasVTOLs[8],_bResult,_bResult2,
265
DEBUG_POWER,DEBUG_COMMANDS,dead[8],killedBase[8],bDummy,initialDefensesFinished,
266
bFirstTimeDefenders,ghostDead[120],debugMenuUp,bRunning,bIterateNonCommanders[MAX_GROUP_ITERATE_BUCKET],
267
bIterateCommanders[MAX_GROUP_ITERATE_BUCKET],bIterateCmdAssignedDroids[MAX_GROUP_ITERATE_BUCKET],
270
private int me,baseX,baseY,maxTrucks,minTrucks,buildX,buildY,maxBuildOilTrucks,
271
unitLimit,maxResearch,noPower,lowPower,minFacs,minResFacs,
272
minx,miny,maxx,maxy,baseSq,scoutRange,scoutStep,maxOilScouts,
273
maxOilDef,base[8][2],enemy,numAttackers,maxAttackers,minAttackers,
274
numDefenders,threatRange,minReinforcements,curBase[8][2],numOilScouts,maxBB,
275
numBB,minBB,addScout,addScoutInterval,baseRange,highPower,muchoPower,requestHelpTime,maxRequestHelpTime,
276
notifyReadyAttackTime,maxNotifyReadyAttackTime,oilDefensesRange,
277
minOilRecallPrior,defendCorridor,allyOfferTime[8],maxAllyOfferTime,
278
aaRange,maxOilDefenseTrucks,timeNotifyEnemyInBase,maxTimeNotifyEnemyInBase,
279
attackedCount,allyState[8],allyPhase[8],allyEnemy[8],minAllyHelpers,
280
minDefenders,maxBaseDefenseLoc,maxBaseDefenseTrucks,
281
lasSatState[8],lasSatEnemy,tLasSat,tLasSatReady,tLasSatCountdown,
282
tLasSatReplyMax,tLasSatWaitAlliesMax,lsNone,lsRecharging,
283
lsReady,lsRequesterWaitingRecharging,lsWaitingReply,
284
lsDelayedFiring,lsWaitingForRequester,lsWaiting,lsFiring;
286
private int phase,phNone,phMoveToLoc,phAttackingLoc,phSearchingForBase,phCollecting,
287
phGuardingPos,phLostBase,phRTB,storeOilDefTime[8],storeBaseDefTime[8],
288
storeTime,none,off,allyInThreat,msgPlayer,msgPlayer2,offeredEnemy,
289
phGettingTech,phGettingUnits,phWaitAllies,phLoadingTransport,
290
phSendDrop,phTransportDone,tWaitAlliesDrop,tMaxWaitAlliesDrop,tWaitLoadDrop,
291
tMaxWaitLoadDrop,numDroppers,numTransporters,stDrop,maxTransporters,
292
transportX,transportY,savedState,savedPhase,savedEnemy,stTransporting,
293
reinfCount[8],tRequestStatus[8],tMaxRequestStatus,tWaitPlayerReply[8],tMaxWaitPlayerReply,
294
maxDroppers,medDroppers,minDroppers,tSyncDrop,tMaxSyncDrop,dropStartTime,phSync,maxAllyDroppers,
295
attacked[8],minReinfCount,maxReinfCount,tempReinfCount[8],
296
maxDefendRepairers,_x,_y,_result,_result2,tTakeOil,tMaxTakeOil,tech,tLastResearch,
297
tMaxResearchIdle,numCriticalResearch,sendHelpRange,groupIterateBucket,
298
numPlayerAttackers[MAX_PLAYERS],attackersIncrease;
299
private int tOilAttackBegin,tLastOilAttack,lastOilAttackedX,lastOilAttackedY,watchWindowDebug;
300
private int _temp,_temp2,_temp3,_temp4,_range,lostDroids[MAX_PLAYERS],lostStructs[MAX_PLAYERS];
301
private int beaconX[8],beaconY[8],tBeacon[8],curHelpX[8],curHelpY[8],tBeaconTimeout,maxGhosts,
302
ghostx[120],ghosty[120],tResUrgencyTrackInterval,
303
structNoLiveHealth,iterateCommanderIndex[MAX_GROUP_ITERATE_BUCKET],
304
iterateStage[MAX_GROUP_ITERATE_BUCKET],dice;
305
private float fCurResUrgency,fMaxResUrgency,fMinResUrgency,fNumDefaultResearch,
306
fMinResearch,fMaxResHold,fMapRevealFactor;
309
private DROID droid,droid2,droid3,tempDroid,tempDroid2,ArgDroid0,retDroid,transporter[10],
310
_droid,_droid2,initialDefensesTruck,commander,cmds[MAX_COMMANDERS],
311
iterateGroupDroid[MAX_GROUP_ITERATE_BUCKET];
312
private STRUCTURE structure,structure2,tempStruct,ArgStruct0,retStruct,_structure,_structure2,
314
private GROUP buildGr,defendGr,vtolGr,sendAttackGr,attackGr,scoutGr,enemyScoutGr,
315
tempGr,ArgGr,ArgGr2,transportGr,defendRepairGr,cmdGr[MAX_COMMANDERS],cmdRepGr[MAX_COMMANDERS],
316
groupToIterate[MAX_GROUP_ITERATE_BUCKET],iterateCmdGroup[MAX_GROUP_ITERATE_BUCKET];
317
private FEATURE feature,feature2,retFeature,tempFeature;
318
private BASEOBJ obj,obj2,tempObj,retObj,baseDefendObj;
319
private string cstr,sVer,myName;
320
private RESEARCHSTAT newResearch;
322
private int maxAttackCyborgs,attackReason;
323
private bool bBuildCyborgs;
325
private bool bCheckBaseDebug;
327
private STRUCTURESTAT ghostStat[120];
329
trigger economySelftestTr (every, 80);
330
trigger militarySelftestTr (every, 83);
331
trigger doScoutTr (every, 43);
332
trigger droidBuiltTr (CALL_NEWDROID,me, ref droid,ref structure);
333
trigger structBuiltTr (CALL_STRUCTBUILT, me, ref droid, ref structure);
334
trigger structureAttackedTr (CALL_STRUCT_ATTACKED, me, ref structure, ref obj);
335
trigger droidAttackedTr (CALL_DROID_ATTACKED, me, ref droid, ref obj);
336
trigger objectAttackedTr (CALL_ATTACKED, me, ref obj, ref obj2);
337
trigger consoleTr (CALL_CONSOLE, ref msgPlayer2, ref cstr);
338
trigger multiMsgTr (CALL_AI_MSG, me, ref msgPlayer, ref cstr);
339
trigger transLandedTr (CALL_TRANSPORTER_LANDED_B, tempGr, me, ref droid);
340
trigger beaconTr (CALL_BEACON, me, ref msgPlayer, ref x, ref y, ref cstr);
341
trigger droidTakeOverTr (CALL_UNITTAKEOVER, ref droid);
342
trigger defendBaseTr (every, 42);
343
trigger doResearchTr (every, 52);
344
trigger defendOilTr (every, 63);
345
trigger buildNormalOilDefensesTr (every, 80);
346
trigger scoutForEnemyTr (every, 56);
347
trigger everySecTr (every, 10);
348
trigger halfSecTr (every, 5);
349
trigger coordinatePhasesTr (every, 56);
350
trigger repairDefendDroidsTr (every, 54);
351
trigger manageCMDRepairsTr (every, 45);
352
trigger diffModTr (every,600);
353
trigger allianceOfferedTr (CALL_ALLIANCEOFFER,ref temp, ref temp2);
354
trigger droidSeenTr (CALL_DROID_SEEN, me, ref droid, ref obj);
355
trigger objectSeenTr (CALL_OBJ_SEEN, me, ref obj, ref obj2);
356
trigger checkLostTr (every, 70);
357
trigger structDestroyedTr (CALL_STRUCT_DESTROYED, me, ref structure);
358
trigger droidDestroyedTr (CALL_DROID_DESTROYED, me, ref droid);
359
trigger buildStructureModelTr (wait, 10);
360
trigger researchCompleteTr (CALL_RESEARCHCOMPLETED, ref newResearch, ref structure, me);
361
trigger startAllResearchTr (wait, 11);
362
trigger updateMapRevealFactorTr (every, 100);
363
//=====================================================================
364
// event declarations
365
//=====================================================================
366
event mainEconomySelftest;
367
event mainMilitarySelftest;
371
event structDestroyed;
372
event structureAttacked;
374
event objectAttacked;
379
event droidTakeOverEv;
384
event buildNormalOilDefenses;
386
event coordinatePhases;
387
event manageCMDRepairsEv;
388
event repairDefendDroids;
390
event allianceOffered;
394
event buildStructureModel;
395
event startNewResearch;
396
event startAllResearch;
397
event evUpdateMapRevealFactor;
398
event delayedMainInitialize;
400
//=====================================================================
401
// function declarations
402
//=====================================================================
403
function void reInitialize();
404
function void showVersion();
405
function void mainInitialize();
406
function void storeBase();
407
function void unassignedDroids(GROUP defendersGr, GROUP buildersGr);
408
function void fixGroups();
411
function void doEconomy();
412
function void doEconomyMisc();
413
function void doMilitary();
414
function void doMilitaryMisc();
415
function void updateMaxTrucks();
416
function void updateLasSat();
417
function void resetLasSat();
418
function bool allyLasSatReady();
419
function STRUCTURE findLasSatTarget(int _prefferedEnemy);
420
function STRUCTURE mostDamagedBaseStructure(int _targetPlayer);
421
function void notifyLassat(STRUCTURE _targetStructure);
422
//function void fireLasSat(STRUCTURE _targetStructure);
423
function bool pendingLasSatStrike();
424
function void economySelftest();
425
function void baseDetails();
426
function void militarySelftest();
427
function bool needTrucks();
428
function int numNeedRepairers();
429
function void buildTrucks();
430
function void buildBaseStructs();
432
function void checkPowerGen();
433
function void buildOil(bool _bInBaseOnly);
434
function bool buildNextOil(DROID _truck, int _maxRange, bool _bClosestOil);
435
function void buildMoreOil();
436
function bool manageOilSite(DROID _truck, STRUCTURE _derrick);
437
function bool repairDamagedDefenses(int _repairx, int _repairy, DROID _truck, int _minDamage, int _maxRange);
438
function bool finishDefenses(DROID _truck, int _repairx, int _repairy, int _maxRange);
439
function void initializeStartDefeindingOil(int _oilx, int _oily);
440
function bool checkOilThreat(int _oilx, int _oily);
441
function void dealWithOilAttacked(int _oilx, int _oily);
442
function void upgradeFac();
443
function void upgradePow();
444
function void upgradeVtolFac();
445
function void upgradeResFac();
446
function void finishStructures();
447
function void repairStructures();
448
function void groupRepairGroup(GROUP _damagedGr, GROUP _repairerGr);
449
function int totalRepairersInProduction();
450
function int numCybRepairsInProd();
451
function int numNonCybRepairsInProd();
453
function void startEnemyScout();
454
function void getNextScoutCoord(int _lastX, int _lastY);
455
function void closerTruck();
457
function bool buildInBase(STRUCTURESTAT _statToBuild, int _maxTrucks);
458
function void buildOnMap(STRUCTURESTAT _statToBuild, int _buildX, int _buildY, int _maxTrucks);
459
function DROID closestIdleTruck(int _x, int _y);
460
function bool buildUsingClosestTruck(STRUCTURESTAT _statToBuild, int _buildX, int _buildY, int _maxTrucks);
461
function FEATURE findBestOilToBuildOn(int _lookx, int _looky, int _maxRange);
462
function STRUCTURE findBestEnemyDerrick(int _targetPlayer, int _numAttackers, int _centerx, int _centery, int _maxRange);
463
function int posWeight(int _owner, int _x, int _y, int _range, int _centerx, int _centery);
464
function int oilWeight(int _owner, int _oilx, int _oily, int _centerx, int _centery);
468
function int numStatBusy(STRUCTURESTAT _structureToCheck, bool _bExcludeAlreadyBuilding); //On the way or already a certain building type
469
function int numStatMoveBusy(STRUCTURESTAT _structStatToCheck); //On the way
470
function int numTrucksBuilding(); //Number of trucks currently building something
471
function int numBusyByType(STRUCTURESTAT _busyStructType); //Num of certain structures busy
472
function int numBuildSameBuilding(STRUCTURESTAT _checkStat, int _x, int _y);
473
function int numTrucksSameOrderLoc(int _x, int _y, int _orderIndex);
474
function int numTrucksOrderInRange(int _rangex, int _rangey, int _range, int _order); //How many are building near this loc
475
function int numTrucksSameOrder(int _orderIndex);
476
function int numBuildingDefenses(); //How many building defenses
477
function int numBuildingBaseDefenses();
478
function int numBuildingNoBaseDefenses();
479
function int numVisibleOilResInRange(int _x, int _y, int _range);
480
function int numTotalOilInRange(int _x, int _y, int _range);
481
function int numDerricksInRange(int _targetPlayer, int _x, int _y, int _range);
482
function bool buildingSiteBlocked(DROID _truck, int _radius, int _x, int _y, bool _bAllOrders);
483
function int numDefenses();
484
function int numBaseDefenses();
485
function bool isInMyBase(int _checkX, int _checkY); //tests if x,y coords are in the base
486
function bool isNearAnyBase(int _x, int _y); //check if point is near someone's base
487
function bool isNearEnemyBase(int _x, int _y);
488
function bool isNearOil(int _x, int _y);
489
function bool isBaseStruct(STRUCTURE _checkStruct); //TRUE if one of the base structure types (like factory)
490
function int findResearch(int _searchStart, int _techTree);
491
function int calcNeededRes();
492
function void doResearchAll();
493
function int doResearch(STRUCTURE _resFac, int _resIndex);
494
function void getClosestCorner(int _x, int _y); //corner, closest to x,y
495
function STRUCTURE closestDerrick(int _x, int _y);
496
function FEATURE closestOilResource(int _x, int _y);
497
function void findFreeSpot(int _x, int _y);
498
function void findFreeSpotSmall(int _x, int _y);
499
function void findFreeSpotMedium(int _x, int _y);
500
function int repairStructure(STRUCTURE _damagedStruct, int _maxRepairers);
502
function bool needStartupScouts();
503
function bool canBuildTanks();
504
function void buildTanks();
505
function void buildVTOLs();
506
function void buildBaseDefenses();
507
function void cybFactorBuildCyborg(STRUCTURE _factory);
508
function void buildInitialDefenses(bool _bForceBuild);
509
function void stopInitialDefenses();
510
function void buildAA();
511
function void gatewayDefenses();
513
function void checkBase(int _player);
514
function bool findBase(int _targetPlayer);
515
function bool canSeePlayer(int _player);
516
function bool checkPlayerDead(int _player);
517
function void findAlternateTarget();
518
function void updateMilitaryStatus();
519
function int chooseEnemy();
521
function void resetOilDefendCoords();
522
function bool canStartDefendingOil();
523
function bool canStartAttack(int _enemy);
524
function bool canTheoreticallyStartAttack(); //count current attackers as well
525
function bool haveTheoreticallyMinAttackers(bool _bSafeToSendLittleAttackers); // have *any* attackers? (count current attackers as well)
526
function int numAvailableAttackers();
527
function int totalWeapUnits();
528
function bool canFollowAttackRequest(int _attackRequester, bool _bHighPriorityTask);
529
function int groupSizeCmds(GROUP _groupToCount, bool _bIncludeUnassigned,
530
bool _bIncludeCmds, bool _bInclDroidsAssignedToCmds);
532
function void checkStopAttack();
533
function void doAttack();
534
function void prepareAttackers(bool _bHighPriorityTask);
535
function void startAttack(int _enemy, int _x, int _y);
536
function void startEnemyBaseAttack(int _enemy);
537
function void startArtyCounterAttack(int _enemy, int _x, int _y);
538
function void vStartAttackBase(int _enemy);
539
//function void vAttackBase(int _enemy);
540
function int sortOutBBs();
541
function void checkBaseThreat();
542
function int checkAllyThreat();
543
function int findAllyInTrouble();
544
function void startHelpAlly(int _allyToHelp, int _helpx, int _helpy);
545
function void startDefending(int _counterEnemy);
546
function void startTakingOil(STRUCTURE _enemyDerrick);
547
function bool initializeStartTakingOil(int _oilx, int _oily, int _maxRange);
548
function bool canStartTakingOil();
549
function void startDefendingOil(int _derrickX, int _derrickY, int _maxTime);
550
function STRUCTURE findEnemyDerrick(int _targetPlayer);
551
function void manageHelpAlly();
552
function void fillAttackers(int _numAttackers);
553
function int numAttackersFromPriorty(bool _highPriorityTask);
554
function void fillReinforcements(bool _bHelping);
556
function void fillHelpers();
558
function int findBestAA();
559
function int findBestDefense();
561
function void setCollectingLoc();
562
function void startCollectingPhase(); //gather together
563
function void startCollecting(); //gather together
565
function bool canSendReinf(bool _forHelping); //have enough units tosend reinf?
566
function void coordinateSendMovement(int _sendX, int _sendY, int _range, int _order, GROUP _coordinateGr);
567
function bool checkReachedDestination(int _destX, int _destY, GROUP _toCheckGr, GROUP _toAddToGr, int _range);
569
function void updateTransport();
570
function void updateDropPhase();
572
function void startMovePhase();
573
function void startTransportState(GROUP _groupToTransport, int _destinationX, int _destinationY);
575
function void stopState();
576
function void stopJoiningForces();
577
function void stopDefendingBase();
578
function void stopTakingOil();
579
function void stopDefendingOil();
580
function void stopAttack();
581
function void stopCollecting();
582
function void stopAllyDefense();
583
function void stopTransportState();
584
function void stopDropState();
586
function void cancelState();
587
function void cancelJoiningForces();
588
function void cancelDefendingBase();
589
function void cancelTakingOil();
590
function void cancelDefendingOil();
591
function void cancelAttack();
592
function void cancelCollecting();
593
function void cancelAllyDefense();
594
function void cancelTransportState();
595
function void cancelDropState();
597
function void endJoiningForces();
598
function void endDefendingBase();
599
function void endTakingOil();
600
function void endDefendingOil();
601
function void endAttack();
602
function void endAllyDefense();
603
function void endTransportState();
604
function void endDropState();
606
function void pauseState();
607
function void resumeState();
608
function void erasePausedState();
609
function void resetSendForceCoords();
611
function void loadSavedState();
612
function void saveCurrentState();
613
function void eraseLoadSavedState();
615
function bool canStopCollecting(); //finished gathering or time is up
616
function bool finishedCollecting(); //finished gathering
618
function void doAlly(int _playerOffered);
620
function bool canRequestHelp();
621
function void requestHelp(int _x, int _y);
622
function void requestStatus(int _player);
623
function void checkRequestStatus();
624
function void requestStartAttack(int _enemy, int _x, int _y);
625
function void requestPrepareDrop();
626
function void dropAllyBeacon(STRING _cstr, int _x, int _y);
628
function void notifyAllies(STRING _cstr, bool _bUpdateRadar);
629
function void notifyAll(STRING _cstr);
630
function void notifyReadyAttack();
631
function void notifyIdle(bool bAfterFailure);
632
function void notifyTakeOil(int _enemy, int _x, int _y);
633
function void taunt(int targetPlayer, int type, int tauntProbability);
634
function void notifyStatus(int _playerToNotify);
635
function void notifyStatusAll();
636
function void notifyPower(int _targetPlayer);
637
function void notifyPlayerHasVTOLs(int _playerWithVTOLs);
638
function void notifyEnemyAtBase();
639
function void notifyPlayerDead(int deadPlayer);
640
function void notifyPlayerBaseDestroyed(int _destroyedPlayer);
641
function void notifyPlayerAlive(int _alivePlayer);
642
function void notifyPrepareDrop();
643
function void notifyStartDrop();
644
function void notifyCantDrop();
645
function void notifyLost();
647
function void refreshAllyRadar();
648
function void rememberPlayerIsAlive(int _alivePlayer);
650
function int bestAlliancePlayer();
651
function void makeAlliances();
652
function bool canAlly(int _player);
653
function void doOfferAlliance(int _alliancePlayer);
655
function void findAttackBaseTarget(DROID _looker, int _x, int _y, int _radius);
656
function void findBBAttackBaseTarget(DROID _looker);
658
function void storeBaseDefLocEv();
659
function void storeOilDefLocEv();
661
function void deselectAllDroids();
662
function void goRTB();
663
function void saveExperience();
665
function bool alliesReadyToDrop();
666
function bool timeToDrop();
667
function int numAlliesDroppingPlayer(int _player);
668
function int numActiveEnemyDrop(int _enemyToCheck);
669
function int getNumTransporters();
670
function bool enoughTransporters();
671
function void buildTransporters();
672
function bool enoughDroppers();
673
function void dropLoadTransport();
674
function void orderTranspDisembark(DROID _transporter, int _coordx, int _coordy);
675
function int chooseEnemyToDrop();
676
function void fillDroppers();
677
function bool transporterLoaded();
678
function bool checkTransportersLanded();
679
function void doDrop();
680
function void startDropPhase();
681
function void prepareTransporters();
682
function int setNumDroppers();
683
function int calcNumRequiredTransporters(int _numUnits);
684
function int numDroidsLoaded();
685
function void joinForces(int _joinPlayer, int _x, int _y);
686
function void requestEnemy(int _toAskPlayer);
687
//function void processCommand(int _msgPlayer, STRING _cstr, bool _bBlipMessage, string _processedString, int _targetPlayers);
688
function void processCommand(string _message, int _sender, bool _bBlipMessage);
689
function void processDebugCommand(int _msgPlayer, STRING _cstr);
690
function void assignDroid(DROID _droid);
691
function bool beaconTimeout(int _player);
692
function bool haveBeacon(int _player);
693
function void updateBeacons();
694
function bool isCurrentOrder(int _state, int _enemy);
695
function void updateStateCoord(int _newx, int _newy);
696
function void defendArea(GROUP _defendGr, int _range, int _defendX, int _defendY, int _defendCorridor, int _minDefenders);
697
function void cleanBaseCenter(GROUP _group, int _range, int _defendX, int _defendY, int _edgeX, int _edgeY, int _defendCorridor);
698
function DROID getTruckByTarget(BASEOBJ _target);
699
function int numBuildersInProduction(int _player);
700
function int numBBsInProduction(int _player);
701
function bool lowOnPower();
702
function void setState(int _newState);
703
function void vsetState(int _newState);
704
function void toggleDebugMenu();
705
function void shutDown();
706
function void oneTimeInitialize(bool bAIControlled);
707
function bool haveMinimalStructures();
708
function void checkMinimalStructures();
709
function void updateNumDefenders();
711
function bool canUseCommanders();
712
function int getNumCommanders();
713
function int getTotalCmdsCapacity(GROUP _group, bool _bIncludeInProduction);
714
function int getFreeCmdsCapacityInGroup(GROUP _group);
715
function void assignCommander(DROID _newCommander, GROUP _group);
716
function int numCommandersInProduction();
717
function void fillCommanderGroup(DROID _commander, GROUP _fillFromGroup);
718
function DROID closestDroidByGroup(GROUP _group, int _x, int _y, bool _bIncludeCommanders);
719
function void orderGroupLocCmd(GROUP _groupToOrder, int _order, int _x, int _y);
720
function void groupAddGroupCmd(GROUP _groupTo, GROUP _groupFrom);
721
function int initIterateGroupCmd(GROUP _groupToIterate, bool _bReturnNonCmds, bool _bReturnCmds, bool _bReturnCmdAssignedDroids);
722
function DROID iterateGroupCmd(GROUP _groupToIterate, int _bucket);
723
function int idleGroupCmd(GROUP _idleGroup, bool _bIncludeNonCmds, bool _bIncludeCmds);
724
function int cmdToIndex(DROID _commander);
725
function int groupCMD_x(GROUP _group);
726
function int groupCMD_y(GROUP _group);
727
function void groupAddCmd(GROUP _group, DROID _commander);
728
function void assignDroidToBestCommander(DROID _droid, GROUP _group);
729
function void unassignAllDroidsFromCMDsFromGroup(GROUP _unassignGroup, GROUP _toGroup);
730
function void unassignAllDroidsFromCMD(DROID _commander, GROUP _toGroup);
731
function void assignDroidsToBestCommandersFromGroup(GROUP _fromGroup, GROUP _toGroup);
732
function void fillBestCommandersCapacity(int _maxCapacity, GROUP _newGroup, GROUP _oldGroup);
734
// commander repairs functions
735
function int numMissingCmdRepairers(int _groupIndex, bool _bIncludeDeadCmds);
736
function DROID bestCommanderWithoutRepairer();
737
function void repairCMDGroup();
738
function DROID findCMDGroupObjectToRepair(int _cmdIndex, DROID _repairer);
740
function void setTechBranch();
742
function string groupToString(GROUP _group);
743
function string droidToGroupName(DROID _droid);
745
function void goToPerim(int _centerX, int _centerY, int _fromX, int _fromY, int _perimRange, int _order, DROID _droid);
747
function bool droidOrderIdle(DROID _droid);
748
function bool droidActionAttacking(DROID _droid);
749
function bool droidActionDroidRepair(DROID _repairer);
750
function bool defendingBase();
751
function bool counteringArty();
752
function bool attackingEnemyBase(int _enemy);
753
function bool idling();
754
function bool canStartArtyCouterAttack(int _enemy, int _x, int _y);
755
function bool helpingAlly();
756
function bool defendingOil();
757
function bool legoPhase();
758
function bool startupPhase();
759
function bool haveMinTrucks();
760
function bool gettingMinTrucks();
761
function BASEOBJ closerObject(BASEOBJ _obj1, BASEOBJ _obj2, int _x, int _y);
762
function float secondLanchasterLaw(float _fAllyStartForce, float _fEnemyStartForce, int _time, float _allyEffectiveness, float _enemyEffectiveness);
763
function bool LanchasterVictory(float _fStartForceA, float _fStartForceB, float _fKillRateA, float _fKillRateB);
764
function int LanchasterTimeToWin(float _fStartForceA, float _fStartForceB, float _fKillRateA, float _fKillRateB);
765
function float objBaseDamagePerSec(BASEOBJ _obj);
766
function float weaponDamagePerSec(int _player, WEAPON _weap);
767
function float enemyFirepowerInRange(int _x, int _y, int _range);
768
function float friendlyFirepowerInRange(int _x, int _y, int _range);
769
function float groupFirepower(GROUP _group);
770
function float groupHP(GROUP _group);
771
function float playerFirepowerInRange(int _player, int _x, int _y, int _range);
772
function int totalPlayerWeapObjHPInRange(int _player, int _x, int _y, int _range, bool _bVtols);
773
function int totalEnemyWeapObjHPInRange(int _x, int _y, int _range, bool _bVtols);
774
function int totalFriendlyWeapObjHPInRange(int _x, int _y, int _range, bool _bVtols);
775
function bool isTankTemplate(TEMPLATE _tmpl);
776
function void updateMaxScouts();
777
function void updateMapRevealFactor();
778
function bool buildOilDefenseFromExperience(int _index, DROID _truck);
779
function bool buildOilDefense(int _buildX, int _buildY, int _oilx, int _oily, DROID _truck);
780
function DROID closestEnemyDroidByType(int _x, int _y, int _range, int _type);
781
function int numDroidsByType(int _player, int _droidType);
783
function string strGratitude();
785
function TEMPLATE getBestTankATTemplate(int _factoryCapacity);
787
function void setPhase(int _phase, int _timeout);
788
function bool canSeePlayerBase(int _player);
789
function bool canSeeLoc(int _x, int _y);
790
function bool enemyTargetInRange(int _enemy, int _x, int _y, int _range);
791
function BASEOBJ findEnemyTargetInRange(int _enemy, int _x, int _y, int _range, bool _bStructures, bool _bDroids);
793
function PROPULSION getBestTankPropulsion();
794
function BODY getBestTankBody(int _factoryCapacity);
795
function WEAPON getBestTankATWeapon();
797
//=====================================================================
799
//=====================================================================
800
//event powerup(CALL_GAMEINIT)
801
event powerup(wait, 5)
803
local bool bMyRespons,bNotLost;
807
DEBUG_MSG = DEBUG_ALL; //isHumanPlayer(player);
809
MainDesc="DEBUG messages",
812
DEBUG_OBSERVE = DEBUG_ALL; /*%! ID="DEBUG_OBSERVE",
813
MainDesc="DEBUG observe mode",
816
DEBUG_POWER = FALSE; /*%! ID="DEBUG_POWER",
817
MainDesc="DEBUG power",
821
DEBUG_COMMANDS = DEBUG_ALL; /*%! ID="DEBUG_COMMANDS",
822
MainDesc="DEBUG commands",
828
bLearn = TRUE; //Use experience?
831
bRunning = FALSE; //remember this AI is inactive
835
myName = getPlayerColourName(me) & "-Aiv";
837
dbgMsgOn(me, DEBUG_MSG);
840
/* Check if this AI is inactive */
841
groupAddArea(tempGr, player, 0, 0, (mapWidth*128), (mapHeight*128));
842
structure = getStructure(fac, me);
845
if((tempGr.members == 0) and (structure == NULLOBJECT))
850
//find out if this player is controlled by AI
852
if(myResponsibility(me) and ((me != selectedPlayer) or DEBUG_OBSERVE))
854
if(bNotLost){ //alive?
857
dbg("deactivated", me);
862
dbg("not my responsibility", me);
865
//do common one-time initialization only if this player is loaded
867
oneTimeInitialize(bMyRespons);
870
//only load if AI is active
873
setEventTrigger(delayedMainInitialize, everySecTr);
877
event delayedMainInitialize(inactive)
879
if(GAME_TIME_IN_SECS >= me)
882
setEventTrigger(delayedMainInitialize, inactive);
886
/* Initialization for both AI and human player, to be performed once only */
887
function void oneTimeInitialize(bool bAIControlled)
889
local int loadExperienceStatus;
891
/* Decide what debug info to output to the watch window */
892
watchWindowDebug = WATCH_DEBUG_REINF;
897
if((mapWidth * mapHeight) > (125 * 125)) // > 125*125
904
//assign all dorids to an approriate group
905
unassignedDroids(defendGr, buildGr);
907
// remember base location
910
if(bLearn and bAIControlled)
912
loadExperienceStatus = loadPlayerAIExperience(me);
916
if(loadExperienceStatus == 0) //loaded successfully
918
dbg("Experience loaded successfully for player " & me, me);
920
else if(loadExperienceStatus < 0)
922
dbg("No saved experience found for player " & me, me);
926
dbg("Error while loading experience for player " & me, me);
931
/* Initialize ghost structures data */
934
while(count < maxGhosts)
936
ghostStat[count] = NULLSTRUCTURESTAT;
939
ghostDead[count] = TRUE;
943
groupIterateBucket = (-1);
946
storeTime = 120; //in seconds, how long to wait until next store if the same function void can be triggered
948
reinfTime = 0; //last time we send reinforcements
949
maxReinfTime = 420; // > 6 min
951
helpTime = 0; //last time we send reinforcements
952
maxHelpTime = 400; // > 6 min
955
maxTimeGuardPos = 180; //attackers wait at current pos
961
maxRequestHelpTime = 180; //3 min
964
maxCollectTime = 150;
966
timeNotifyEnemyInBase = 0;
967
maxTimeNotifyEnemyInBase = 300; //5 mins
969
maxTimeSaveExperience = 120; //2 mins
970
timeSaveExperience = maxTimeSaveExperience; //skip first time
972
maxAllyOfferTime = 500; //>7 min
975
tMaxWaitAlliesDrop = 420; //7 mins
978
tMaxSyncDrop = 300; //in secs
981
tMaxWaitLoadDrop = 150; //in secs
983
tMaxRequestStatus = 550; //randomized after every execution of requestStatus()
985
tMaxWaitPlayerReply = 30; //in secs
987
tLastBaseDefense = 0; //when started to build a base defense last time
989
dropStartTime = none;
991
minReinfCount = 3; //accept drop request if send minReinfToDrop reinforcements to this enemy and he's still alive
992
maxReinfCount = minReinfCount + random(4) + 2; //consider dropping an enemy if can't get him by land
994
maxTakeOil = 6; //max take oil reids we can make
996
numTakeOil = random(maxTakeOil);
998
// For the oil defense routine
999
resetOilDefendCoords();
1001
maxDefendRepairers = MAX_DEFEND_REPAIRERS;
1003
defWeight = 18; //defense weight for distance calculation
1004
weightDistFactor = 250; //factor for derrick weight calculation (divided by distance)
1006
notifyReadyAttackTime = 0;
1007
maxNotifyReadyAttackTime = 8 + random(12); //should be different for each AI
1008
bNotifiedReadyAttack = FALSE;
1010
maxTransporters = 9;
1014
while(count < MAX_PLAYERS)
1016
storeOilDefTime[count] = 0;
1017
storeBaseDefTime[count] = 0;
1018
allyOfferTime[count] = 0;
1019
lostDroids[count] = 0;
1020
lostStructs[count] = 0;
1025
/* Decide how many trucks we need */
1028
/* Total Unit limit */
1029
unitLimit = MAX_UNITS; //getUnitLimit(me);
1031
/* Set research limits */
1032
maxResearch = getStructureLimit(resFac, me); //use all we can
1033
fMinResearch = F_MIN_ACTIVE_RES_FAC;
1035
if(maxResearch <= 0){
1036
dbg("*************maxResearch = 0 *************", me);
1039
//fNumDefaultResearch = fMinResearch;
1040
fNumDefaultResearch = fMinResearch;
1043
/* Research urgency - controls how many research facilities are put to work */
1044
tResUrgencyTrackInterval = (MINUTE * 7); //How 'deep' our memory frame is, in secs - trimmed after tResUrgencyTrackInterval secs
1045
//it will take tResUrgencyTrackInterval seconds for maxResearch idle research facilities to reach highestResearchUrgency value
1046
fMaxResUrgency = (float)tResUrgencyTrackInterval * fNumDefaultResearch; // We haven't done much research lately, but trim it to some max value
1047
fMinResUrgency = (-fMaxResUrgency); //We've done alot research lately, can't go lower than this though
1048
fMaxResHold = (float)(MINUTE * 4) * fNumDefaultResearch; //Max time to hold all research, until it can be forced, in secs (fNumDefaultResearch num of res facs can wait 4 mins)
1049
fCurResUrgency = fMaxResHold; //(float)(MINUTE * 8) + fMaxResHold; //In 'secs', Increases with time when research is idle - make urgent at the beginning
1051
structNoLiveHealth = 9; //When to demolish structure if it's low on hitpoints, in %
1053
offeredEnemy = none; //last player an ally offered us to attack
1055
counterEnemy = none; //enemy that currently attacked us (used for counter attacks)
1061
alert = FALSE; //Emergency
1062
lowMilitary = FALSE;
1066
baseSq = 0; //base square
1068
aaRange = 0; //prim where to build base aa
1070
oilDefensesRange = OIL_DEFENSES_RANGE;
1072
// Initialize scout variables
1075
maxOilDef = MAX_OIL_DEFENSES_PER_LOC; /*%! ID="maxOilDef",
1076
MainDesc="max oil defenses",
1077
type="asn", //Assign
1079
ArgDesc="5 (Default)",
1089
numOilDef = maxOilDef;
1090
minOilDef = MIN_OIL_DEFENSES_PER_LOC; /*%! ID="minOilDef",
1091
MainDesc="min oil defenses",
1092
type="asn", //Assign
1094
ArgDesc="3 (Default)",
1105
minOilRecallPrior = MIN_OIL_RECALL_PRIORITY; //ignore derricks with lower defend priority
1107
maxInitialBaseDef = 2; //max defenses per defend site
1108
curInitialBaseDef = 1; //current number of defenses per defend site (rises slowly with time)
1109
maxInitialDefSites = 4;
1112
maxBaseDef = MAX_BASE_DEFENSES_PER_LOC;
1113
minBaseDef = MIN_BASE_DEFENSES_PER_LOC;
1114
numBaseDef = maxBaseDef;
1115
maxBaseDefenseLoc = MAX_BASE_DEFEND_LOCS; //build at max 6 locations
1116
maxBaseDefendDefLocTrucks = NUM_BASE_DEF_LOC_TRUCKS;
1125
phSearchingForBase = 4;
1132
phLoadingTransport = 11;
1133
phSync = 12; //Synchronizing with allies
1135
phTransportDone = 14; //signal for drop phase that transport phase is done successfully
1140
stDefendingBase = 2;
1143
stJoiningForces = 5;
1150
threatRange = (TILE * 10);
1152
tBeaconTimeout = 30; //in secs
1154
tLastResearch = 0; //when we did last research
1155
tMaxResearchIdle = 2 * 60; //max time to suspend research for, 2 mins, in secs
1156
numCriticalResearch = 1; //min research facilities to put to work if we did no research for long time
1158
initialDefensesFinished = false; //if finished building anti-rush defenses
1160
bFirstTimeDefenders = TRUE;
1166
lsReady = 2; //recharged
1167
//lsFinishingRecharging = 3; //will finish recharging lassat soon
1168
lsRequesterWaitingRecharging = 4; //someone requested a lassat strike and is waiting for us to finish recharging lassat
1169
lsWaitingReply = 5; //wait to find out if anyone wants to join
1170
lsWaitingForRequester = 6; //we finished recharging our lassat and are now waiting for the requester to start the strike
1171
lsDelayedFiring = 7; //requester firedand we are about to do a delayed fire
1172
lsWaiting = 8; //waiting for allies to fire
1175
tLasSat = 0; //how much time left till tLasSatReady (till recharged)
1176
tLasSatReady = 300; //300; //how long takes to recharge (in secs)
1177
tLasSatCountdown = off; //used for misc stuff
1178
tLasSatReplyMax = 6;
1179
tLasSatWaitAlliesMax = 45; //wait max x secs for allies' lasSat to fully recharge
1181
//initialize enemy and ally information
1183
while(count < 8) //multiPlayerMaxPlayers)
1186
lasSatState[count] = lsNone; //finished charging etc
1188
base[count][0] = none; //x
1189
base[count][1] = none; //y
1191
curBase[count][0] = none; //x
1192
curBase[count][1] = none; //y
1194
hasVTOLs[count] = FALSE;
1196
knowBase[count]= FALSE;
1197
seeBase[count] = FALSE;
1199
ally[count] = FALSE;
1200
dead[count] = (not playerLoaded(count)); //FALSE;
1204
dbg(getPlayerName(count) & " (" & count & ") is not loaded", me);
1207
killedBase[count] = FALSE;
1209
attacked[count] = 0; //num times attacked by this player
1210
reinfCount[count] = 0;
1211
tempReinfCount[count] = 0; //how many times we sent reinfs after the last time we dropped this enemy (tempReinfCount is reset everytime AI does a drop on a certain player and starts over)
1213
tRequestStatus[count] = tMaxRequestStatus + random(700);
1214
tWaitPlayerReply[count] = 0;
1216
allyState[count] = stNone;
1217
allyPhase[count] = phNone;
1218
allyEnemy[count] = none;
1220
curHelpX[count] = -1;
1221
curHelpY[count] = -1;
1224
beaconX[count] = -1;
1225
beaconY[count] = -1;
1226
tBeacon[count] = -1; //time of the last beacon msg
1228
//recall players base location
1231
if(recallPlayerBaseLoc(me, count, ref x, ref y)) //if this location stored
1233
if(x <= 0 or y <= 0)
1235
MsgBox("x or y <= 0");
1237
base[count][0] = x; //x
1238
base[count][1] = y; //y
1240
curBase[count][0] = x; //x
1241
curBase[count][1] = y; //y
1243
curHelpX[count] = curBase[count][0]; //where to go help
1244
curHelpY[count] = curBase[count][1];
1246
knowBase[count] = TRUE;
1248
dbg("recalled base location for " & getPlayerName(count), me);
1255
base[me][0] = baseX;
1256
base[me][1] = baseY;
1260
numOilAttackers = 5; //num units required before can start taking oil
1261
minOilAttackers = 3; //min units required before can start taking oil
1263
minDefenders = MIN_DEFENDERS; //min defenders to leave in base
1266
numDefenders = 0; //set in updateNumDefenders() now
1268
defendCorridor = (5 * 128); //range which defenders can stay in (baseRange)
1271
maxAttackers = 90; //(unitLimit - maxTrucks - numDefenders) * 3 / 4;
1272
numAttackers = 13 + random(12) + minAttackers;
1274
attackersIncrease = 4; // by how many units to increase number of attackers vs a certain player when attack fails
1276
// set initial number of attackers to use vs. all players
1278
while(count < MAX_PLAYERS)
1280
numPlayerAttackers[count] = numAttackers;
1284
minReinforcements = 5; //13 + random(8);
1290
maxDroppers = maxDroppers + 10;
1292
medDroppers = max(maxDroppers / 2, minDroppers);
1293
minDroppers = 10; //1 transporter
1295
maxAllyDroppers = 3 + random(2); //no more than x players
1304
attackedCount = 0; // how many times was attacked
1306
//Commanders belong to the defend group on start up
1308
while(count < MAX_COMMANDERS)
1310
cmds[count] = NULLOBJECT;
1311
cmdGr[count] = defendGr;
1315
//adapt for big maps
1318
minReinforcements = minReinforcements + random(2) + 3;
1321
maxAttackCyborgs = 40;
1324
function void mainInitialize()
1326
bRunning = TRUE; //remember this AI is active
1328
/* only change name if not human */
1329
if(not isHumanPlayer(me))
1331
setPlayerName(me, myName);
1334
reInitialize(); //assign variables
1338
mainEconomySelftest();
1339
mainMilitarySelftest();
1341
setEventTrigger(mainEconomySelftest, economySelftestTr); //Start
1342
setEventTrigger(mainMilitarySelftest, militarySelftestTr);
1343
setEventTrigger(doScout, doScoutTr);
1344
setEventTrigger(doResearchEv, doResearchTr);
1345
setEventTrigger(defendOil, defendOilTr);
1346
setEventTrigger(buildNormalOilDefenses, buildNormalOilDefensesTr);
1348
setEventTrigger(defendBase, defendBaseTr);
1349
setEventTrigger(structureAttacked, structureAttackedTr);
1350
setEventTrigger(droidAttacked, droidAttackedTr);
1351
setEventTrigger(everySecEv, everySecTr);
1352
//setEventTrigger(consoleEv, consoleTr);
1353
setEventTrigger(multiMsgEv, multiMsgTr);
1354
setEventTrigger(beaconEv, beaconTr);
1355
setEventTrigger(droidTakeOverEv, droidTakeOverTr);
1359
setEventTrigger(objectAttacked, objectAttackedTr);
1360
setEventTrigger(coordinatePhases, coordinatePhasesTr);
1362
setEventTrigger(allianceOffered, allianceOfferedTr);
1363
setEventTrigger(droidSeen, droidSeenTr);
1364
setEventTrigger(objectSeen, objectSeenTr);
1365
setEventTrigger(structBuilt, structBuiltTr);
1366
setEventTrigger(structDestroyed, structDestroyedTr);
1367
setEventTrigger(checkLost, checkLostTr);
1368
setEventTrigger(transLanded, transLandedTr);
1369
setEventTrigger(repairDefendDroids, repairDefendDroidsTr);
1370
setEventTrigger(manageCMDRepairsEv, manageCMDRepairsTr);
1371
setEventTrigger(droidBuilt, droidBuiltTr);
1372
setEventTrigger(buildStructureModel, buildStructureModelTr);
1373
setEventTrigger(startNewResearch, researchCompleteTr);
1374
setEventTrigger(startAllResearch, startAllResearchTr);
1375
setEventTrigger(evUpdateMapRevealFactor, updateMapRevealFactorTr);
1378
//---------------------------------------------------------
1380
//---------------------------------------------------------
1381
function void reInitialize()
1383
//if(IGNORE_MESSAGES)
1385
// console("multiplayer mode on for Aivolution " & me & " (cooperation off)");
1388
dbg("ACTIVE!!!", me);
1392
unassignedDroids(defendGr, buildGr); //assign all dorids to an approriate group
1395
baseDefendObj = NULLOBJECT;
1400
debugMenuUp = FALSE;
1402
setPhase(phNone, NONE);
1407
vsetState(stNone); //vtol state
1408
lastvState = stNone;
1413
curBase[me][0] = baseX;
1414
curBase[me][1] = baseY;
1415
curHelpX[me] = curBase[me][0]; //where to go help
1416
curHelpY[me] = curBase[me][1];
1421
noBaseTargets = TRUE; //didn't find any targets yet
1423
resetSendForceCoords(); //where to send the sendAttackGr units
1431
collectX = none; //where to gather forces
1435
allyInThreat = none; //what ally is in danger now?
1436
sendHelpRange = 18 * TILE; //range units should stay inside when helping ally in his base
1438
//dbg(" " & me & ") Num attackers: " & numAttackers);
1441
//if we have no trucks and no facs, deactivate events
1442
event checkLost(inactive)
1444
/* any base structures left? */
1446
while(temp < numBaseStructs)
1448
tempStruct = getStructureVis(baseStructs[temp], me, me);
1449
if(tempStruct != NULLOBJECT)
1451
exit; //yes, have a base structure
1456
// FIXME: might consider reactivating
1457
//if((getDroidCount(me) == 0) and
1458
// not (multiPlayerGameType == SKIRMISH and multiPlayerAlliancesType == ALLIANCES_TEAMS))
1460
if(getDroidCount(me) == 0)
1462
taunt(NONE, TAUNT_GAME_LOSS, 60);
1468
* Deactivete this AI
1470
function void shutDown()
1472
bRunning = FALSE; //remember this AI is inactive
1474
notifyPlayerDead(me);
1476
setEventTrigger(mainEconomySelftest, inactive);
1477
setEventTrigger(mainMilitarySelftest, inactive);
1478
setEventTrigger(doScout, inactive);
1479
setEventTrigger(doResearchEv, inactive);
1480
setEventTrigger(defendOil, inactive);
1481
setEventTrigger(buildNormalOilDefenses, inactive);
1482
setEventTrigger(defendBase, inactive);
1483
setEventTrigger(structureAttacked, inactive);
1484
setEventTrigger(droidAttacked, inactive);
1485
setEventTrigger(everySecEv, inactive);
1486
//setEventTrigger(consoleEv, inactive); //allow AI to re-activate itself again
1487
setEventTrigger(multiMsgEv, inactive);
1488
setEventTrigger(beaconEv, inactive);
1489
setEventTrigger(droidTakeOverEv, inactive);
1492
setEventTrigger(objectAttacked, inactive);
1493
setEventTrigger(coordinatePhases, inactive);
1495
setEventTrigger(allianceOffered, inactive);
1496
setEventTrigger(droidSeen, inactive);
1497
setEventTrigger(objectSeen, inactive);
1498
setEventTrigger(structBuilt, inactive);
1499
setEventTrigger(structDestroyed, inactive);
1500
setEventTrigger(checkLost, inactive);
1501
setEventTrigger(transLanded, inactive);
1502
setEventTrigger(repairDefendDroids, inactive);
1503
setEventTrigger(manageCMDRepairsEv, inactive);
1504
setEventTrigger(droidBuilt, inactive);
1505
setEventTrigger(startNewResearch, inactive);
1506
setEventTrigger(startAllResearch, inactive);
1507
setEventTrigger(evUpdateMapRevealFactor, inactive);
1509
dbg("DEACTIVATED SCRIPT!!!!!!!!!!!!!!!!!!", me);
1512
//---------------------------------------------------------
1513
// Deal with basic stuff
1514
//---------------------------------------------------------
1515
event mainEconomySelftest(inactive)
1520
doEconomyMisc(); /* should be done before any other economy tasks */
1524
event mainMilitarySelftest(inactive)
1526
doMilitaryMisc(); /* should be done before any other military tasks */
1530
//---------------------------------------------------------
1531
// Deal with basic military stuff
1532
//---------------------------------------------------------
1533
function void doMilitary()
1537
/* build anti-rush defenses */
1538
if(!initialDefensesFinished)
1540
//dbg("buildInitialDefenses() - doMilitary()", me);
1541
buildInitialDefenses(FALSE);
1544
if(!initialDefensesFinished and (gameTime >= 9000)) //max 15 mins
1546
stopInitialDefenses(); //enough
1549
/* manage helping ally process */
1550
if(state == stHelpingAlly) //did we choose to defend him?
1552
/* if checkAllyThreat detected that no enemies left and were helping ally, retreat back to base */
1556
if(helpTime > 0) //help didn't timeout yet
1562
dbg("DEFEND ALLY: time out, rtb!!!!!!!!!!!!!!!!!", me);
1563
notifyAllies(getPlayerName(enemy) & ", retreating for now, call me if you need me again" , false); //allyInThreat
1567
else if(defendingOil())
1569
if(tState >= maxStateTime)
1576
if((tech == techAir) or (playerPower(me) > muchoPower))
1581
if((tech == techTanks) or (playerPower(me) > muchoPower))
1583
// if(canBuildTanks())
1590
/* Build base defenses */
1591
if( ((GAME_TIME_IN_SECS - tLastBaseDefense) > (SECOND * 30)) or defendingBase()) //wait at least 30 secs
1593
// if(not((playerPower(me) <= lowPower) and defendingBase())) //build defenses only if not low on power and not defendingBase
1595
buildBaseDefenses();
1599
/* build AA defenses */
1600
/* if((!alert and !defendingBase()) or (playerPower(me) > highPower))
1605
/* build gateway defenses if enough power */
1606
if(!alert and (playerPower(me) > highPower) and (GAME_TIME_IN_SECS > (MINUTE * 20))) //don't waste too much power on it; don't waste startup power
1611
/* check if tired attacking an enemy and want to try to drop him instead */
1612
if(attackingEnemyBase(enemy))
1614
if((tempReinfCount[enemy] >= maxReinfCount) and (groupSizeCmds(attackGr,true,false,true) <= 1)) //if we attacked too many times and current attack failed too
1616
result2 = random(3);
1622
result = numResearchLeft(me, resUnitTransporter);
1623
if(result <= 3) //won't take too long
1625
dbg("ATTACKED ENEMY TOO MANY TIMES: drop instead!!!", me);
1631
enemy = result; //same enemy
1632
requestPrepareDrop();
1637
/* wipe out some derricks */
1640
// make sure we have enough units
1641
if(canStartTakingOil())
1643
structure = findEnemyDerrick(enemy);
1645
if(structure != NULLOBJECT)
1647
dbg("ATTACKED ENEMY TOO MANY TIMES: wipeout oil instead!!!", me);
1648
pauseState(); //resume when done hunting enemy derricks
1650
startTakingOil(structure);
1651
notifyTakeOil(structure.player, structure.x, structure.y);
1658
/* see if we want to drop someone ... just out of fun */
1661
if((state == stNone) and (random(10) > 6))
1663
if((notifyReadyAttackTime <= 0) and (bNotifiedReadyAttack == FALSE)) //make sure not about to start attack
1665
//result = enoughDroppers();
1666
if(enoughDroppers())
1668
result = numResearchLeft(me, resUnitTransporter);
1669
if(result <= 6) //won't take too long
1671
result = chooseEnemyToDrop();
1672
if(result != none) //found any enemy targets?
1675
requestPrepareDrop();
1684
/* build transporters if gonna drop */
1686
if((state == stDrop) and researchFinished(resUnitTransporter, me)) //gonna drop and got unit transporter tech
1688
//temp = enoughTransporters();
1689
if((not alert) and (not enoughTransporters()))
1691
buildTransporters();
1695
/* see if we want to blow up some enemy derricks */
1696
if(countTakeOil < numTakeOil) //don't do too often
1698
if((state == stNone) and (notifyReadyAttackTime <= 0) and (bNotifiedReadyAttack == FALSE)) //not busy and not about to start attack
1700
result = numAvailableAttackers();
1701
if((random(10) < 7) and (result >= numOilAttackers))
1703
structure = findEnemyDerrick(none); //any player
1704
//structure = retStruct;
1706
if(structure != NULLOBJECT)
1708
startTakingOil(structure);
1709
notifyTakeOil(structure.player, structure.x, structure.y);
1716
/* start land attack */
1719
//result = canTheoreticallyStartAttack(); //enough units in total
1720
/* if(canTheoreticallyStartAttack()) //we can start
1722
if(noBaseTargets) //if couldn't find any enemy main bases
1724
findAlternateTarget(); //find any other visible target
1727
if(not noBaseTargets) //notify only if can actually start attacking someone
1729
if(bNotifiedReadyAttack or (not playerInAlliance(me))) //already notified or no allies
1731
result = chooseEnemy(); //should be able to find enemy if (not noBaseTargets)
1732
if(result != none) //found any enemy targets?
1734
if(canStartAttack(result))
1737
startEnemyBaseAttack(result);
1738
requestStartAttack(result, curBase[result][0], curBase[result][1]);
1743
dbg("ATTACK: failed to find an enemy", me);
1746
else if(notifyReadyAttackTime <= 0) //haven't started countdown already
1748
if(haveTheoreticallyMinAttackers(false))
1750
notifyReadyAttack(); //notify allies and wait for orders
1757
/* Continue military actions if we are attacking */
1758
if(state == stAttacking)
1764
/* remind allies we are in trouble */
1767
if(canRequestHelp())
1769
requestHelp(baseX, baseY); //do once in a while
1777
function void doMilitaryMisc()
1779
militarySelftest(); //misc stuff
1781
/* set tech branch */
1782
if((tech == none) and (gameTime > 100))
1784
setTechBranch(); // decide what we will research
1787
/* create alliances */
1788
if(not alliancesLocked() and (gameTime > 100))
1790
if(numAllies(me) < (multiPlayerMaxPlayers / 2)) //not allied to too many players already
1799
/* Make sure we are not under heavy attack */
1800
if(gameTime > 1800) //3 mins, in case bases are close to each other
1802
checkBaseThreat(); //set or cancel base threat alert
1806
/* find enemies and allies and their bases (targets) */
1807
updateMilitaryStatus();
1809
/* if we haven't heard anything from our allies for a long time, ask what they are doing */
1810
checkRequestStatus();
1812
/* Update minimum number of defender units to use */
1813
updateNumDefenders();
1816
//---------------------------------------------------------
1817
// Deal with basic economy stuff
1818
//---------------------------------------------------------
1819
function void doEconomyMisc()
1824
/* Returns true if it's the beginning of the game */
1825
function bool legoPhase()
1827
if(GAME_TIME_IN_SECS <= LEGO_PHASE_LEN){
1834
/* Returns true the game has just started */
1835
function bool startupPhase()
1837
if(GAME_TIME_IN_SECS <= STARTUP_PHASE_LEN){
1844
function bool haveMinTrucks()
1846
if(groupSizeCmds(buildGr,true,false,true) >= minTrucks){
1853
// have trucks + num building
1854
function bool gettingMinTrucks()
1856
if((groupSizeCmds(buildGr,true,false,true) +
1857
numBuildersInProduction(me)) >= minTrucks)
1865
function void buildMoreOil()
1867
local int _maxRange;
1871
_maxRange = TILE * 50;
1873
if(numStatBusy(derrick, true) < maxBuildOilTrucks)
1875
_oil = findBestOilToBuildOn(-1, -1, -1); //just find the best oil on the map
1876
if(_oil != NULLOBJECT)
1878
_truck = closestIdleTruck(_oil.x, _oil.y);
1880
if(_truck != NULLOBJECT)
1882
orderDroidStatsLoc(_truck, DORDER_BUILD, derrick, _oil.x, _oil.y);
1888
function void doEconomy()
1890
local int _numBuilders;
1891
local bool _bBaseHasHighPriority;
1895
/* build AA defenses */
1896
if(!defendingBase() or (playerPower(me) > muchoPower))
1901
//dbg(" " & me & ") doEconomy");
1902
if(DEBUG_POWER and (playerPower(me) <= lowPower)){
1903
addPower(highPower - 300, me);
1906
// send a droid to build oil if we have just started or we are not low on trucks and there are many unoccupied oil resources
1907
if((numVisibleOilResInRange(-1,-1,-1) >= 4) or legoPhase())
1912
dbg(numVisibleOilResInRange(-1,-1,-1) & " oil resources are visible", me);
1918
//dbg(" " & me & ") buildTrucks");
1921
// dbg("NEED TRUCKS", me);
1927
// dbg("DON'T NEED TRUCKS", me);
1929
//dbg(" " & me & ") checkPowerGen");
1931
//Make sure we have all vital base structures (factory, power getm etc)
1932
if(!haveMinimalStructures()){
1933
checkMinimalStructures();
1938
//dbg(" " & me & ") repair");
1940
// see if we have to repair base structure before some other tasks
1941
_bBaseHasHighPriority = defendingBase();
1942
if(_bBaseHasHighPriority and (haveMinTrucks() or !needTrucks())) //don't send if low on trucks
1948
// don't update factories while we building initial trucks, to get them faster (5 mins max)
1949
_numBuilders = groupSizeCmds(buildGr,true,false,true);
1950
if(! (!haveMinTrucks() and legoPhase()) )
1955
// upgrade power generators
1958
if(state == stDrop) //give it a higher priority if going to drop
1963
//dbg(" " & me & ") buildOil");
1965
/* Build derricks */
1966
if(not structureLimitReached(derrick, me)) //don't try if can't
1968
buildOil( defendingBase() ); //don't go away from base if in danger and low on trucks
1971
/* Build factories and research facilities */
1974
if(!_bBaseHasHighPriority and (haveMinTrucks() or !needTrucks()) )
1980
if(!alert and (state != stDrop)){
1987
//dbg(" " & me & ") END doEconomy()");
1990
function void economySelftest()
1993
exit; //wait until power is initialized
1995
bResult = alert; //remember last state
1997
/* if base is in danger ignore anything else */
1998
if((playerPower(me) <= highPower) and (groupSizeCmds(defendGr,true,false,true) < numDefenders))
2002
if(not bResult){dbg("economy - not enough defenders (!!!!!)", me);}
2009
/* restet lowMilitary */
2012
if(groupSizeCmds(defendGr,true,false,true) >= numDefenders)
2014
lowMilitary = FALSE; //reset here
2016
dbg("lowMilitary back to normal (!!!!!)", me);
2021
exit; //don't reset alert until lowMilitary is back to normal
2024
if(playerPower(me) >= lowPower)
2026
numOilDef = maxOilDef;
2027
numBaseDef = maxBaseDef;
2029
else if(playerPower(me) <= noPower) //no power
2031
numOilDef = minOilDef;
2032
numBaseDef = minBaseDef;
2035
/* set alert and lowMilitary */
2036
if(playerPower(me) >= lowPower) //high power, back to normal
2040
else if(playerPower(me) <= noPower) //no power
2042
if(!haveMinTrucks() and needTrucks())
2045
if(not bResult){dbg("economy low on trucks (!!!!!)", me);}
2050
if((getNumStructures(fac,me) < minFacs) or (getNumStructures(powGen,me) == 0))
2053
if(not bResult){dbg("economy low on vital structures (!!!!!)", me);}
2059
if((gameTime > 4200) and (groupSizeCmds(defendGr,true,false,true) < numDefenders))
2063
if(not bResult){dbg("economy - not enough defenders (!!!!!)", me);}
2068
if(bResult and (not alert))
2070
dbg("Economy back to normal !!!!!!", me);
2074
function void updateMaxTrucks()
2076
local int _numHaveTrucks;
2078
minTrucks = 6; //Critical number
2082
// we need more at startup
2084
maxTrucks = maxTrucks + 4;
2087
// we need more trucks if there's a lot of defences to build
2088
if(getBaseDefendLocCount() > 0){
2092
// the more unoccupied oil we have the more trucks we need
2093
maxTrucks = maxTrucks + numVisibleOilResInRange(-1,-1,-1) / 4;
2094
minTrucks = minTrucks + numVisibleOilResInRange(-1,-1,-1) / 4;
2098
maxTrucks = maxTrucks + 3;
2099
minTrucks = minTrucks + 1;
2102
_numHaveTrucks = groupSizeCmds(buildGr,true,false,true);
2104
// decide how many trucks are allowed to be building derricks at a time (used to be 7)
2105
maxBuildOilTrucks = (_numHaveTrucks + 1) / 2;
2107
// max trucks building defenses at a time
2108
if(!haveMinTrucks()){
2109
maxBaseDefenseTrucks = 1;
2110
maxOilDefenseTrucks = max(1,_numHaveTrucks / 3);
2112
maxBaseDefenseTrucks = max(2, _numHaveTrucks / 4);
2113
maxOilDefenseTrucks = max(1, (int)((float)_numHaveTrucks / 1.9));
2118
if(haveMinTrucks()){
2119
maxOilDefenseTrucks++;
2123
// how many trucks to use for a single base defense location
2124
maxBaseDefendDefLocTrucks = NUM_BASE_DEF_LOC_TRUCKS;
2125
if(defendingBase()){
2126
maxBaseDefendDefLocTrucks = MAX_BASE_DEF_LOC_TRUCKS;
2130
function void showVersion()
2132
dbg("Aivolution AI active for player " & me & " (version " & sVer & ")", me); //show to the local player
2135
function void storeBase()
2137
local STRUCTURE _structure;
2139
local bool _bHaveBaseStructs;
2140
local int _index,_baseX,_baseY,_numBaseStructs,_bucket;
2143
_bHaveBaseStructs = FALSE;
2145
//Go through all structures
2147
_numBaseStructs = 0;
2150
while(_index < numBaseStructs)
2152
initEnumStruct(FALSE,baseStructs[_index],me,me);
2153
_structure = enumStruct();
2154
while(_structure != NULLOBJECT)
2156
_baseX = _baseX + _structure.x / TILE;
2157
_baseY = _baseY + _structure.y / TILE;
2160
_structure = enumStruct();
2165
if(_numBaseStructs > 0)
2167
baseX = (_baseX / _numBaseStructs) * TILE;
2168
baseY = (_baseY / _numBaseStructs) * TILE;
2172
_bucket = initIterateGroupCmd(buildGr,true,false,true); // find idle droids in build group.
2173
_truck = iterateGroupCmd(buildGr, _bucket);
2175
if(_truck != NULLOBJECT){
2179
baseX = (TILE * mapWidth) / 2;
2180
baseY = (TILE * mapHeight) / 2;
2182
console("Couldn't find base location for " & getPlayerName(me));
2187
function void fixGroups()
2189
InitEnumDroids(me,me);
2190
tempDroid = EnumDroid();
2191
while(tempDroid != NULLOBJECT)
2193
droidLeaveGroup(tempDroid);
2194
tempDroid = EnumDroid();
2198
event diffMod(diffModTr)
2200
if(not isHumanPlayer(me) and modifierOn)
2202
skDifficultyModifier(me);
2206
function void goRTB()
2208
local int _x, _y,_index;
2210
dbg("Going back to base", me);
2212
ASSERT(sendForceX != none and sendForceY != none, "goRTB: sendForceX < 0", me);
2214
groupAddGroupCmd(sendAttackGr, attackGr);
2216
// send to the base perimeter
2217
if(sendForceX != baseX and sendForceY != baseY) // can be equal if were send to defend the base
2224
// send to last defend location
2225
if(defendX != NONE and defendY != NONE)
2232
circlePerimPoint(baseX, baseY, ref _x, ref _y, baseRange); //move locations to the derrick perimeter
2234
// find a place with enough space
2235
pickStructLocation(powGen, ref _x, ref _y, me);
2237
//Order droids and commanders
2238
orderGroupLocCmd(sendAttackGr, DORDER_MOVE, _x, _y);
2240
//Move all droids and commanders to defend group
2241
groupAddGroupCmd(defendGr, sendAttackGr);
2244
event buildStructureModel(inactive)
2246
local STRUCTURE _structure;
2251
initEnumStruct(TRUE,wall,me,me);
2252
_structure = enumStruct();
2253
while((_structure != NULLOBJECT) and (i < maxGhosts))
2255
/* Remember initial walls and defenses */
2256
if((_structure.stat == wall) or (_structure.stattype == REF_DEFENSE))
2258
ghostStat[i] = _structure.stat;
2259
ghostx[i] = _structure.x;
2260
ghosty[i] = _structure.y;
2261
ghostDead[i] = FALSE;
2265
_structure = enumStruct();
2268
dbg("Model saved (" & i & ")", me);
2271
function void updateBeacons()
2276
if(beaconTimeout(count)) //last beacon timed out
2278
dbg("beacon timeout for " & count, me);
2280
tBeacon[count] = -1;
2282
beaconX[count] = -1;
2283
beaconY[count] = -1;
2285
curHelpX[count] = curBase[count][0]; //restore base and help location
2286
curHelpY[count] = curBase[count][1];
2292
//---------------------------------------------------------
2294
//---------------------------------------------------------
2295
function void baseDetails()
2298
miny = (mapHeight*128); minx = (mapWidth*128);
2300
baseRange = 1; //avoid possible div by 0
2304
while(count < numBaseStructs)
2306
initEnumStruct(FALSE,baseStructs[count],me,me);
2307
structure = enumStruct();
2308
while(structure != NULLOBJECT)
2310
if(structure.x < minx){minx = structure.x;}
2311
if(structure.x > maxx){maxx = structure.x;}
2312
if(structure.y < miny){miny = structure.y;}
2313
if(structure.y > maxy){maxy = structure.y;}
2315
result = distBetweenTwoPoints(baseX, baseY, structure.x, structure.y);
2316
if(result > baseRange){baseRange = result;}
2318
structure = enumStruct();
2325
minx = minx - result; maxx = maxx + result;
2326
miny = miny - result; maxy = maxy + result;
2328
if(minx < 0){minx = 128;}
2329
if(miny < 0){miny = 128;}
2330
if(maxx > (mapWidth * 128)){maxx = (mapWidth * 128) - 128;}
2331
if(maxy > (mapHeight * 128)){maxy = (mapHeight * 128) - 128;}
2333
aaRange = baseRange + 128; //between the base and baseRange
2335
baseRange = baseRange + (5 * 128);
2338
//baseSq = ((maxx - minx) / 128) * ((maxy - miny) / 128);
2341
//---------------------------------------------------------
2342
// Prepare scouting routines
2343
//---------------------------------------------------------
2344
function void startEnemyScout()
2346
bEnemyScoutHor = TRUE;
2348
//only one of these is actually used, depending on bEnemyScoutHor
2349
bEnemyScoutToBottom = TRUE;
2350
bEnemyScoutToRight = TRUE;
2352
getClosestCorner(baseX, baseY); //find corner we are closest to
2356
if(not mapRevealedInRange(x,y,enemyScoutRange,me))
2358
//make this the first place scouts will visit
2361
//dbg("can visit corner", me);
2365
dbg("can't visit corner", me);
2368
setEventTrigger(scoutForEnemy, scoutForEnemyTr);
2371
function bool finishDefenses(DROID _truck, int _repairx, int _repairy, int _maxRange)
2374
local STRUCTURE _defense;
2378
while(!_bOK and (_def >= 0))
2380
initEnumStruct(FALSE,def[_def],me,me);
2381
_defense = enumStruct();
2382
while(!_bOK and (_defense != NULLOBJECT))
2384
if(!structureComplete(_defense))
2386
if(distBetweenTwoPoints(_repairx, _repairy, _defense.x, _defense.y) < _maxRange)
2388
if(!buildingSiteBlocked(_truck, _maxRange, _defense.x, _defense.y, true))
2390
orderDroidStatsLoc(_truck, DORDER_BUILD, def[_def], _defense.x, _defense.y);
2391
dbg("finishing defense at " & (_defense.x / TILE) & "-" & (_defense.y / TILE), me);
2396
_defense = enumStruct();
2405
function void finishStructures()
2407
initIterateGroupB(buildGr, me);
2408
droid = iterateGroupB(buildGr, me);
2409
while(droid != NULLOBJECT)
2411
if((droid.order == DORDER_NONE) or (droid.order == DORDER_RTB))
2413
//Check all base structures first
2414
//-------------------------------------
2416
structure2 = NULLOBJECT;
2419
while(count < numBaseStructs)
2421
initEnumStruct(FALSE,baseStructs[count],me,me);
2422
structure = enumStruct();
2423
while(structure != NULLOBJECT)
2425
if(not structureComplete(structure))
2428
result3 = distBetweenTwoPoints(baseX, baseY, structure.x, structure.y);
2429
if(result3 < result)
2431
//Make sure no one's building already
2432
//result2 = buildingSiteBlocked(NULLOBJECT, 128, structure.x, structure.y);
2434
if(not buildingSiteBlocked(NULLOBJECT, 128, structure.x, structure.y, false))
2436
structure2 = structure;
2441
structure = enumStruct();
2447
//------------------------------
2448
if(structure2 == NULLOBJECT)
2450
initEnumStruct(TRUE,fac,me,me); //all
2451
structure = enumStruct();
2452
while(structure != NULLOBJECT)
2454
if(not structureComplete(structure))
2457
result3 = distBetweenTwoPoints(baseX, baseY, structure.x, structure.y);
2458
if(result3 < result)
2460
//Make sure no one's building already
2461
//result2 = buildingSiteBlocked(NULLOBJECT, 128, structure.x, structure.y);
2463
if(not buildingSiteBlocked(NULLOBJECT, 128, structure.x, structure.y, false))
2465
//check for threat, since can be far from the base
2466
if(not threatInRange(me, structure.x, structure.y, threatRange, FALSE))
2468
structure2 = structure;
2474
structure = enumStruct();
2479
if(structure2 != NULLOBJECT)
2481
bDummy = buildUsingClosestTruck(structure2.stat, structure2.x, structure2.y, 1);
2486
droid = iterateGroupB(buildGr, me);
2490
function bool canSendReinf(bool _forHelping)
2492
local int _numAvailable, _minSendUnits,
2493
_fightRange,_numAllies,_enemyHP,_friendlyHP;
2494
local int _travelTime,_travelDist,
2495
_predictedEnemyReinf,_minTravelingUnits,
2496
_sentReinfTravelTime,_numEnemies,_sentReinfTravDist,_sendRange,
2497
_numReinfOnTheWay,_timeToWin,_timeToLose,
2498
_reinfLoseTime,_reinfWinTime;
2499
local float _enemyKillRate,_allyKillRate,_fFriendlyAvUnitFirepower,_fEnemyAvUnitFirepower,
2500
_fEnemyHPFactor,_fFriendlyHPFactor,_fEnemyAvUnitStrength,
2501
_fFriendlyAvUnitStrength,_fFriendlyFirepower,_fEnemyFirepower,
2502
_fNumAttackersLeft,_fNumEnemiesLeft,_fNumEffectiveReinf,
2503
_fNumReinfAttackersLeft,_fNumReinfEnemiesLeft,_fNumReinfLeft,
2504
_fReinfAvUnitStrength,_fReinfAvKillRate,_fReinfEnAvKillRate,
2505
_fReinfAvFirepower,_fAllyCompoundKillRate,_fEnemyCompoundKillRate,
2507
local bool _bWin,_bWinWithSentReinf;
2509
// Calculate how many units we have available
2510
_numAvailable = groupSizeCmds(defendGr,true,false,true) - numDefenders; //use less units
2511
if(_forHelping) //use more units if helping
2513
_numAvailable = groupSizeCmds(defendGr,true,false,true) -
2514
min(minDefenders, numDefenders); //leave only minimal number of derenders
2517
_numAvailable = max(0,_numAvailable);
2519
// if(_numAvailable > 0)
2521
_fightRange = REINF_ENEMY_COUNT_RANGE;
2523
// range when sendAttackGr units get added to attackGr
2525
_sendRange = sendHelpRange;
2526
}else if(defendingOil()){
2527
_sendRange = REACHED_DEF_OIL_RANGE;
2529
_sendRange = REACHED_DEST_RANGE;
2532
// Calculate travel distance of the reinforcements
2533
_travelDist = ( max(0, distBetweenTwoPoints(sendForceX, sendForceY, baseX, baseY) -
2534
baseRange - defendCorridor)) / TILE;
2536
// Calculate travel time of the reinforcements
2537
_travelTime = TILE_TRAVEL_TIME * _travelDist;
2539
_numReinfOnTheWay = groupSizeCmds(sendAttackGr,true,false,true);
2541
// If there are already old reinforcements on the way to the attack location, calc how long they need to arrive
2542
_sentReinfTravDist = 0;
2543
_sentReinfTravelTime = 0;
2544
if(_numReinfOnTheWay > 0)
2546
_sentReinfTravDist = distBetweenTwoPoints(sendForceX, sendForceY, groupCMD_x(sendAttackGr), groupCMD_y(sendAttackGr)) / TILE;
2547
if(_sentReinfTravDist > _sendRange) //make sure won't count sendAttackGr members twice
2549
_sentReinfTravelTime = TILE_TRAVEL_TIME * _sentReinfTravDist;
2553
// Determine number of enemy and friendly units in range
2554
_numEnemies = numEnemyWeapObjInRange(me, sendForceX, sendForceY, _fightRange, false, true);
2555
_numAllies = numFriendlyWeapObjInRange(me, sendForceX, sendForceY, _fightRange, false, true);
2557
// Calculate enemy and friendly strengths
2558
_fNumAttackersLeft = (float)_numAllies;
2559
_fNumEnemiesLeft = (float)_numEnemies;
2561
// if(_numEnemies > 0 and _numAllies > 0)
2563
// Calculate total hp of the weapon objects
2565
_friendlyHP = totalFriendlyWeapObjHPInRange(sendForceX, sendForceY, _fightRange, false);
2568
if(_numEnemies > 0){
2569
_enemyHP = totalEnemyWeapObjHPInRange(sendForceX, sendForceY, _fightRange, false);
2572
// Find out how much stronger friendly/enemy units are compared
2573
// to the default unit hp used to measure default kill rate
2574
_fFriendlyAvUnitStrength = 0.0;
2575
if(_friendlyHP > 0 and _numAllies > 0){
2576
_fFriendlyAvUnitStrength = (float)_friendlyHP / (float)_numAllies;
2579
_fEnemyAvUnitStrength = 0.0;
2580
if(_enemyHP > 0 and _numEnemies > 0){
2581
_fEnemyAvUnitStrength = (float)_enemyHP / (float)_numEnemies;
2584
// _fEnemyAvUnitFirepower = _enemyPower / _numEnemies;
2585
// _fFriendlyAvUnitFirepower = _friendlyPower / _numAllies;
2587
_fFriendlyFirepower = friendlyFirepowerInRange(sendForceX, sendForceY, _fightRange);
2589
_fFriendlyAvUnitFirepower = _fFriendlyFirepower / (float)_numAllies; //can't use group here because of possible ally units
2592
_fEnemyFirepower = enemyFirepowerInRange(sendForceX, sendForceY, _fightRange);
2593
if(_numEnemies > 0){
2594
_fEnemyAvUnitFirepower = _fEnemyFirepower / (float)_numEnemies;
2597
// Calculate how fast units kill each other (one unit vs one enemy unit)
2598
if(_fEnemyAvUnitStrength > 0.0){
2599
_allyKillRate = _fFriendlyAvUnitFirepower / _fEnemyAvUnitStrength;
2602
if(_fFriendlyAvUnitStrength > 0.0){
2603
_enemyKillRate = _fEnemyAvUnitFirepower / _fFriendlyAvUnitStrength;
2606
// Calculate predicted number of attackers left in the attackGr when reinforcements will arrive
2607
_fNumAttackersLeft = (float)_numAllies;
2608
_fNumEnemiesLeft = (float)_numEnemies;
2610
_fNumAttackersLeft = secondLanchasterLaw((float)_numAllies,(float)_numEnemies,_travelTime,_allyKillRate,_enemyKillRate);
2611
_fNumEnemiesLeft = secondLanchasterLaw((float)_numEnemies,(float)_numAllies,_travelTime,_enemyKillRate,_allyKillRate);
2613
_bWin = LanchasterVictory((float)_numAllies, (float)_numEnemies, _allyKillRate, _enemyKillRate);
2615
// calculate how much time it will take for us to win
2617
_timeToWin = LanchasterTimeToWin((float)_numAllies, (float)_numEnemies, _allyKillRate, _enemyKillRate);
2619
// if(_timeToWin < _travelTime)
2621
_fNumAttackersLeft = secondLanchasterLaw((float)_numAllies,(float)_numEnemies,_timeToWin,_allyKillRate,_enemyKillRate);
2622
_fNumEnemiesLeft = 0.0;
2625
_timeToLose = LanchasterTimeToWin((float)_numEnemies, (float)_numAllies, _enemyKillRate, _allyKillRate);
2627
// if(_timeToWin < _travelTime)
2629
_fNumAttackersLeft = 0.0;
2630
_fNumEnemiesLeft = secondLanchasterLaw((float)_numEnemies,(float)_numAllies,_timeToLose,_enemyKillRate,_allyKillRate);
2634
// How many reinforcements do we have considering their number and distance to the battlefield
2635
_fNumEffectiveReinf = fmax(0.0, (float)_numReinfOnTheWay - (float)_sentReinfTravelTime / (float)SECONDS_PER_DROID);
2637
// if we are going to lose see if reinforcements that are already on the way (!) will make it in time
2638
_bWinWithSentReinf = true;
2640
// Reinforcements vs Enemy
2641
//------------------------------------------
2642
_fReinfAvUnitStrength = 0.0;
2643
_fReinfAvFirepower = 0.0;
2644
_fReinfAvKillRate = 0.0;
2645
if(_numReinfOnTheWay > 0)
2647
_fReinfAvUnitStrength = groupHP(sendAttackGr) / (float)_numReinfOnTheWay;
2648
_fReinfAvFirepower = groupFirepower(sendAttackGr) / (float)_numReinfOnTheWay;
2650
// kill rate our reinforcements vs the original enemy force
2651
if(_fEnemyAvUnitStrength > 0.0){
2652
_fReinfAvKillRate = _fReinfAvFirepower / _fEnemyAvUnitStrength;
2655
// kill rate of the riginal enemy force vs our reinforcements
2656
if(_fReinfAvUnitStrength > 0.0){
2657
_fReinfEnAvKillRate = _fEnemyAvUnitFirepower / _fReinfAvUnitStrength;
2662
// check if reinforcements will be able to win against the enemy force
2663
if(!_bWin and _numReinfOnTheWay > 0) // will lose and have reinforcements that are already on the way to the battlefield
2665
// check if reinf will be there before we lose
2666
if(_sentReinfTravelTime < _timeToLose)
2668
// calc how many units will be left when sent reinf will arrive
2669
_fNumReinfAttackersLeft = secondLanchasterLaw((float)_numAllies,(float)_numEnemies,_timeToLose,_allyKillRate,_enemyKillRate);
2670
_fNumReinfEnemiesLeft = secondLanchasterLaw((float)_numEnemies,(float)_numAllies,_timeToLose,_enemyKillRate,_allyKillRate);
2672
// Original attackForce + old reinforcements
2673
_fTotalAllyUnits = (float)_numReinfOnTheWay + _fNumReinfAttackersLeft;
2675
// kill rate of original attackers and reinforcements
2676
_fAllyCompoundKillRate = (( (float)_numReinfOnTheWay * _fReinfAvKillRate +
2677
_fNumReinfAttackersLeft * _allyKillRate)) / _fTotalAllyUnits;
2679
// kill rate of original enemy force against original ally force and reinforcements
2680
_fEnemyCompoundKillRate = _fEnemyAvUnitFirepower /
2681
(( (float)_numReinfOnTheWay * _fReinfAvUnitStrength +
2682
_fNumReinfAttackersLeft * _fFriendlyAvUnitStrength) / _fTotalAllyUnits);
2686
_bWinWithSentReinf = LanchasterVictory(_fTotalAllyUnits, _fNumReinfEnemiesLeft,
2687
_fAllyCompoundKillRate, _fEnemyCompoundKillRate);
2689
// if we are going to lose even with reinforcements, see how many enemies will be left
2690
if(!_bWinWithSentReinf){
2691
_reinfLoseTime = LanchasterTimeToWin(_fNumReinfEnemiesLeft, _fTotalAllyUnits, _fEnemyCompoundKillRate, _fAllyCompoundKillRate);
2692
_fNumReinfEnemiesLeft = secondLanchasterLaw(_fNumReinfEnemiesLeft, _fTotalAllyUnits, _reinfLoseTime, _fEnemyCompoundKillRate, _fAllyCompoundKillRate);
2694
// calc how many reinf will be left
2695
_reinfWinTime = LanchasterTimeToWin(_fTotalAllyUnits, _fNumReinfEnemiesLeft, _fAllyCompoundKillRate, _fEnemyCompoundKillRate);
2696
_fNumReinfLeft = secondLanchasterLaw(_fTotalAllyUnits, _fNumReinfEnemiesLeft, _reinfWinTime, _fAllyCompoundKillRate, _fEnemyCompoundKillRate);
2699
else // sent reinf will arrive after attackers are killed
2701
// calc how many enemies will be left
2702
_fNumReinfEnemiesLeft = secondLanchasterLaw((float)_numEnemies,(float)_numAllies,_timeToLose,_enemyKillRate,_allyKillRate);
2703
_fNumReinfAttackersLeft = 0.0;
2705
// see if our reinfrcements will be able to win against remaining enemy troops, use corrected kill rates
2706
_bWinWithSentReinf = LanchasterVictory((float)_numReinfOnTheWay, _fNumReinfEnemiesLeft, _fReinfAvKillRate, _fReinfEnAvKillRate);
2708
// if we are going to lose even with reinforcements, see how many enemies will be left
2709
if(!_bWinWithSentReinf){
2710
_reinfLoseTime = LanchasterTimeToWin(_fNumReinfEnemiesLeft, (float)_numReinfOnTheWay, _fReinfEnAvKillRate, _fReinfAvKillRate);
2711
_fNumReinfEnemiesLeft = secondLanchasterLaw(_fNumReinfEnemiesLeft,(float)_numReinfOnTheWay,_reinfLoseTime,_fReinfEnAvKillRate,_fReinfAvKillRate);
2713
// calc how many reinf will be left
2714
_reinfWinTime = LanchasterTimeToWin((float)_numReinfOnTheWay,_fNumReinfEnemiesLeft, _fReinfAvKillRate, _fReinfEnAvKillRate);
2715
_fNumReinfLeft = secondLanchasterLaw((float)_numReinfOnTheWay,_fNumReinfEnemiesLeft,_reinfWinTime,_fReinfAvKillRate,_fReinfEnAvKillRate);
2722
// The longer the travel distance, the more units must be sent, 1 additional unit per 10 secs
2723
_minTravelingUnits = _travelTime / SECONDS_PER_DROID;
2725
// how many enemy reinforcements must arrive - we need additional firepower to counter them
2726
_predictedEnemyReinf = 1;
2728
// we should only send more units if we are going to lose
2730
_minSendUnits = _predictedEnemyReinf + _minTravelingUnits;
2731
}else if(!_bWin and _bWinWithSentReinf){
2732
_minSendUnits = _predictedEnemyReinf + _minTravelingUnits;
2733
}else{ // going to lose no matter what, send at least as many as they will have
2734
_minSendUnits = _predictedEnemyReinf +
2735
max(_minTravelingUnits, (int)_fNumReinfEnemiesLeft);
2738
//_minSendUnits = _predictedEnemyReinf + max(0, (int)_fNumEnemiesLeft - (int)_fNumAttackersLeft);
2740
// Take old reinforcements into account
2741
// TODO: need a better way to model this
2742
// if(_numReinfOnTheWay > 0)
2744
// _minSendUnits = _minSendUnits - (int)_fNumEffectiveReinf;
2747
// Make sure there is a min number of reinforcements available
2748
// if(_minSendUnits < _minTravelingUnits)
2750
// _minSendUnits = _minTravelingUnits;
2754
if(watchWindowDebug == WATCH_DEBUG_REINF)
2756
setDebugMenuEntry("time/min trav:" & _travelTime & "/" & _minTravelingUnits, 0);
2757
setDebugMenuEntry("# (left): " & _numAllies & "(" & _fNumAttackersLeft & ")/" & _numEnemies & "(" & _fNumEnemiesLeft & ")", 1);
2759
setDebugMenuEntry("hp:" & (int)_fFriendlyAvUnitStrength & " (" & _friendlyHP &
2760
") / " & (int)_fEnemyAvUnitStrength & " (" & _enemyHP & ")" , 2);
2762
setDebugMenuEntry("dam:" & _fFriendlyAvUnitFirepower & " (" &
2763
(int)_fFriendlyFirepower & ") / " & _fEnemyAvUnitFirepower &
2764
" (" & (int)_fEnemyFirepower & ")" , 3);
2766
setDebugMenuEntry("kill rate: " & _allyKillRate & " / " & _enemyKillRate , 4);
2768
setDebugMenuEntry("old r/time: " & _numReinfOnTheWay & "(" & _sentReinfTravelTime & ")" , 5);
2769
setDebugMenuEntry("o r kill rate: " & _fReinfAvKillRate & "/" & _fReinfEnAvKillRate, 6);
2770
setDebugMenuEntry("*min send*/avail: " & _minSendUnits & " (" & _numAvailable & ")", 7);
2773
setDebugMenuEntry("win in " & ((float)_timeToWin / (float)MINUTE) & " mins", 8);
2774
setDebugMenuEntry("left: " & _fNumAttackersLeft, 9);
2775
}else if(!_bWin and _bWinWithSentReinf){
2776
//will reinf arrive before al lattackers are lost?
2777
if(_sentReinfTravelTime < _timeToLose){
2778
setDebugMenuEntry("reinf win+:" & ((float)_timeToLose / (float)MINUTE) & "+" & ((float)_reinfWinTime / (float)MINUTE), 8);
2779
setDebugMenuEntry("left:" & _fNumReinfLeft & "+" & _fNumReinfAttackersLeft & "(" & _fAllyCompoundKillRate & "/" & _fEnemyCompoundKillRate & ")", 9);
2781
setDebugMenuEntry("reinf win-:" & ((float)_timeToLose / (float)MINUTE) & "+" & ((float)_reinfWinTime / (float)MINUTE), 8);
2782
setDebugMenuEntry("reinf left:" & _fNumReinfLeft & "(" & _fNumReinfEnemiesLeft & ")", 9);
2785
//will reinf arrive before al lattackers are lost?
2786
if(_sentReinfTravelTime < _timeToLose){
2787
setDebugMenuEntry("no chance+:" & ((float)(_timeToLose - _sentReinfTravelTime) / (float)MINUTE) & "+" & ((float)_reinfLoseTime / (float)MINUTE), 8);
2789
setDebugMenuEntry("no chance-:" & ((float)_timeToLose / (float)MINUTE) & "+" & ((float)_reinfLoseTime / (float)MINUTE), 8);
2791
setDebugMenuEntry("en left: " & _fNumReinfEnemiesLeft, 9);
2798
// make sure there will be any attackers left when reinforcements will arrive
2799
/* if(_fNumAttackersLeft <= 0.0)
2804
if(_numAvailable < _minSendUnits)
2811
/* _numAvailable = groupSizeCmds(defendGr,true,false,true) - numDefenders; //use less units
2812
if(_forHelping) //use more units if helping
2814
_numAvailable = groupSizeCmds(defendGr,true,false,true) -
2815
min(minDefenders, numDefenders); //leave only minimal number of derenders
2818
_minSendUnits = minReinforcements;
2821
// if we wait for more units ally can get killed
2822
_minSendUnits = min(MIN_HELPING_ALLY_REINF, minReinforcements);
2825
if((_numAvailable >= _minSendUnits) or
2826
((_numAvailable >= (_minSendUnits / 2)) and
2827
(groupSizeCmds(attackGr,true,false,true) >= (numAttackers / 2))) ) //enough reinf, or still many attackers and some reinf
2835
//----------------------------------------------------------
2837
//----------------------------------------------------------
2838
function void stopState()
2840
if(state == stAttacking)
2844
else if(defendingBase())
2846
stopDefendingBase();
2848
else if(defendingOil())
2852
else if(helpingAlly())
2856
else if(state == stJoiningForces)
2858
stopJoiningForces();
2860
else if(state == stTakingOil)
2864
else if(state == stCollecting)
2868
else if(state == stTransporting)
2870
stopTransportState();
2872
else if(state == stDrop)
2876
else if(state != stNone)
2878
MsgBox("stopState() - unknown state");
2882
function void cancelState()
2884
if(state == stAttacking)
2888
else if(state == stDefendingBase)
2890
cancelDefendingBase();
2892
else if(defendingOil())
2894
cancelDefendingOil();
2896
else if(state == stHelpingAlly)
2898
cancelAllyDefense();
2900
else if(state == stJoiningForces)
2902
cancelJoiningForces();
2904
else if(state == stTakingOil)
2908
else if(state == stCollecting)
2912
else if(state == stTransporting)
2914
cancelTransportState();
2916
else if(state == stDrop)
2920
else if(state != stNone)
2922
MsgBox("cancelState() - unknown state");
2926
function void endState()
2928
if(state == stAttacking)
2932
else if(state == stDefendingBase)
2936
else if(defendingOil())
2940
else if(state == stHelpingAlly)
2944
else if(state == stJoiningForces)
2948
else if(state == stTakingOil)
2952
else if(state == stTransporting)
2954
endTransportState();
2956
else if(state == stDrop)
2960
else if(state != stNone)
2962
MsgBox("endState() - unknown state");
2967
function void pauseState()
2969
if(state == stNone){exit;}
2971
/* only stAttacking is paused, otherwise just stop doing what we were doing */
2972
if(state != stAttacking)
2976
} //only stAttacking for now
2978
dbg("PAUSING CURRENT STATE!!!!!!!!!!!!!!!!!!", me);
2980
/* cancelState() will reset enemy and stat, so remember now */
2981
lastStateTemp = state;
2982
lastEnemyTemp = enemy;
2986
lastState = lastStateTemp;
2987
lastEnemy = lastEnemyTemp;
2990
function void resumeState()
2992
if(lastState == stAttacking)
2994
if((not allianceExistsBetween(lastEnemy ,me)) and knowBase[lastEnemy])
2996
dbg("Resuming attack: at enemy: " & lastEnemy, me);
2998
groupAddGroupCmd(defendGr, attackGr);
2999
groupAddGroupCmd(defendGr, sendAttackGr);
3001
setState(lastState);
3003
//HACK: resume with curBase[], actually must remember last attack x and y
3004
if(knowBase[lastEnemy])
3006
startEnemyBaseAttack(lastEnemy);
3007
requestStartAttack(lastEnemy, curBase[lastEnemy][0], curBase[lastEnemy][1]);
3016
function void erasePausedState()
3022
function int findAllyInTrouble()
3026
_temp4 = none; //ally in trouble
3027
while(_temp < multiPlayerMaxPlayers)
3029
if(ally[_temp] and (not dead[_temp]) and (allyState[_temp] == stDefendingBase))
3031
//if(knowBase[_temp])
3032
if(curHelpX[_temp] > 0) //have help location
3034
//_temp3 = distBetweenTwoPoints(baseX, baseY, curBase[_temp][0], curBase[_temp][1]);
3035
_temp3 = distBetweenTwoPoints(baseX, baseY, curHelpX[_temp], curHelpY[_temp]);
3036
if(_temp3 < _temp2) //this ally is closer
3049
//----------------------------------------------------------
3050
// stop defendingBase
3051
//----------------------------------------------------------
3052
function void stopDefendingBase()
3060
dbg("DEFEND: stopped", me);
3062
/* If we were doing something before defending, resume it */
3063
if(lastState != stNone)
3069
/* now that we are ok, check if can help our ally, if someone's in trouble */
3070
if(not _busy) //didn't resume state
3072
temp = totalWeapUnits();
3073
if(temp > minAllyHelpers)
3075
temp = findAllyInTrouble(); //see if any of our allies is in trouble
3078
notifyAllies(getPlayerName(temp) & ", coming now, hold on", false);
3082
startHelpAlly(temp,curHelpX[temp],curHelpY[temp]);
3087
/* Return to base if idle */
3091
resetSendForceCoords();
3097
if(random(2) == 0){notifyAllies("they suck", TRUE);}
3098
else{notifyAllies("bwuhaha", TRUE);}
3101
/* Check ally status */
3102
checkRequestStatus();
3105
function void cancelDefendingBase()
3107
erasePausedState(); //don't resume since cancelled
3113
resetSendForceCoords();
3115
dbg("DEFEND: cancelled defendingBase", me);
3118
function void endDefendingBase()
3120
deselectAllDroids();
3124
setPhase(phNone,NONE);
3127
counterEnemy = none;
3129
requestHelpTime = 0;
3131
/* reset notification stuff */
3132
bNotifiedReadyAttack = FALSE;
3133
notifyReadyAttackTime = 0;
3137
//----------------------------------------------------------
3139
//----------------------------------------------------------
3140
function void stopTakingOil()
3142
dbg("TAKE OIL: stopped", me);
3146
/* If we were doing something before helping ally, resume it */
3147
if(lastState != stNone)
3154
resetSendForceCoords();
3155
checkRequestStatus();
3159
function void cancelTakingOil()
3161
erasePausedState(); //don't resume since cancelled
3167
resetSendForceCoords();
3169
dbg("TAKE OIL: cancelled", me);
3172
function void endTakingOil()
3174
deselectAllDroids();
3178
setPhase(phNone, NONE);
3185
/* reset notification stuff */
3186
bNotifiedReadyAttack = FALSE;
3187
notifyReadyAttackTime = 0;
3190
//----------------------------------------------------------
3191
// stop defending oil
3192
//----------------------------------------------------------
3193
function void stopDefendingOil()
3195
dbg("DEFENDING OIL: stopped", me);
3199
/* If we were doing something before helping ally, resume it */
3200
if(lastState != stNone)
3207
resetSendForceCoords();
3208
checkRequestStatus();
3212
function void endDefendingOil()
3214
deselectAllDroids();
3218
setPhase(phNone, NONE);
3222
// reset coordinates of the attacked derrick
3223
resetOilDefendCoords();
3226
function void cancelDefendingOil()
3228
erasePausedState(); //don't resume since cancelled
3234
resetSendForceCoords();
3236
dbg("DEFENDING OIL: cancelled", me);
3239
//----------------------------------------------------------
3240
// stop joining forces
3241
//----------------------------------------------------------
3242
function void stopJoiningForces()
3244
dbg("JOINING FORCES: stopped", me);
3248
/* If we were doing something before defending, resume it */
3249
if(lastState != stNone)
3256
resetSendForceCoords();
3260
function void cancelJoiningForces()
3262
erasePausedState(); //don't resume since cancelled
3266
resetSendForceCoords();
3270
dbg("JOINING FORCES: cancelled", me);
3273
function void endJoiningForces()
3275
deselectAllDroids();
3279
setPhase(phNone, NONE);
3283
timeGuardPos = 0; //reset
3285
/* reset notification stuff */
3286
bNotifiedReadyAttack = FALSE;
3287
notifyReadyAttackTime = 0;
3290
//----------------------------------------------------------
3291
// stop ally defense
3292
//----------------------------------------------------------
3293
function void stopAllyDefense()
3297
dbg("stopped helping ally !!!!!!!!!!!!!!!!!!!!!!!!", me);
3299
/* If we were doing something before helping ally, resume it */
3300
if(lastState != stNone)
3308
resetSendForceCoords();
3312
function void cancelAllyDefense()
3314
erasePausedState(); //don't resume since cancelled
3320
resetSendForceCoords();
3322
dbg("ALLY DEFENSE: cancelled", me);
3325
function void endAllyDefense()
3327
deselectAllDroids();
3329
enemy = none; //allyInThreat
3333
/* reset notification stuff */
3334
bNotifiedReadyAttack = FALSE;
3335
notifyReadyAttackTime = 0;
3339
setPhase(phNone, NONE); //phRTB;
3342
//----------------------------------------------------------
3344
//----------------------------------------------------------
3345
function void stopAttack()
3349
dbg("ATTACK: stopped", me);
3351
/* If we were doing something before attacking, resume it */
3352
if(lastState != stNone)
3359
resetSendForceCoords();
3360
checkRequestStatus();
3364
function void cancelAttack()
3366
erasePausedState(); //don't resume since cancelled
3372
resetSendForceCoords();
3374
dbg("ATTACK: cancelled", me);
3377
function void endAttack()
3379
deselectAllDroids();
3385
setPhase(phNone, NONE); //phRTB
3387
reinfTime = 0; //timer
3389
countTakeOil = 0; //allow hunting oil again
3391
/* reset notification stuff */
3392
bNotifiedReadyAttack = FALSE;
3393
notifyReadyAttackTime = 0;
3395
numTakeOil = random(maxTakeOil); //allow attacking oil again
3398
function void resetSendForceCoords()
3400
updateStateCoord(NONE, NONE);
3403
//--------------------------------------
3405
//--------------------------------------
3406
function void stopTransportState()
3408
endTransportState(); //first end then load otherwise endTransportState will reset state
3410
setPhase(phTransportDone, NONE); //make sure drop state knows that transport finished successfully
3415
function void cancelTransportState()
3417
dbg("cancelTransportState", me);
3419
eraseLoadSavedState(); //since cancelled
3422
while(temp < maxTransporters)
3424
if(transporter[temp] != NULLOBJECT)
3426
//temp = isInMyBase(transporter[temp].x, transporter[temp].y);
3427
if((not transporterFlying(transporter[temp])) and isInMyBase(transporter[temp].x, transporter[temp].y)) //landed inside of the base
3429
dbg("unloading transporter", me);
3430
unloadTransporter(transporter[temp], transporter[temp].x, transporter[temp].y);
3432
else //Send to unload in the base
3434
dbg("ordering transporter to disembark in the base", me);
3435
orderTranspDisembark(transporter[temp], baseX, baseY); //make unload units in the base
3444
checkRequestStatus();
3446
deselectAllDroids();
3447
goRTB(); //only sends sendAttackGr home, not transportGr
3449
prepareTransporters(); //send transporters back to base
3451
endTransportState();
3453
resetSendForceCoords();
3455
enemy = none; //must be done here, since not done in endTransportState()
3458
function void endTransportState()
3460
dbg("endTransportState", me);
3462
groupAddGroupCmd(defendGr, transportGr); //return unloaded units to defenders or if state cancelled
3471
setPhase(phNone, NONE);
3476
//--------------------------------------
3478
//--------------------------------------
3479
function void stopDropState()
3482
dbg("DROP: stopped !!!", me);
3484
/* If we were doing something before dropping, resume it */
3485
if(lastState != stNone)
3491
/* we started the drop directly, not from a different state, so just start attacking the enemy */
3492
enemy = enemy; //shouldn't change
3495
//HACK resume with curBase[], since didn't save last attack x and y coords
3496
startEnemyBaseAttack(enemy);
3497
requestStartAttack(enemy, curBase[enemy][0], curBase[enemy][1]);
3502
function void cancelDropState()
3504
erasePausedState(); //don't resume since cancelled
3506
enemy = none; //should be cleard here?
3508
dropStartTime = none; //doesn't belong to endDropState()
3509
tSyncDrop = 0; //doesn't belong to endDropState()
3513
dbg("DROP: cancelled !!!", me);
3516
function void endDropState()
3520
setPhase(phNone, NONE);
3524
tempReinfCount[enemy] = 0; //start over
3528
//----------------------------------------------------------
3530
//----------------------------------------------------------
3531
function void stopCollecting()
3537
setPhase(phNone, NONE);
3542
dbg("COLLECT: stopped", me);
3545
function void cancelCollecting()
3550
function void setTechBranch()
3552
tech = 0; //random(numBranches); //FIXME
3555
function bool pendingLasSatStrike()
3557
local int _tempPlayer;
3560
while(_tempPlayer < 8)
3562
if(allianceExistsBetween(_tempPlayer, me))
3564
if(lasSatState[_tempPlayer] == lsWaitingReply) //someone requested lassat strike?
3569
_tempPlayer = _tempPlayer + 1;
3575
function void updateLasSat()
3577
local STRUCTURE _lasSatTarget;
3579
/* check if finished recharging lassat */
3580
if(lasSatState[me] == lsRecharging) //only recharge if we built lasSat already and are not recharged already (would reset waiting state)
3582
if(tLasSat >= tLasSatReady) //ready
3584
dbg("lassat ready**********************", me);
3585
lasSatState[me] = lsReady;
3589
if(lasSatState[me] == lsReady)
3591
if(pendingLasSatStrike())
3593
dbg("LASSAT: joining ****************", me);
3594
lasSatState[me] = lsRequesterWaitingRecharging; //join and tell that lassat is ready
3598
notifyAllies("let's lassat someone", TRUE);
3599
dbg("notified allies**********************", me);
3600
lasSatState[me] = lsWaitingReply; //wait to find out if anyone wants to join
3601
tLasSatCountdown = tLasSatReplyMax; //start countdown
3605
if(lasSatState[me] == lsWaitingReply)
3607
if(tLasSatCountdown <= 0) //waited enough for allies to reply to lassat request
3609
dbg("notified allies countdown: time is up********", me);
3610
lasSatState[me] = lsWaiting; //wait for allies to finish recharging lassat
3611
tLasSatCountdown = tLasSatWaitAlliesMax; //start wait for allies countdown
3615
// start 'someone requested lassat strike' code
3617
/* someone requested lassat and waiting for us to finish recharging lassat */
3618
if(lasSatState[me] == lsRequesterWaitingRecharging)
3620
/* check if finished recharging lassat */
3621
if(tLasSat >= tLasSatReady) //ready
3623
notifyAllies("lassat ready", FALSE); //tell them lassat is ready, so that requester can start the strike if everyone else is ready too
3624
lasSatState[me] = lsWaitingForRequester;
3625
tLasSatCountdown = tLasSatWaitAlliesMax; //wait for requester to start lassat strike
3629
/* we finished recharging our lassat and are now waiting for the requester to start the strike */
3630
if(lasSatState[me] == lsWaitingForRequester)
3632
/* check if we waited to long, if yes, start the attack on our own */
3633
if(tLasSatCountdown <= 0) //requester got killed? etc
3635
dbg("waited too long for the requester, firing*************", me);
3636
lasSatState[me] = lsFiring; //just fire, don't wait anymore
3640
// end 'someone requested lassat strike' code
3642
/* all allies ready to fire? */
3643
if(lasSatState[me] == lsWaiting)
3645
//tLasSatCountdown = off; //not needed anymore
3647
dbg("lsWaiting: waiting...********", me);
3648
if(allyLasSatReady() or (tLasSatCountdown <= 0)) //if everyone can fire or waited too long
3650
if(allyLasSatReady())
3652
dbg("lsWaiting: firing now0********", me);
3654
else if(tLasSatCountdown <= 0)
3656
dbg("lsWaiting: firing now1********", me);
3659
lasSatState[me] = lsFiring;
3663
/* everyone's ready or waited too long, fireing now! */
3665
if(lasSatState[me] == lsFiring)
3667
_lasSatTarget = findLasSatTarget(enemy);
3669
if(_lasSatTarget != NULLOBJECT)
3671
dbg("lsFiring: found target********", me);
3672
fireLasSat(_lasSatTarget);
3676
dbg("lsFiring: couldn't find target********", me);
3683
function void fireLasSat(STRUCTURE _targetStructure)
3685
//TODO: must select lasSat if debugging otherwise WZ wouldn't let fire if AI is played as selectedPlayer (human)
3686
//if(DEBUG_OBSERVE and (me == selectedPlayer))
3688
// selectStructure(_targetStructure, TRUE);
3691
skFireLassat(me, _targetStructure);
3692
notifyLassat(_targetStructure);
3694
resetLasSat(); //reset all counters etc
3695
lasSatState[me] = lsRecharging; //start recharging lassat (after resetLasSat() !)
3699
function void notifyLassat(STRUCTURE _targetStructure)
3701
notifyAllies("let's lassat " & getPlayerName(_targetStructure.player), TRUE); //tell allies who to lassat
3703
dropAllyBeacon("lassat " & getPlayerName(_targetStructure.player), _targetStructure.x, _targetStructure.y);
3706
function bool allyLasSatReady()
3708
local int _tempPlayer;
3710
/* did we wait too long for allies' lassat to finish recharging? */
3711
//if(tLasSatWaitAllies >= tLasSatWaitAlliesMax)
3716
/* find out if we are still waiting for someone's lassat to recharge */
3718
while(_tempPlayer < 8)
3720
if(allianceExistsBetween(_tempPlayer, me))
3722
if(lasSatState[_tempPlayer] == lsRequesterWaitingRecharging)
3723
//if((lasSatState[_tempPlayer] != lsRecharging) and (lasSatState[_tempPlayer] != lsWaitingForRequester))//ignore those who don't strike with us
3725
dbg("LASSAT: " & getPlayerName(_tempPlayer) & " not ready********", me);
3726
return FALSE; //someone is still recharging lassat or this is the first time we are checking and thex haven't enterd "lsRequesterWaitingRecharging" yet
3730
_tempPlayer = _tempPlayer + 1;
3736
function void resetLasSat()
3738
local int _tempPlayer;
3740
lasSatState[me] = lsNone;
3743
tLasSat = 0; //start recharging
3744
tLasSatCountdown = off; //reset the misc timer
3747
//while(_tempPlayer < 8)
3749
// lasSatState[_tempPlayer] = lsNone;
3750
// _tempPlayer = _tempPlayer + 1;
3754
function STRUCTURE findLasSatTarget(int _prefferedEnemy)
3756
local int _tempPlayer,_bestDist,_tempDist;
3757
local STRUCTURE _targetStruct,_tempStruct;
3759
_targetStruct = NULLOBJECT;
3761
if(_prefferedEnemy >= 0)
3763
_targetStruct = mostDamagedBaseStructure(_prefferedEnemy);
3766
/* check all other enemies */
3767
if(_targetStruct == NULLOBJECT)
3769
/* find closest target */
3772
while(_tempPlayer < 8)
3774
if((not allianceExistsBetween(_tempPlayer, me)) and (_tempPlayer != me))
3776
_tempStruct = mostDamagedBaseStructure(_tempPlayer);
3779
if(_tempStruct != NULLOBJECT)
3781
//dbg("mostDamagedBaseStructure(" & _tempPlayer & "): not NULL!! ", me);
3782
/* check if new one is closer */
3783
_tempDist = distBetweenTwoPoints(baseX, baseY, _tempStruct.x, _tempStruct.y);
3784
if(_tempDist < _bestDist)
3786
//dbg("findLasSatTarget: assigned struct********", me);
3787
_targetStruct = _tempStruct;
3788
_bestDist = _tempDist;
3793
// dbg("mostDamagedBaseStructure: NULL ", me);
3797
_tempPlayer = _tempPlayer + 1;
3801
return _targetStruct;
3804
function STRUCTURE mostDamagedBaseStructure(int _targetPlayer)
3806
local int _structTypeIndex,_lowestHP,_tempHP;
3807
local STRUCTURE _returnStruct,_tempStruct;
3809
_structTypeIndex = 0;
3811
_returnStruct = NULLOBJECT;
3813
while(_structTypeIndex < numBaseStructs)
3815
initEnumStruct(FALSE,baseStructs[_structTypeIndex],_targetPlayer,me);
3817
_tempStruct = enumStruct();
3818
while(_tempStruct != NULLOBJECT)
3820
_tempHP = _tempStruct.health;
3821
if(_tempHP < _lowestHP)
3823
_lowestHP = _tempHP;
3824
_returnStruct = _tempStruct;
3827
_tempStruct = enumStruct();
3830
_structTypeIndex = _structTypeIndex + 1;
3833
return _returnStruct;
3836
function int checkAllyThreat()
3838
//return value - player in danger
3842
if(state == stHelpingAlly){return(enemy);} //already defending
3845
while(count < multiPlayerMaxPlayers)
3849
if(knowBase[count]) //know where his base is?
3851
result = numEnemyWeapObjInRange(me, curBase[count][0], curBase[count][1], range, false, true);
3852
result2 = numFriendlyWeapObjInRange(me, curBase[count][0], curBase[count][1], range, false, true);
3854
if(result > result2)
3856
//if(enemy == none) //don't suddenly switch the player, only if not already set //allyInThreat
3858
dbg("ally " & count & " is in danger", me);
3859
//enemy = count; //allyInThreat
3860
//exit; //must exit here
3864
//else if(result < 4) //we have much more and they only < 4
3866
// if(mapRevealedInRange(curBase[count][0],curBase[count][1],(5 * 128),me)) //can judge if safe only if can see the base
3868
// if(allyInThreat == count) //same we were helping
3870
// dbg(" " & me & ") HELP ALLY: this player seems to be safe now");
3871
// allyInThreat = none; //can stop helping now
3872
// exit; //must exit here
3882
return(none); //nothing found
3885
function void startDefending(int _counterEnemy)
3887
if((state != stNone) and !defendingBase()) //units busy with something else
3889
dbg("BASE: we need our units in the base now, cancel current state", me);
3893
requestHelpTime = 0; //reset since started over
3895
setState(stDefendingBase);
3897
setPhase(phMoveToLoc, NONE);
3900
updateStateCoord(baseX,baseY);
3903
counterEnemy = _counterEnemy;
3905
dbg("DEFENDING: defend mode on (enemy = " & counterEnemy & ")", me);
3908
function void startHelpAlly(int _allyToHelp, int _helpx, int _helpy)
3910
enemy = _allyToHelp; //store it in the enemy var, since he invoked this state
3912
/* Calculate some place on the base edge (my base -> help dest), so won't block the inner of the base */
3913
updateStateCoord(baseX,baseY);
3915
circlePerimPoint(_helpx, _helpy, ref sendForceX, ref sendForceY, sendHelpRange);
3917
//sendForceX = _helpx; //curBase[enemy][0]; //allyInThreat
3918
//sendForceY = _helpy; //curBase[enemy][1]; //allyInThreat
3920
if((sendForceX <= 0) or (sendForceY <= 0))
3922
MsgBox("startHelpAlly() - sendForceX <= 0");
3926
setState(stHelpingAlly);
3928
setPhase(phMoveToLoc, NONE);
3930
helpTime = maxHelpTime; //limited time we can help this ally or can stuck forever
3932
/* Set minimum number of defenders to leave in the base */
3933
updateNumDefenders();
3935
dbg("helping " & getPlayerName(enemy) & " !!!!!!!!!!!!!!!!!!!!!!!!", me); //allyInThreat
3937
/* Add required number of units from defendGr to sendAttackGr */
3940
//selectGroup(sendAttackGr, TRUE);
3943
//ToDo: <check if enough attackers and send to the ally player base>
3944
//ToDo: <send message to ally>
3946
//orderGroupLoc(sendAttackGr, DORDER_SCOUT, curBase[enemy][0], curBase[enemy][1]); //allyInThreat
3949
function void manageHelpAlly()
3951
local bool _bFoundTarget;
3953
ASSERT(enemy >= 0, "manageHelpAlly: wrong ally index (" & enemy & ")", me);
3955
dbg("manageHelpAlly", me);
3960
ASSERT(FALSE,"manageHelpAlly() - no player set", me);
3964
if((sendForceX <= 0) or (sendForceY <= 0))
3966
notifyAllies(getPlayerName(enemy) & ", I can't see your base", false); //allyInThreat
3967
//notifyAllies(getPlayerName(enemy) & ", give vision" , false); //allyInThreat
3968
ASSERT(FALSE, "manageHelpAlly - (sendForceX <= 0) or (sendForceY <= 0)", me);
3972
//MsgBox("manageHelpAlly() - sendForceX not initialized");
3976
if(not knowBase[enemy]) //no visible structures left for this ally
3978
notifyAllies(getPlayerName(enemy) & ", I don't see your base" , false); //allyInThreat
3979
dbg("manageHelpAlly - not haveBase", me);
3985
//--------------------------------------
3987
//--------------------------------------
3988
if(phase == phAttackingLoc)
3990
/* Attack any ally's base intruders */
3991
defendArea(attackGr, sendHelpRange, sendForceX, sendForceY, defendCorridor, 1);
3995
//--------------------------------------------------------
3996
//Add required number of units from defendGr to attackGr
3997
//--------------------------------------------------------
3998
/* function void fillAttackers(bool _highPriorityTask)
4000
local int _numDefenders;
4001
//_highPriorityTask - if task is a high priority, then use more units
4003
//don't leave BBs in defend group
4006
_numDefenders = groupSizeCmds(defendGr,false,true) - numDefenders;
4007
if(_highPriorityTask)
4009
_numDefenders = groupSizeCmds(defendGr,false,true) - minDefenders; //leave less units in the base
4012
initIterateGroupCmd(defendGr,true,false,false);
4013
tempDroid = iterateGroupCmd(defendGr);
4014
while((tempDroid != NULLOBJECT) and (_numDefenders > 0)) //leave 'numDefenders' number of units in the defendGr
4016
groupAddDroid(sendAttackGr, tempDroid);
4017
_numDefenders = _numDefenders - 1;
4018
tempDroid = iterateGroupCmd(defendGr);
4021
selectGroup(sendAttackGr, TRUE);
4024
function void fillAttackers(int _numAttackers)
4027
local int _bucket,_numBBs;
4029
//don't leave BBs in defend group
4030
_numBBs = sortOutBBs();
4033
_numAttackers = _numAttackers - _numBBs;
4035
_bucket = initIterateGroupCmd(defendGr,true,false,true);
4036
_droid = iterateGroupCmd(defendGr, _bucket);
4037
while((_droid != NULLOBJECT) and (_numAttackers > 0))
4039
groupAddDroid(sendAttackGr, _droid);
4041
_droid = iterateGroupCmd(defendGr, _bucket);
4044
selectGroup(sendAttackGr, TRUE);
4047
function int numAttackersFromPriorty(bool _highPriorityTask)
4049
local int _numAttackers;
4052
if(_highPriorityTask)
4054
_numAttackers = groupSizeCmds(defendGr,true,false,true) - minDefenders; //leave less units in the base
4058
_numAttackers = groupSizeCmds(defendGr,true,false,true) - numDefenders;
4061
return _numAttackers;
4064
//--------------------------------------------------------
4065
//Add required number of units from defendGr to attackGr
4066
//--------------------------------------------------------
4067
function void fillReinforcements(bool _bHelping)
4069
dbg("MANAGE UNITS: sending reinforcements", me);
4071
//fillAttackers(numAttackersFromPriorty(_bHelping)); //reinforcements have high priority ONLY if defendig ally
4073
prepareAttackers(_bHelping);
4075
//Take care of statistic stuff
4076
if((state != stTakingOil) and !helpingAlly() and !defendingOil())
4078
reinfCount[enemy] = reinfCount[enemy] + 1;
4079
tempReinfCount[enemy] = tempReinfCount[enemy] + 1;
4082
if((state == stAttacking) or (state == stTakingOil))
4084
reinfTime = maxReinfTime; //restart "cancel attack" countdown
4088
function void fillHelpers()
4091
prepareAttackers(true);
4093
/* //don't leave BBs in defend group
4096
temp = groupSizeCmds(defendGr,true,false,true) - minDefenders; //send more units if sent not enough
4098
if((temp + groupSizeCmds(attackGr,true,false,true) + groupSizeCmds(sendAttackGr,true,false,true)) > (numDefenders * 3))
4100
temp = groupSizeCmds(defendGr,true,false,true) - numDefenders;
4103
initIterateGroupCmd(defendGr,true,true,false);
4104
tempDroid = iterateGroupCmd(defendGr);
4105
while((tempDroid != NULLOBJECT) and (temp > 0)) //leave 'numDefenders' number of units in the defendGr
4107
groupAddDroid(sendAttackGr, tempDroid);
4109
tempDroid = iterateGroupCmd(defendGr);
4112
selectGroup(sendAttackGr, TRUE);
4116
//---------------------------------------------------------
4117
// For all trucks with build orders, if there's a
4118
// closer idle truck, use it instead
4119
//---------------------------------------------------------
4120
function void closerTruck()
4124
initIterateGroupB(buildGr, 0);
4125
droid = iterateGroupB(buildGr, 0);
4126
while(droid != NULLOBJECT)
4128
//if((droid.action == DACTION_MOVETOBUILD) and (droid.stat != NULLSTAT)) //has a build order
4129
if(droid.action == DACTION_MOVETOBUILD)
4131
//pointless, if too close already
4132
result = distBetweenTwoPoints(droid.orderx, droid.ordery, droid.x, droid.y);
4133
if(result > range) //will build soon
4136
//now check if we have a droid closer to the build pos
4137
initIterateGroupB(buildGr, 1);
4138
droid2 = iterateGroupB(buildGr, 1);
4139
while(droid2 != NULLOBJECT)
4141
if((droid2.order == DORDER_NONE) or (droid2.order == DORDER_RTB))
4143
result2 = distBetweenTwoPoints(droid.orderx, droid.ordery, droid2.x, droid2.y);
4144
if((result - result2) > range) //the second one is much closer
4146
//build what first droid was going to build
4148
//dbg(" " & me & ") found a much closer droid at " & (droid.x / 128) & ", " & (droid.y / 128));
4149
orderDroidStatsLoc(droid2, DORDER_BUILD, droid.stat, droid.orderx, droid.ordery);
4150
orderDroid(droid, DORDER_RTB); //send back to base
4153
droid2 = iterateGroupB(buildGr, 1);
4158
droid = iterateGroupB(buildGr, 0);
4162
function STRUCTURE closestDerrick(int _x, int _y)
4164
local int _bestDist,_tempDist;
4165
local STRUCTURE _closestDerrick,_tempDerrick;
4169
_closestDerrick = NULLOBJECT;
4171
initEnumStruct(FALSE,derrick,me,me);
4172
_tempDerrick = enumStruct();
4173
while(_tempDerrick != NULLOBJECT)
4175
_tempDist = distBetweenTwoPoints(_tempDerrick.x, _tempDerrick.y, _x, _y);
4176
if(_tempDist < _bestDist) //already going to some derrick
4178
_closestDerrick = _tempDerrick;
4179
_bestDist = _tempDist;
4182
_tempDerrick = enumStruct();
4185
return _closestDerrick;
4188
function FEATURE closestOilResource(int _x, int _y)
4190
local int _bestDist,_tempDist;
4191
local FEATURE _closestOil,_tempOil;
4195
_closestOil = NULLOBJECT;
4197
// check oil resources
4198
initGetFeature(oilRes,me,me);
4199
_tempOil = getFeatureB(me);
4200
while(_tempOil != NULLOBJECT)
4202
_tempDist = distBetweenTwoPoints(_tempOil.x, _tempOil.y, _x, _y);
4203
if(_tempDist < _bestDist) //already going to some derrick
4205
_tempOil = _tempOil;
4206
_bestDist = _tempDist;
4208
_tempOil = getFeatureB(me);
4214
function int findBestDefense()
4216
//return - defense index
4217
/* find best defense */
4220
while(_temp < numDef)
4222
if(isStructureAvailable(def[_temp],me))
4224
_temp2 = _temp; //Best defense
4232
//---------------------------------------------------------
4233
// Build oil defenses
4234
//---------------------------------------------------------
4235
event buildNormalOilDefenses(inactive)
4237
if(defendingBase()){exit;}
4239
if(idleGroupCmd(buildGr,true,false) == 0){exit;}
4241
/* find best defense */
4242
best = findBestDefense();
4244
if(best == none){exit;}
4246
/* make sure not too many trucks are busy with defenses */
4247
result = numBuildingNoBaseDefenses();
4249
if(result >= maxOilDefenseTrucks)
4254
/* set number of defenses allowed */
4256
// count = minOilDef;
4257
// if(playerPower(me) >= highPower)
4259
// count = maxOilDef;
4263
/* find undefended derrick */
4264
initEnumStruct(FALSE,derrick,me,me);
4265
structure = enumStruct();
4266
while(structure != NULLOBJECT)
4268
/* check if this derrick has a defense location stored */
4269
result = getOilDefendLocIndex(me, structure.x, structure.y);
4271
if((result < 0) or (not bLearn)) //no defense loc stored for this derrick
4273
/* check if too many defenses around already */
4274
result = numFriendlyWeapStructsInRange(me, structure.x, structure.y, RANGE_ALL_OIL_DEFENSES, false);
4277
/* make sure derrick is not in the base */
4278
//result = isInMyBase(structure.x, structure.y);
4280
if(!isInMyBase(structure.x, structure.y))
4282
/* is anyone already on the way to build something nearby? */
4283
//result =buildingSiteBlocked(NULLOBJECT, range, structure.x, structure.y);
4285
if(!buildingSiteBlocked(NULLOBJECT, RANGE_ALL_OIL_DEFENSES, structure.x, structure.y, true)) //anyone going to do ANYTHIN Gon that spot?
4287
/* build the normal way */
4288
dbg("building oil defense the normal way at " & (structure.x / 128) & " - " & (structure.y / 128), me);
4290
buildOnMap(def[best], structure.x, structure.y, 1);
4296
structure = enumStruct();
4300
/* Build a single defense for a single derrick */
4301
function bool buildDerrickDefence(STRUCTURE _derrick, DROID _truck)
4303
local int _bestDefIndex,_numFreandlyDefenses,
4304
_oilDefLocIndex,_oilRecallPrior,_x,_y,_buildX,_buildY;
4305
//--------------------------------------------------------
4306
//Check if derrick has at least min num of defenses nearby
4307
//--------------------------------------------------------
4309
/* find _bestDefIndex defense */
4310
_bestDefIndex = findBestDefense();
4312
if(_bestDefIndex == none){
4316
/* make sure derrick is not in the base */
4317
//result = isInMyBase(_derrick.x, _derrick.y);
4319
if(!DEFEND_BASE_DERRICKS and isInMyBase(_derrick.x, _derrick.y)){ //in base, so exit
4323
/* is anyone already on the way to build something nearby? */
4324
//result = buildingSiteBlocked(_truck, oilDefensesRange, _derrick.x, _derrick.y);
4326
if(buildingSiteBlocked(_truck, RANGE_ALL_OIL_DEFENSES, _derrick.x, _derrick.y, true)){ //yes
4327
return false; //someone will build something here (probably a defence, so exit)
4331
/* check if too many defenses around already */
4332
_numFreandlyDefenses = numFriendlyWeapStructsInRange(me, _derrick.x, _derrick.y, RANGE_ALL_OIL_DEFENSES, false);
4334
/* make sure not too many trucks are busy with defenses */
4335
//result = numBuildingNoBaseDefenses();
4337
//if((result >= maxOilDefenseTrucks) and (_numFreandlyDefenses >= 1))
4338
if(_numFreandlyDefenses >= numOilDef)
4340
return false; //has basic defense, so exit
4345
// check if this derrick has a defense location stored
4346
_oilDefLocIndex = getOilDefendLocIndex(me, _derrick.x, _derrick.y);
4348
if(_oilDefLocIndex >= 0) //we have a defense loc stored for this derrick
4350
/* check if priority is high enough */
4351
if(recallOilDefendLoc(me, _oilDefLocIndex, ref _x, ref _y, ref _oilRecallPrior)) //get priority
4353
if(_oilRecallPrior >= minOilRecallPrior) //prior high enough
4355
circlePerimPoint(_derrick.x, _derrick.y, ref _x, ref _y, DEFENSE_DIST_FROM_OIL);
4357
if(pickStructLocation(def[_bestDefIndex], ref _x, ref _y, me))
4359
orderDroidStatsLoc(_truck, DORDER_BUILD, def[_bestDefIndex], _x, _y);
4367
if(_numFreandlyDefenses >= numOilDef){
4368
return false; //already has a basic defence, so exit
4371
/* this derrick doesn't have a defense loc, build the normal way */
4372
_buildX = _derrick.x;
4373
_buildY = _derrick.y;
4375
if(pickStructLocation(def[_bestDefIndex], ref _buildX, ref _buildY, me))
4377
orderDroidStatsLoc(_truck, DORDER_BUILD, def[_bestDefIndex], _buildX, _buildY);
4384
event defendOil(inactive)
4386
local int _numDefensesToBuild,_maxDefRange,_totalOil;
4387
local STRUCTURE _closestDerrick;
4388
local DROID _nullTruck;
4390
if(not bLearn){exit;}
4392
if(defendingBase()){exit;}
4394
if(idleGroupCmd(buildGr,true,false) == 0){exit;} //no trucks
4396
/* make sure not too many trucks are busy with defenses */
4397
result = numBuildingNoBaseDefenses();
4399
if(result >= maxOilDefenseTrucks)
4407
while(count < numDef)
4409
result2 = numStatBusy(def[count], TRUE); //How many trucks are busy with defenses
4410
result = result + result2;
4415
/* find best defense */
4416
best = findBestDefense();
4418
if(best == none){exit;} //no defenses available
4420
if(result > maxOilDefenseTrucks){exit;} //too many busy
4424
//Go through remembered oil defense locations
4425
//------------------------------------------------
4426
count2 = getOilDefendLocCount();
4430
while((count < count2) and (count4 < MAX_OIL_DEFENSES_SIDES)) //pick max 3 locs
4432
if(recallOilDefendLoc(me, count, ref x, ref y, ref result)) //if this one stored
4434
if(result >= minOilRecallPrior) //at least priority of 3
4436
//find oil derrick which is supposed to be defended (closest one)
4437
//---------------------------------------------------------------
4438
_closestDerrick = closestDerrick(x, y);
4440
if(_closestDerrick != NULLOBJECT) //found anything?
4442
buildX = _closestDerrick.x;
4443
buildY = _closestDerrick.y;
4445
//make sure derrick is not in the base
4446
//result = isInMyBase(buildX, buildY);
4448
if(!isInMyBase(buildX, buildY)) //not in base
4450
//move coords closer to derrick perimeter
4451
circlePerimPoint(_closestDerrick.x, _closestDerrick.y, ref x, ref y, DEFENSE_DIST_FROM_OIL); //move locations to the derrick perimeter
4453
// count how many oil resources we are going to defend
4454
_totalOil = numTotalOilInRange(_closestDerrick.x, _closestDerrick.y, (TILE * 3));
4456
//decide how many defenses we want to build depending on total number of oil resource we have to guard
4457
_numDefensesToBuild = max(numOilDef, numOilDef + (_totalOil - 1) * (numOilDef / 2));
4459
//count if not too many built on this site already (using corrected coords!)
4460
if(numStructsByTypeInRange(me, me, REF_DEFENSE, buildX, buildY, oilDefensesRange) < _numDefensesToBuild) //max
4462
buildX = x; //remember coords before using pickStructLocation() to check if corrected coords too far away
4466
if(pickStructLocation(def[best], ref buildX, ref buildY, me))
4468
//Make sure not too many building already
4469
//--------------------------------------------
4470
retInt = numTrucksOrderInRange(buildX, buildY, RANGE_ALL_OIL_DEFENSES, DORDER_BUILD);
4472
if(retInt < MAX_TRUCKS_PER_OIL_DEFENSE) //max 1
4474
//don't allow to build outside of the range
4475
_maxDefRange = max( oilDefensesRange, oilDefensesRange + (TILE * (_totalOil - 1)) );
4476
if(distBetweenTwoPoints(buildX, buildY, x, y) < _maxDefRange) //coords corrected with pickStructLocation() not too far away from orig
4479
intOK[count4] = count;
4481
count4 = count4 + 1; //picked another one
4495
if(count4 == 0){exit;} //couldn't find anything
4497
//Now choose a random location from the picked ones
4498
//-------------------------------------------------
4499
result = intOK[random(count4 - 1)];
4501
// now recall defend location and build defenses
4502
bDummy = buildOilDefenseFromExperience(result, _nullTruck);
4505
function bool buildOilDefenseFromExperience(int _index, DROID _truck)
4507
local int _prior,_defx,_defy;
4508
local STRUCTURE _closestDerrick;
4510
recallOilDefendLoc(me, _index, ref _defx, ref _defy, ref _prior);
4512
//find oil derrick which is supposed to be defended (closest one)
4513
//---------------------------------------------------------------
4514
_closestDerrick = closestDerrick(_defx, _defy);
4516
if(_closestDerrick == NULLOBJECT) //found anything?
4518
dbg("defendOil() - couldn't find closest derrick !!!!!!!!!!!!!!!!", me);
4523
bDummy = buildOilDefense(_defx, _defy, _closestDerrick.x, _closestDerrick.y, _truck);
4528
function bool buildOilDefense(int _buildX, int _buildY, int _oilx,
4529
int _oily, DROID _truck)
4531
local STRUCTURE _closestDerrick;
4532
local int _x,_y,_closestDist,_bucket,_dist,_dist2;
4533
local bool _bFound,_bResult2;
4534
local DROID _droid2,_droid3;
4536
//find oil derrick which is supposed to be defended (closest one)
4537
//---------------------------------------------------------------
4538
// _closestDerrick = closestDerrick(_oilx, _oily);
4540
// if(_closestDerrick != NULLOBJECT) //found anything?
4542
// buildX = _closestDerrick.x;
4543
// buildY = _closestDerrick.y;
4547
// dbg("buildOilDefense() - couldn't find closest derrick !!!!!!!!!!!!!!!!", me);
4551
//move locations to the base perimeter
4552
circlePerimPoint(_oilx, _oily, ref _buildX, ref _buildY, DEFENSE_DIST_FROM_OIL);
4555
//if(structure2 == NULLOBJECT){exit;} //no derrick found
4557
if(_truck == NULLOBJECT)
4559
//Now find the closest truck
4560
//---------------------------------------------
4561
_closestDist = 99999;
4562
_bFound = FALSE; //found any?
4564
_droid2 = NULLOBJECT;
4565
_droid3 = NULLOBJECT;
4569
_bucket = initIterateGroupCmd(buildGr,true,false,true);
4570
_truck = iterateGroupCmd(buildGr,_bucket);
4571
while(_truck != NULLOBJECT)
4573
_dist2 = distBetweenTwoPoints(_truck.x, _truck.y, _buildX, _buildY);
4575
if(_dist2 < _closestDist) //closer
4577
if(droidOrderIdle(_truck))
4579
_droid2 = _truck; //totally idle
4580
_closestDist = _dist2;
4583
//if busy, check if it's worth to make this _truck build an oil defense instead
4584
else if((_truck.order == DORDER_BUILD) and (_truck.action == DACTION_MOVETOBUILD))
4586
_bResult2 = TRUE; //can take this truck
4587
if(_truck.stat == derrick)
4589
_bResult2 = FALSE; //don't touch him, probably going far
4593
initEnumStruct(FALSE,derrick,me,me);
4594
structure = enumStruct();
4595
while((structure != NULLOBJECT) and (_bResult2))
4597
//skip derricks in the base
4598
//result3 = isInMyBase(structure.x, structure.y);
4599
if(!isInMyBase(structure.x, structure.y)) //not in base
4601
if(distBetweenTwoPoints(_truck.orderx, _truck.ordery, structure.x, structure.y) < oilDefensesRange) //already going to some derrick
4603
_bResult2 = FALSE; //don't touch this truck, going far already
4607
structure = enumStruct();
4611
if(_bResult2) //safe to 'kidnap' this busy truck
4613
_droid3 = _truck; //remember this one too
4614
_closestDist = _dist2;
4619
_truck = iterateGroupCmd(buildGr,_bucket);
4628
dbg("buildOilDefense() - no idle trucks (MUST BE SOME!)", me);
4632
//decide which _truck to take
4633
//-----------------------------------------
4634
_truck = _droid2; //default
4635
if((_droid2 != NULLOBJECT) and (_droid3 != NULLOBJECT)) //which of 2?
4637
//only if busy one is much closer, otherwise let him do his job since he's busy
4638
_dist = distBetweenTwoPoints(_droid2.x, _droid2.y, _buildX, _buildY);
4639
_dist2 = distBetweenTwoPoints(_droid3.x, _droid3.y, _buildX, _buildY);
4641
if((_dist - _dist2) > (TILE * 12)) //busy one is much closer
4646
else if(_droid3 != NULLOBJECT)
4652
if(_truck == NULLOBJECT)
4658
if(pickStructLocation(def[best], ref _buildX, ref _buildY, me))
4660
orderDroidStatsLoc(_truck, DORDER_BUILD, def[best], _buildX, _buildY);
4664
//buildOnMap(def[best], _x, _y, 1);
4670
//take over enemy derricks
4671
function STRUCTURE findEnemyDerrick(int _targetPlayer)
4673
local int _numAttackers,_numEnemies;
4674
local STRUCTURE _enemyDerrick;
4676
//find enemy derrick
4677
_enemyDerrick = findBestEnemyDerrick(_targetPlayer, numAvailableAttackers(),
4681
if(_enemyDerrick == NULLOBJECT){
4682
return _enemyDerrick;
4685
//_enemyDerrick = retStruct;
4687
dbg("findEnemyDerrick() - found derrick", me);
4689
//see if we can deal with this many defenses
4690
_numAttackers = numAvailableAttackers();
4691
_numEnemies = numEnemyWeapObjInRange(me, _enemyDerrick.x, _enemyDerrick.y, (8 * 128), false, true);
4693
if(_numAttackers < (_numEnemies + 1))
4695
_enemyDerrick = NULLOBJECT; //clear
4696
dbg("TAKE OIL: not enough attackers for this oil", me);
4697
return _enemyDerrick; //too many enemies around
4700
dbg("findEnemyDerrick()- safe", me);
4702
//enemy = _enemyDerrick.player;
4704
//sendForceX = _enemyDerrick.x;
4705
//sendForceY = _enemyDerrick.y;
4707
return _enemyDerrick;
4710
//find closest enemy derrick with litte defense
4711
function STRUCTURE findBestEnemyDerrick(int _targetPlayer, int _numAttackers,
4712
int _centerx, int _centery, int _maxRange)
4714
local int _numEnemies,_enemy,_x,_y,_dist,_dist2,_dist3;
4715
retStruct = NULLOBJECT;
4717
tempResult2 = 99999; //best weight
4720
while(_enemy < multiPlayerMaxPlayers)
4722
if( ((_targetPlayer == none) and (_enemy != me) and
4723
(not allianceExistsBetween(_enemy, me))) //target player not set
4724
or ((_targetPlayer != none) and (_enemy == _targetPlayer)) ) //target player set
4726
initEnumStruct(false,derrick,_enemy,me);
4727
tempStruct = enumStruct();
4728
while(tempStruct != NULLOBJECT)
4730
// make sure oil derrick is in set range
4731
if( (_maxRange <= 0) or
4732
(distBetweenTwoPoints(tempStruct.x, tempStruct.y,
4733
_centerx, _centery) < _maxRange) )
4738
//don't choose if near an enemy base, since might have units nearby, which we don't see
4739
//temp4 = isNearEnemyBase(x, y);
4741
if(not isNearEnemyBase(_x, _y))
4743
//make sure not too well defended
4744
_numEnemies = numEnemyWeapObjInRange(me, _x, _y, (8 * 128), true, true); //check VTOLs too
4745
if(_numEnemies < _numAttackers) //this one has less defenses than the amount of units we will use for attack
4747
_dist = distBetweenTwoPoints(_x, _y, _centerx, _centery) / 128; // my base-derrick distance
4749
//enemy-derrick distance
4750
_dist2 = (_dist / 2) / 128; //if don't know enemy base location
4751
if(knowBase[_enemy])
4753
_dist2 = distBetweenTwoPoints(_x, _y, curBase[_enemy][0], curBase[_enemy][1]) / 128;
4756
_dist3 = distBetweenTwoPoints(_centerx, _centery, curBase[_enemy][0], curBase[_enemy][1]) / 128; //my base-enemy base
4759
//criticalAngle = 45 / dist3 / baseRange;
4760
//temp4 = degree(_centerx, _centery, x, y, curBase[temp][0], curBase[temp][1]); //base-derrick-enemyBase angle, the bigger the safer
4761
//if(temp4 > 180){temp4 = 360 - temp4;}
4763
//if(not((temp4 < criticalAngle) and ((dist - baseRange) > dist3))) //make sure not behind the enemy base
4765
//tempResult = (temp2 * defWeight) + dist - dist2 - temp4; //calculate weight of the derrick
4767
//calculate weight for this derrick (threat)
4768
tempResult = oilWeight(_enemy, _x, _y, _centerx, _centery);
4770
if(tempResult < tempResult2)
4772
tempResult2 = tempResult;
4773
retStruct = tempStruct;
4781
tempStruct = enumStruct();
4784
_enemy = _enemy + 1;
4790
function int oilWeight(int _owner, int _oilx, int _oily, int _centerx, int _centery)
4794
_range = TILE * 12; //must be same as in posWeight()
4796
retInt = posWeight(_owner, _oilx, _oily, _range, _centerx, _centery);
4798
retInt = retInt - 250 * numFeatByTypeInRange(me, 4, _oilx, _oily, _range); //4 = FEAT_OIL_RESOURCE
4805
function int posWeight(int _owner, int _x, int _y, int _range,
4806
int _centerx, int _centery)
4808
_result = 0; //threat
4809
_temp2 = 100; //more integer precision
4812
_dist = distBetweenTwoPoints(_centerx, _centery, _x, _y) / 128;
4818
_temp3 = numStructsByTypeInRange(me, me, REF_RESOURCE_EXTRACTOR, _x, _y, _range);
4823
//my weight //*_temp2 for precision
4824
_dist = (-1) * (weightDistFactor * _temp2) / (_dist / _temp3);
4826
_temp3 = (_dist / _temp2);
4827
//dbg("my weight = " & _temp3, me);
4830
_dist2 = 0; //if dead, no threat
4832
//check object enemy
4833
if(_owner != none) //not always need one
4835
if((not dead[_owner]) and (not killedBase[_owner]))
4837
_dist2 = _dist; //neutralize if enemy base loc unknown
4838
if(knowBase[_owner])
4840
_dist2 = distBetweenTwoPoints(curBase[_owner][0], curBase[_owner][1], _x, _y) / 128;
4841
//dbg("_dist2 = " & _dist2, me);
4842
_dist2 = (weightDistFactor * _temp2) / _dist2;
4847
_temp3 = (_dist2 / _temp2);
4848
//dbg("his weight = " & _temp3, me);
4851
_result = (_dist2 + _dist);
4853
_temp3 = (_result / _temp2);
4854
//dbg("_result = " & _temp3, me);
4856
//check allies and all enemies
4858
while(_temp < multiPlayerMaxPlayers)
4860
if((_temp != me) and (_temp != _owner))
4864
if(not allianceExistsBetween(_temp ,me))
4869
if(knowBase[_temp] and canSeePlayerBase(_temp)) //seeBase[] - otherwise this player might have been destroyed already or not loaded at all
4871
_dist2 = distBetweenTwoPoints(curBase[_temp][0], curBase[_temp][1], _x, _y) / 128;
4872
if(_dist2 == 0){_dist2 = 1;}
4874
_result = _result + (_temp3 * (weightDistFactor / 4 * _temp2)) / _dist2; //weightDistFactor / 2 => allies and other enemies have less weight //was /4
4880
_result = _result / _temp2;
4882
//dbg("ally _result = " & _result, me);
4884
//also check enemy defenses nearby
4885
_temp3 = numEnemyWeapObjInRange(me, _x, _y, (_range + TILE * 2), true, true); //also check VTOLs
4887
//dbg("num defenses = " & _temp3, me);
4889
_result = _result + _temp3;
4891
//also take into account possible ally and my objects nearby
4892
_temp3 = numFriendlyWeapObjInRange(me, _x, _y, (_range + TILE * 2), true, true); //also check VTOLs
4893
_result = _result - _temp3;
4898
//---------------------------------------------------------
4899
// Check if point is in base
4900
//---------------------------------------------------------
4901
function bool isInMyBase(int _checkX, int _checkY)
4903
if(distBetweenTwoPoints(_checkX, _checkY, baseX, baseY) > (baseRange + defendCorridor)) //not in the base
4911
//---------------------------------------------------------
4912
// Check if point is near anyone's base
4913
//---------------------------------------------------------
4914
function bool isNearAnyBase(int _x, int _y)
4916
_range = (25 * 128);
4919
while(_temp < multiPlayerMaxPlayers)
4921
if(knowBase[_temp] and canSeePlayerBase(_temp)) //seeBase[] - otherwise this player might have been destroyed already or not loaded at all
4923
if(distBetweenTwoPoints(curBase[_temp][0], curBase[_temp][1], _x, _y) < _range)
4934
function bool isNearEnemyBase(int _x, int _y)
4936
local int _enemy,_range;
4938
_range = (TILE * 25);
4941
while(_enemy < multiPlayerMaxPlayers)
4943
if(not allianceExistsBetween(_enemy ,me))
4945
if(!dead[_enemy] and knowBase[_enemy] and canSeePlayerBase(_enemy)) //seeBase[] - otherwise this player might have been destroyed already or not loaded at all
4947
if(distBetweenTwoPoints(curBase[_enemy][0], curBase[_enemy][1], _x, _y) < _range)
4953
_enemy = _enemy + 1;
4959
//---------------------------------------------------------
4960
// Returns TRUE if a base structures (not defense etc)
4961
//---------------------------------------------------------
4962
function bool isBaseStruct(STRUCTURE _checkStruct)
4964
if(_checkStruct == NULLOBJECT)
4966
MsgBox("isBaseSTruct - _checkStruct is NULLOBJECT");
4971
while(temp < numBaseStructs)
4973
if(_checkStruct.stat == baseStructs[temp])
4983
//---------------------------------------------------------
4985
//---------------------------------------------------------
4986
function void buildOil(bool _bInBaseOnly)
4989
local int _numBuildingOil;
4991
//dbg(" " & me & ") Executing buildOil()");
4993
//How many trucks already working on derricks
4994
_numBuildingOil = numStatBusy(derrick, true); //How many trucks are busy with derricks
4998
//dbg(" " & me & ") right now building " & _numBuildingOil & " oil resoirces");
5000
if(_numBuildingOil < maxBuildOilTrucks) //Not too many
5003
_oil = findBestOilToBuildOn(baseX, baseY, baseRange); //Look near the base
5005
_oil = findBestOilToBuildOn(baseX, baseY, -1); //Normal way
5008
if(_oil != NULLOBJECT)
5010
//dbg(" " & me & ") found unoccupied oil resource");
5012
bDummy = buildUsingClosestTruck(derrick, _oil.x, _oil.y, 1); //Can skip "buildOnMap" for oil
5016
//dbg(" " & me & ") End buildOil()");
5019
/* Build oil near some location */
5020
function bool buildNextOil(DROID _truck, int _maxRange, bool _bClosestOil)
5022
local int _oilDist,_bestDist,_bucket,_oilRange;
5023
local bool _bCanBuild;
5024
local FEATURE _oil,_bestOil;
5025
local DROID _otherTruck;
5028
_bestOil = NULLOBJECT; //Not found right now
5030
_oilRange = _maxRange; //max range to look for further oil
5031
_bCanBuild = false; //can we build using callback truck?
5035
initGetFeature(oilRes,me,me);
5036
_oil = getFeature(me);
5037
while(_oil != NULLOBJECT)
5039
_oilDist = distBetweenTwoPoints(_truck.x, _truck.y, _oil.x, _oil.y);
5040
if(_oilDist < _oilRange) //oil very near
5042
if(_oilDist < _bestDist) //closest one
5044
if(!buildingSiteBlocked(_truck, _maxRange, _oil.x, _oil.y, true))
5046
//make sure not dangerous
5047
if(!threatInRange(me, _oil.x, _oil.y, threatRange, false))
5049
_bestDist = _oilDist;
5050
_bestOil = _oil; //Remember and return it
5054
dbg("dangerous to build more oil", me);
5059
dbg("oil blocked", me);
5063
_oil = getFeature(me);
5068
// if not looking for the best oil, just find the closest possible
5069
_bestOil = findBestOilToBuildOn(_truck.x, _truck.y, _maxRange);
5072
//now check if any other trucks were sent to build there already
5073
if(_bestOil != NULLOBJECT) //found oil
5077
_bucket = initIterateGroupCmd(buildGr,true,false,true);
5078
_otherTruck = iterateGroupCmd(buildGr,_bucket);
5079
while(_otherTruck != NULLOBJECT)
5081
if((_otherTruck.orderx == _bestOil.x) and (_otherTruck.ordery == _bestOil.y))
5083
_bCanBuild = false; //someone already going to build
5085
//check if it's closer than callback _truck
5086
if(distBetweenTwoPoints(_otherTruck.x, _otherTruck.y, _bestOil.x, _bestOil.y) > _bestDist)
5088
//dbg(" " & me & ") CALLBACK truck - sending other _truck back to base", me);
5089
orderDroid(_otherTruck, DORDER_RTB); //send back to base
5090
_bCanBuild = true; //(assuming AI only sends 1 truck at each oil !!!)
5093
_otherTruck = iterateGroupCmd(buildGr,_bucket);
5097
if(_bCanBuild) //safe to build with callback _truck
5099
//dbg(" " & me & ") CALLBACK truck - building derrick with CALLBACK truck (" & _bestOil.x & "-" & _bestOil.y & ")", me);
5100
orderDroidStatsLoc(_truck, DORDER_BUILD, derrick, _bestOil.x, _bestOil.y);
5101
return true; //exit here
5107
//-----------------------------------------------------
5108
//Build ArgStrStat0 (passes STRUCTURESTAT) somewhere
5109
//-----------------------------------------------------
5110
function void buildOnMap(STRUCTURESTAT _statToBuild, int _buildX, int _buildY, int _maxTrucks)
5112
bTempResult = pickStructLocation(_statToBuild, ref _buildX, ref _buildY, me);
5115
bDummy = buildUsingClosestTruck(_statToBuild, _buildX, _buildY, _maxTrucks); //can re-use all arguments
5119
function FEATURE findBestOilToBuildOn(int _lookx, int _looky, int _maxRange)
5121
local FEATURE _oil,_tempOil;
5122
local int _bestWeight,_tempWeight;
5124
//dbg(" " & me & ") Executing findBestOilToBuildOn()");
5126
_oil = NULLOBJECT; //Not found right now
5127
_bestWeight = 99999;
5129
initGetFeature(oilRes,me,me);
5130
_tempOil = getFeature(me);
5131
while(_tempOil != NULLOBJECT)
5133
//_tempWeight = distBetweenTwoPoints(temp3, temp4, _tempOil.x, _tempOil.y);
5134
//if(_tempWeight < _bestWeight)
5136
//make sure not dangerous
5137
if(not threatInRange(me, _tempOil.x, _tempOil.y, threatRange, false))
5139
//Any trucks already were sent to build there?
5140
//temp5 = buildingSiteBlocked(NULLOBJECT, (5 * 128), _tempOil.x, _tempOil.y); //anyone going there already?
5142
if(not buildingSiteBlocked(NULLOBJECT, (TILE * 5), _tempOil.x, _tempOil.y, true)) //No one going there
5144
//make sure close enough to provided position
5145
if(not ((_maxRange > 0) and
5146
(distBetweenTwoPoints(_lookx, _looky, _tempOil.x, _tempOil.y) < _maxRange)))
5148
_tempWeight = oilWeight(none, _tempOil.x, _tempOil.y,
5151
if(_tempWeight < _bestWeight)
5153
_bestWeight = _tempWeight;
5154
_oil = _tempOil; //Remember it
5160
_tempOil = getFeature(me);
5165
//dbg(" " & me & ") End findBestOilToBuildOn()");
5168
function bool needTrucks()
5170
local int _totalTrucks,_numHaveTrucks;
5172
// we always need at least minTrucks
5173
if( !gettingMinTrucks() ){
5177
_numHaveTrucks = groupSizeCmds(buildGr,true,false,true);
5179
_totalTrucks = numBuildersInProduction(me) + _numHaveTrucks;
5181
if((idleGroupCmd(buildGr,true,false) == 0) and (_totalTrucks < MAX_BUILDERS)){
5188
if(_totalTrucks >= maxTrucks)
5193
if(_totalTrucks < minTrucks)
5198
// need trucks if we have more than minTrucks and almost all of them are busy
5199
if((_totalTrucks >= minTrucks) and (idleGroupCmd(buildGr,true,false) < 2))
5207
function void buildTrucks()
5209
local int _numBuilding,_haveTrucks,_tmplIndex,_totalTrucks,
5211
local STRUCTURE _factory;
5212
local bool _bFoundTemplate,_bStartedBuilding;
5214
_haveTrucks = groupSizeCmds(buildGr,true,false,true);
5216
_numBuilding = numBuildersInProduction(me); //How many builders are being built at the moment
5218
_totalTrucks = _haveTrucks + _numBuilding;
5220
if(_totalTrucks >= MAX_BUILDERS){
5221
dbg("HAVE TOO MANY TRUCKS", me);
5225
_maxBuiltMinTrucks = 2;
5226
if(defendingBase()){
5227
_maxBuiltMinTrucks = 1;
5230
initEnumStruct(FALSE,fac,me,me);
5231
_factory = enumStruct();
5232
while( (_factory != NULLOBJECT) and
5233
((_numBuilding == 0) or // max 1 at a time, if have more than minTrucks, use only 1 fac for trucks
5234
(!gettingMinTrucks() and (_numBuilding < _maxBuiltMinTrucks)) ) ) //But keep building until we have min number (max _maxBuiltMinTrucks at a time)
5236
if(structureComplete(_factory))
5238
if(structureIdle(_factory))
5240
// find best availabe truck template for this factory
5241
_tmplIndex = numTruckTmpl - 1;
5242
_bFoundTemplate = false;
5243
while(!_bFoundTemplate and (_tmplIndex >= 0))
5245
if(skCanBuildTemplate(me,_factory, truck[_tmplIndex]))
5247
tmplOK[0] = truck[_tmplIndex];
5248
_bFoundTemplate = true;
5256
buildDroid(tmplOK[0], _factory, me, 1);
5262
_factory = enumStruct();
5265
// Build cyborg engineers if we are still low on trucks
5266
initEnumStruct(false,cybfac,me,me);
5267
_factory = enumStruct();
5268
while((_factory != NULLOBJECT) and
5269
( !gettingMinTrucks() or // very low on trucks
5270
(needTrucks() and legoPhase() )) ) // at the beginning we need asap trucks to get oil
5272
if(structureComplete(_factory))
5274
if(structureIdle(_factory))
5276
//Try to build an engineer
5277
if( skCanBuildTemplate(me,_factory, cybEngineer) ) //make sure we have researched cyb engineer
5279
buildDroid(cybEngineer, _factory, me, 1);
5285
_factory = enumStruct();
5289
function void checkPowerGen()
5291
local bool _bStartedBuilding;
5292
//dbg(" " & me & ") Executing checkPowerGen()");
5294
_bStartedBuilding = FALSE;
5296
if(not structureLimitReached(powGen, me))
5298
result = getNumStructures(derrick, me);
5299
result = result + numStatBusy(derrick, FALSE); //"Think ahead"
5301
result2 = getNumStructures(powGen,me);
5303
if((result2 * 4) < result) //not enough pow gens
5305
count = (((result+3)/4) - result2); //How many power gens are missing
5307
//dbg(" " & me & ") num gens to build: " & count);
5311
_bStartedBuilding = buildInBase(powGen, 1); //Build power gen in the base (can re-use argument ArgStrStat0)
5313
if(_bStartedBuilding){
5316
count = -1; //break loop
5322
//dbg(" " & me & ") End checkPowerGen()");
5325
function void upgradePow()
5327
local int _numUpgrading;
5328
local STRUCTURE _structure;
5330
if(idleGroupCmd(buildGr,true,false) == 0){exit;}
5333
initEnumStruct(FALSE,powGen,me,me);
5334
_structure = enumStruct();
5335
while(_structure != NULLOBJECT)
5337
if(isStructureAvailable(powMod,me) and (not testStructureModule(me, _structure, 0)))
5339
//result = buildingSiteBlocked(NULLOBJECT, 128, _structure.x, _structure.y);
5341
if(numBuildSameBuilding(powMod, _structure.x, _structure.y) <= MAX_POWGEN_UPGRADE_TRUCKS) //Make sure not too many upgrading
5343
_numUpgrading = numStatBusy(powMod, true); //How many trucks are busy with facMod
5345
if(_numUpgrading == 0) //Make sure not too many trucks are doing the same thing at a time
5347
buildOnMap(powMod, _structure.x, _structure.y, MAX_POWGEN_UPGRADE_TRUCKS);
5351
_structure = enumStruct();
5355
function void upgradeFac()
5357
local int _numUpgrading;
5358
local STRUCTURE _structure;
5359
local bool _bLetFinishProduction;
5361
if(idleGroupCmd(buildGr,true,false) == 0){exit;}
5363
initEnumStruct(FALSE,fac,me,me);
5364
_structure = enumStruct();
5365
while(_structure != NULLOBJECT)
5367
if(isStructureAvailable(facMod,me) and (skGetFactoryCapacity(_structure) < 2 ))
5369
//result = buildingSiteBlocked(NULLOBJECT, 128, _structure.x, _structure.y);
5371
// if this is a startup phase and we are low on scouts and fac is building a tank, let it finish
5372
_bLetFinishProduction = false;
5373
if(!structureIdle(_structure) and needStartupScouts())
5375
// see if this tank can be used as a scout (and probably will be)
5376
_bLetFinishProduction = isTankTemplate(factoryGetTemplate(_structure));
5379
if(!_bLetFinishProduction)
5381
if(numBuildSameBuilding(facMod, _structure.x, _structure.y) <= MAX_FACTORY_UPGRADE_TRUCKS) //Make sure not too many upgrading
5383
_numUpgrading = numStatBusy(facMod, TRUE); //How many trucks are busy with facMod
5385
if(_numUpgrading <= (MAX_FACTORY_UPGRADE_TRUCKS + 1)) //Make sure not too many trucks are doing the same thing at a time
5387
buildOnMap(facMod, _structure.x, _structure.y, MAX_FACTORY_UPGRADE_TRUCKS);
5392
_structure = enumStruct();
5396
function void upgradeVtolFac()
5398
local int _numUpgrading;
5399
local STRUCTURE _structure;
5401
if(idleGroupCmd(buildGr,true,false) == 0){exit;}
5404
initEnumStruct(FALSE,vtolfac,me,me);
5405
_structure = enumStruct();
5406
while(_structure != NULLOBJECT)
5408
if(isStructureAvailable(facMod,me) and (skGetFactoryCapacity(_structure) < 2))
5410
//result = buildingSiteBlocked(NULLOBJECT, 128, _structure.x, _structure.y);
5412
if(not buildingSiteBlocked(NULLOBJECT, 128, _structure.x, _structure.y, false))
5414
_numUpgrading = numStatBusy(facMod, TRUE); //How many trucks are busy with resMod
5416
if(_numUpgrading <= 1) //Max 2 at a time
5418
buildOnMap(facMod, _structure.x, _structure.y, 1);
5422
_structure = enumStruct();
5426
function void upgradeResFac()
5428
local int _numUpgrading;
5429
local STRUCTURE _structure;
5431
//dbg(" " & me & ") Executing doUpgrades()");
5433
if(idleGroupCmd(buildGr,true,false) == 0){exit;}
5436
initEnumStruct(FALSE,resFac,me,me);
5437
_structure = enumStruct();
5438
while(_structure != NULLOBJECT)
5440
if(isStructureAvailable(resMod,me) and (not testStructureModule(me, _structure, 0)))
5442
//result = buildingSiteBlocked(NULLOBJECT, 128, _structure.x, _structure.y);
5444
if(not buildingSiteBlocked(NULLOBJECT, 128, _structure.x, _structure.y, false))
5446
_numUpgrading = numStatBusy(resMod, TRUE); //How many trucks are busy with resMod
5448
if(_numUpgrading <= 1) //Max 2 at a time
5450
buildOnMap(resMod, _structure.x, _structure.y, 1);
5454
_structure = enumStruct();
5457
//dbg(" " & me & ") End doUpgrades()");
5460
function void deselectAllDroids()
5462
//Iterate through all player droids
5463
InitEnumDroids(me,me);
5464
tempDroid = EnumDroid();
5465
while(tempDroid != NULLOBJECT)
5467
selectDroid(tempDroid, FALSE);
5468
tempDroid = EnumDroid();
5472
/* Calculate how many research facilities need to start researching */
5473
function int calcNeededRes()
5475
local int _missingDefendersCost,
5476
_availableAttackersCost,_minAttackersCost,
5477
_stateCost,_tStateUrgencyTimeout,_researchActivityCost;
5478
local int _needRes,_availableAttackers,_minAttackers;
5479
local float _fNeedRes,_fNeedResInPower,_topicCost,_tankCost,_fMinResCost,_fPlayerPow,
5482
/* decide how many research facilities we want to use */
5483
_needRes = maxResearch;
5486
* NOTE: toPow(x / a, power) - means: parabola depends on x. Parabola's f(x) will have 1 at 'a',
5487
* ie 'a' is like a threshold, which makes toPow() kick-in (output f(x) > 0) only after 'a', having no effect for x < a.
5490
_topicCost = 400.0; //Approximate cost of a single research topic
5491
_tankCost = _topicCost;
5492
_missingDefendersCost = max(0, minDefenders - groupSizeCmds(defendGr,true,false,true)) * (int)_tankCost; //can't be negative, don't care if have more than needed
5494
_availableAttackers = numAvailableAttackers();
5495
_minAttackers = minAttackers;
5496
_availableAttackersCost = _availableAttackers * (int)_tankCost;
5497
_minAttackersCost = _minAttackers * (int)_tankCost;
5499
// don't allow to idle too long
5500
_researchActivityCost = (int)(toPow((fmin(fCurResUrgency, 7000.0) / fMaxResHold), 3.0)
5501
* _topicCost); //+1 res at fMaxResHold
5504
_tStateUrgencyTimeout = (int)fMaxResHold; //MINUTE * 10;
5505
/* 10 mins - when to add at least 1 res, in secs, can't put research on hold forever while defendingBase or helping ally
5506
shouldn't lose urgency way too fast, should still put enough power into what we are doing now - flat function*/
5507
if(defendingBase() or (state == stHelpingAlly)) {
5508
//ASSERT(tState != 0, "doResearch: tState == 0", me);
5509
_stateCost = max(0, (int)_topicCost * max((_tStateUrgencyTimeout / max(tState, 1) - 1), 0)); //f(x) is +inf at the beginnign of the state, 0 at _tStateUrgencyTimeout, '-' after _tStateUrgencyTimeout
5512
/* Temporary calculations in power currency */
5513
/* numRes = (fMinResearch * _topicCost) //Try to keep minimum number of res facs working
5514
+ playerPower(me) //use each 400 power for 1 additional research topic
5515
- _missingDefendersCost //Save some power if we don't have enough defenders
5516
+ toPow(_availableAttackersCost / _minAttackersCost, 2) //Research more if we have alot of attackers already, +1 res at _minAttackersCost
5517
+ _researchActivityCost //Take into account how actively we have been researching in the last tResUrgencyTrackInterval seconds
5519
- enemyAttackers; */ //Do less research if enemy is about to invade with a huge force
5521
_fMinResCost = _topicCost * fMinResearch;
5522
_fPlayerPow = (float)playerPower(me);
5523
_fMissingDefCost = (float)_missingDefendersCost;
5525
_fNeedResInPower = (_fMinResCost + _fPlayerPow -
5527
(float)((int)toPow((float)_availableAttackers / (float)max(_minAttackers, 1), 2.0) * (int)_tankCost) +
5528
(float)(_researchActivityCost - _stateCost)); // - enemyAttackers;
5530
/* Convert from power currency into number of research facilities needed to put to work */
5531
_needRes = (int)(_fNeedResInPower / _topicCost);
5532
_fNeedRes = (_fNeedResInPower / _topicCost);
5534
// round to the nearest integer
5535
if((_fNeedRes - (float)(int)_fNeedRes) > 0.5){
5539
// don't do more than fMinResearch reserahces if defendingBase the base
5540
if(defendingBase() and (playerPower(me) < highPower)){
5541
_needRes = min(0, _needRes);
5545
_needRes = min((int)fMinResearch, _needRes);
5548
/* Update debug menu */
5549
if(watchWindowDebug == WATCH_DEBUG_RESEARCH)
5551
setDebugMenuEntry("need res: " & _needRes & " (" & _fNeedResInPower & ") " & fNumDefaultResearch, 0);
5552
setDebugMenuEntry("resUrgency : " & fCurResUrgency & " (" & _researchActivityCost & ")" , 1);
5553
setDebugMenuEntry("-defenders: " & _missingDefendersCost, 2);
5554
setDebugMenuEntry("attackers: " & _availableAttackers & " (" & toPow((float)_availableAttackers / (float)max(_minAttackers,1), 2.0) & ")", 3);
5556
setDebugMenuEntry("maxOilScouts: " & maxOilScouts, 5);
5557
setDebugMenuEntry("addScout: " & addScout, 6);
5558
setDebugMenuEntry("numEnemyScouts: " & numEnemyScouts, 7);
5559
setDebugMenuEntry("fMapRevealFactor: " & fMapRevealFactor, 9);
5562
/* numRes = fMinResearch //Try to keep minimum number of res facs working
5563
+ (power / _topicCost) //use each 400 power for 1 additional research topic
5564
- ( _numMissingDefenders / (_topicCost / _tankCost) ) //Save some power if we don't have enough defenders
5565
+ toPow(numAvailableAttackers / minAttackers, 2) //Research more if we have alot of attackers already, +1 res at minAttackers
5566
+ toPow(fCurResUrgency / fMaxResHold, 5); //+1 res at fMaxResHold */
5571
/* Put all research facilities to work, done at startup */
5572
event startAllResearch(inactive)
5574
// start research facilities
5578
event doResearchEv(inactive)
5583
function void doResearchAll()
5585
local STRUCTURE _resFac;
5586
local int _needRes,_resIndex,_numResearching;
5589
/* find out how many research facilities are busy */
5590
_numResearching = numBusyByType(resFac);
5592
if(_numResearching > 0){
5593
tLastResearch = 0; //reset, since we are not idle
5596
/* Calculate how many research facilities should be researching */
5597
_needRes = calcNeededRes();
5599
/* see if we already have enough research facilities busy */
5600
if(_numResearching >= _needRes){
5604
_resIndex = none; //research index
5607
/* Put research facilities to work */
5608
initEnumStruct(FALSE,resFac,me,me);
5609
_resFac = enumStruct();
5611
while((_resFac != NULLOBJECT) and (_numResearching < _needRes)) //not too many working
5614
_resIndex = doResearch(_resFac, _resIndex);
5619
_numResearching++; //one more working
5620
tLastResearch = 0; //reset, since we are not idle now
5623
_resFac = enumStruct();
5629
event startNewResearch(inactive)
5631
local STRUCTURE _resFac;
5632
local int _needRes,_resIndex,_numResearching;
5634
// structure can be null sometimes
5635
if(structure == NULLOBJECT){
5639
ASSERT(structureIdle(structure), "startNewResearch: Res fac is not idle", me);
5641
/* find out how many research facilities are busy */
5642
_numResearching = numBusyByType(resFac);
5644
if(_numResearching > 0){
5645
tLastResearch = 0; //reset, since we are not idle
5648
/* Calculate how many research facilities should be researching */
5649
_needRes = calcNeededRes();
5651
/* see if we already have enough research facilities busy */
5652
if(_numResearching >= _needRes){
5656
_resIndex = none; //research index
5658
// start researching next research topic with this idle res fac
5659
_resIndex = doResearch(structure,_resIndex);
5662
function int doResearch(STRUCTURE _resFac, int _resIndex)
5664
local bool _bStarted;
5667
/* current tech tree */
5668
_tech = 0; //default tank tech //TODO: fix
5670
_tech = tech; //use whatever we selected as our new preference
5673
if(structureIdle(_resFac))
5676
if(structureComplete(_resFac))
5678
_bStarted = FALSE; //this res lab idle for now
5680
/* check if need unit transporter ASAP */
5682
if((state == stDrop) and (not researchFinished(resUnitTransporter, me)))
5684
_bStarted = pursueResearch(_resFac,me,resUnitTransporter);
5688
dbg("getting transporter tech", me);
5693
/* do normal research */
5694
while(not _bStarted)
5697
_resIndex = findResearch(_resIndex + 1, _tech);
5699
if(_resIndex > none) //found research
5702
_bStarted = pursueResearch(_resFac,me,research[_tech][_resIndex]);
5706
// _numResearching++; //one more working
5707
// tLastResearch = 0; //reset, since we are not idle now
5712
_bStarted = TRUE; //make loop end, no research found
5726
function int findResearch(int _searchStart, int _techTree)
5728
ASSERT(_searchStart >= 0, "findResearch: _searchStart < 0", me);
5729
ASSERT(_techTree >= 0, "findResearch: _techTree < 0", me);
5731
retInt = _searchStart;
5732
while(retInt < numRes[_techTree])
5734
if((not researchFinished(research[_techTree][retInt], me)) and (not researchStarted(research[_techTree][retInt], me)))
5736
return(retInt); //found research
5738
retInt = retInt + 1;
5741
retInt = none; //not found
5745
//--------------------------------------------------------
5746
//Number of busy structures by type
5747
//--------------------------------------------------------
5748
function int numBusyByType(STRUCTURESTAT _busyStructType)
5751
local STRUCTURE _structure;
5753
initEnumStruct(FALSE,_busyStructType,me,me);
5754
_structure = enumStruct();
5756
while(_structure != NULLOBJECT)
5758
if(not structureIdle(_structure))
5762
_structure = enumStruct();
5768
//--------------------------------------------------------
5769
//For how many structures of given type there's a pending
5770
//build (truck is on the way to build or already building)
5771
//--------------------------------------------------------
5772
function int numStatBusy(STRUCTURESTAT _structureToCheck, bool _bExcludeAlreadyBuilding)
5774
local int _numStatBusy,_bucket;
5775
local DROID _bTruck;
5779
_bucket = initIterateGroupCmd(buildGr,true,false,true);
5780
_bTruck = iterateGroupCmd(buildGr,_bucket);
5781
while(_bTruck != NULLOBJECT)
5783
if(_bTruck.order == DORDER_BUILD)
5785
if(not (_bExcludeAlreadyBuilding and _bTruck.action == DACTION_BUILD))
5787
if(_bTruck.stat == _structureToCheck) //going to build it
5793
_bTruck = iterateGroupCmd(buildGr,_bucket);
5796
return _numStatBusy;
5799
//--------------------------------------------------------
5800
//Total number of trucks are have started building
5801
//something (not just going to the building site)
5802
//--------------------------------------------------------
5803
function int numTrucksBuilding()
5808
_bucket = initIterateGroupCmd(buildGr,true,false,true);
5809
tempDroid = iterateGroupCmd(buildGr,_bucket);
5810
while(tempDroid != NULLOBJECT)
5812
if((tempDroid.order == DORDER_BUILD) and (tempDroid.action != DACTION_MOVETOBUILD)) //Started building
5814
retInt = retInt + 1;
5816
tempDroid = iterateGroupCmd(buildGr,_bucket);
5822
//---------------------------------------------------------
5823
//Returns number of trucks that are on the way to
5824
//build a certain structure type (not building yet)
5825
//---------------------------------------------------------
5826
function int numStatMoveBusy(STRUCTURESTAT _structStatToCheck)
5828
local int _bucket,_numBusy;
5832
_bucket = initIterateGroupCmd(buildGr,true,false,true);
5833
_truck = iterateGroupCmd(buildGr,_bucket);
5834
while(_truck != NULLOBJECT)
5836
if((_truck.order == DORDER_BUILD) and (_truck.action == DACTION_MOVETOBUILD)) //Not reached the building site yet
5838
if(_truck.stat == _structStatToCheck) //going to build it
5840
_numBusy = _numBusy + 1;
5843
_truck = iterateGroupCmd(buildGr,_bucket);
5849
//-----------------------------------------------------
5850
function bool buildInBase(STRUCTURESTAT _statToBuild, int _maxTrucks)
5852
local bool _bStartedBuilding;
5854
_bStartedBuilding = FALSE;
5856
//dbg(" " & me & ") Executing buildInBase()");
5859
temp2 = baseX + (random(temp) - (temp/2)); //Randomize a bit
5860
temp3 = baseY + (random(temp) - (temp/2));
5862
if(pickStructLocation(_statToBuild, ref temp2, ref temp3, me))
5864
_bStartedBuilding = buildUsingClosestTruck(_statToBuild, temp2, temp3, _maxTrucks); //can re-use ArgStrStat0
5867
//dbg(" " & me & ") End buildInBase()");
5869
return _bStartedBuilding;
5872
//-----------------------------------------------------
5873
//Build a structure with the closest truck
5874
//-----------------------------------------------------
5875
function bool buildUsingClosestTruck(STRUCTURESTAT _statToBuild, int _buildX, int _buildY, int _maxTrucks) //Building coords and STRUCTURESTAT are passed
5877
local int _numTrucks;
5878
local bool _bHaveMoreTrucks;
5881
//dbg(" " & me & ") Executing buildUsingClosestTruck()");
5884
_bHaveMoreTrucks = TRUE;
5885
while((_numTrucks < _maxTrucks) and _bHaveMoreTrucks)
5887
_bHaveMoreTrucks = FALSE;
5889
_truck = closestIdleTruck(_buildX, _buildY);
5890
if(_truck != NULLOBJECT)
5892
_bHaveMoreTrucks = TRUE;
5893
orderDroidStatsLoc(_truck, DORDER_BUILD, _statToBuild, _buildX, _buildY);
5895
//dbg(" " & me & ") End buildUsingClosestTruck()");
5900
//dbg(" " & me & ") End buildUsingClosestTruck()");
5902
return (_numTrucks > 0);
5905
//-----------------------------------------------------
5906
//Build factories and research facilities dynamically
5907
//-----------------------------------------------------
5908
function void buildBaseStructs()
5910
local int _maxResFac,_numResFac,_maxFacs,_numFacs,_buildX,_buildY,
5912
local bool _bStartedBuild,_bNeedFac,_bNeedResFac,_bResult;
5914
if(idleGroupCmd(buildGr,true,false) == 0)
5919
_buildX = baseX + random(_range) - (_range / 2);
5920
_buildY = baseY + random(_range) - (_range / 2);
5922
_maxFacs = getStructureLimit(fac, me);
5923
_maxResFac = getStructureLimit(resFac, me);
5925
// num already built plus num pending
5926
_numFacs = getNumStructures(fac,me) + numStatMoveBusy(fac);
5927
_numResFac = getNumStructures(resFac,me) + numStatMoveBusy(resFac);
5929
/* limit num of facs when critical power or low on defenders */
5932
_maxFacs = min(minFacs, _maxFacs); //limit facs,
5933
_maxResFac = min(minResFacs, _maxResFac); //limit res fac
5936
/*check if limit reached */
5937
_bNeedFac = ((not structureLimitReached(fac, me)) and (_numFacs < _maxFacs)); //bool = available //limit not reahced and not more than allowed at the moment
5938
_bNeedResFac = ((not structureLimitReached(resFac, me)) and (_numResFac < _maxResFac));
5940
dbg("max facs/res facs: " & _maxFacs & "/" & _maxResFac & ", need: " &
5941
_bNeedFac & "/" & _bNeedResFac, me);
5943
_bStartedBuild = FALSE;
5946
if(getStructure(HQ, me) == NULLOBJECT) //not built and no one's on the way to build
5948
//Check if someone's already on the way to build HQ
5949
_result3 = numStatBusy(HQ, TRUE);
5951
if(_result3 == 0) //no one's on the way to build
5953
bDummy = buildInBase(HQ, 1);
5957
/* see if we need VTOL factories */
5958
if( ((state == stDrop) or (playerPower(me) > highPower)) and
5959
(groupSizeCmds(defendGr,true,false,true) >= numDefenders)) //don't waste time, since transporter tech becomes available only after vtol fac is built
5961
if((_numFacs > 0) and (_numResFac > 0) and isStructureAvailable(vtolfac, me))
5963
//if(numResearchLeft(me, resUnitTransporter) <= 6) //don't bother if still to far away from being able to build transporter
5965
if(getNumStructures(vtolfac, me) < min(0, getStructureLimit(vtolfac, me))) //don't try to build more than allowed
5967
//Check if someone's already on the way to build VTOL fac
5968
_result3 = numStatBusy(vtolfac, TRUE);
5970
if(_result3 == 0) //no one's on the way to build
5972
bDummy = buildInBase(vtolfac, 2);
5973
dbg("Building VTOL Factory", me);
5981
//if((not _bNeedFac) and (not _bNeedResFac)){exit;}
5985
/* build factories and research facilities */
5986
if(_bNeedFac and // need facs
5987
(!_bNeedResFac or (_numFacs <= _numResFac) or (_numResFac >= 3) or
5988
(_bNeedResFac and (_numResFac * 2 > _numFacs)) or
5989
((_numFacs < minFacs) and (_numResFac >= 1)) ) ) //The only avail left or not enough or (less than min and have at least 1 res)
5991
//How many trucks are on the way to build factories
5992
_result3 = numStatMoveBusy(fac); //How many builds are in pending (not in progress already!)
5994
//dbg(" " & me & ") buildBaseStructs() - factory - have: " & _numFacs & " pending: " & _result3);
5996
if((_numFacs + _result3) < _maxFacs) //Will not max out
5998
_bResult = pickStructLocation(fac, ref _buildX, ref _buildY, me);
5999
if(_bResult == TRUE)
6001
//Anyone already wants to build something else on this spot?
6002
//_result3 = buildingSiteBlocked(NULLOBJECT, 128, _buildX, _buildY);
6004
if(not buildingSiteBlocked(NULLOBJECT, 128, _buildX, _buildY, false))
6006
_bResult = buildUsingClosestTruck(fac, _buildX, _buildY, 2); //Building coords and STRUCTURESTAT are passed
6010
_bStartedBuild = TRUE; //Build successfull
6015
dbg("buildBaseStructs() - factory someone's building (!!!!!!!!!!)", me);
6026
if(!_bStartedBuild and _bNeedResFac) //Factory unavailable (didn't start build it) and Rec fac available
6028
//dbg(" " & me & ") buildBaseStructs() - must build res fac (*)");
6030
//How many trucks are on the way to build res fac
6031
_result3 = numStatMoveBusy(resFac); //How many builds are in progress or pending
6033
if((_result3 + _numResFac) < min(_maxResFac, maxResearch)) //Will not max out, or don't build more than required (maxResearch)
6035
dbg("Building res fac", me);
6037
_bResult = pickStructLocation(resFac, ref _buildX, ref _buildY, me);
6038
if(_bResult == TRUE)
6040
//Anyone already wants to build something else on this spot?
6041
//_result3 = buildingSiteBlocked(NULLOBJECT, 128, _buildX, _buildY);
6043
if(not buildingSiteBlocked(NULLOBJECT, 128, _buildX, _buildY, false))
6045
bDummy = buildUsingClosestTruck(resFac, _buildX, _buildY, 1); //Building coords and STRUCTURESTAT are passed
6051
/* build uplink center */
6052
if(getNumStructures(uplink,me) >= 1){exit;}
6053
if(not isStructureAvailable(uplink, me)){exit;}
6055
if((_numFacs < 1) or (_numResFac < 1)){exit;} //no facs, no research
6057
//How many trucks are on the way to build uplink
6058
_result3 = numStatMoveBusy(uplink); //How many builds are in progress or pending
6060
if(_result3 > 0){exit;}
6062
_buildX = baseX + random(_range) - (_range / 2);
6063
_buildY = baseY + random(_range) - (_range / 2);
6065
_bResult = pickStructLocation(uplink, ref _buildX, ref _buildY, me);
6066
if(_bResult == TRUE)
6068
//Anyone already wants to build something else on this spot?
6069
//_result3 = buildingSiteBlocked(NULLOBJECT, 128, _buildX, _buildY);
6071
if(not buildingSiteBlocked(NULLOBJECT, 128, _buildX, _buildY, false))
6073
bDummy = buildUsingClosestTruck(uplink, _buildX, _buildY, 1); //Building coords and STRUCTURESTAT are passed
6078
//dbg(" " & me & ") End buildBaseStructs()");
6081
//---------------------------------------------------------
6082
// Find droids without a group
6083
//---------------------------------------------------------
6084
function void unassignedDroids(GROUP defendersGr, GROUP buildersGr)
6088
//Iterate through all player droids
6089
InitEnumDroids(me,me);
6090
tempDroid = EnumDroid();
6091
while(tempDroid != NULLOBJECT)
6093
if(not hasGroup(tempDroid))
6095
if(tempDroid.droidType == DROID_CONSTRUCT)
6097
groupAddDroid(buildersGr, tempDroid);
6102
if((tempDroid.droidType != DROID_TRANSPORTER) and
6103
(tempDroid.droidType != DROID_COMMAND))
6105
groupAddDroid(defendersGr, tempDroid);
6110
tempDroid = EnumDroid();
6113
dbg("found " & _temp & " unassigned droids", me);
6116
//---------------------------------------------------------------
6117
//Returns how many droids are already on the way to build the
6118
//same structure on the same spot (like helpbuild)
6119
//---------------------------------------------------------------
6120
function int numBuildSameBuilding(STRUCTURESTAT _checkStat, int _x, int _y)
6126
_bucket = initIterateGroupCmd(buildGr,true,false,true);
6127
tempDroid = iterateGroupCmd(buildGr,_bucket);
6128
while(tempDroid != NULLOBJECT)
6130
if(tempDroid.order == DORDER_BUILD)
6132
if(tempDroid.stat == _checkStat) //Same struct type
6135
if(distBetweenTwoPoints(_x, _y, tempDroid.orderx , tempDroid.ordery) <= 128)
6137
retInt = retInt + 1;
6141
tempDroid = iterateGroupCmd(buildGr,_bucket);
6147
function int numTrucksSameOrder(int _orderIndex)
6153
_bucket = initIterateGroupCmd(buildGr,true,false,true);
6154
tempDroid = iterateGroupCmd(buildGr,_bucket);
6155
while(tempDroid != NULLOBJECT)
6157
if(tempDroid.order == _orderIndex) //right order type
6159
retInt = retInt + 1;
6161
tempDroid = iterateGroupCmd(buildGr,_bucket);
6168
//---------------------------------------------------------------
6169
//Returns how many trucks have order in a range
6170
//---------------------------------------------------------------
6171
function int numTrucksOrderInRange(int _rangex, int _rangey, int _range, int _order)
6178
_bucket = initIterateGroupCmd(buildGr,true,false,true);
6179
_truck = iterateGroupCmd(buildGr,_bucket);
6180
while(_truck != NULLOBJECT)
6182
if((_order < 0) or (_truck.order == _order)) //Any order or right order type
6185
if(distBetweenTwoPoints(_rangex, _rangey, _truck.orderx , _truck.ordery) <= _range)
6187
retInt = retInt + 1;
6190
_truck = iterateGroupCmd(buildGr,_bucket);
6196
//---------------------------------------------------------------
6197
//Returns how many trucks have the same order location
6198
//---------------------------------------------------------------
6199
function int numTrucksSameOrderLoc(int _x, int _y, int _orderIndex)
6205
_bucket = initIterateGroupCmd(buildGr,true,false,true);
6206
tempDroid = iterateGroupCmd(buildGr,_bucket);
6207
while(tempDroid != NULLOBJECT)
6209
if((_orderIndex < 0) or (tempDroid.order == _orderIndex)) //Any order or right order type
6212
if(distBetweenTwoPoints(_x, _y, tempDroid.orderx , tempDroid.ordery) <= 64)
6214
retInt = retInt + 1;
6217
tempDroid = iterateGroupCmd(buildGr,_bucket);
6223
//---------------------------------------------------------------
6224
// Find out if a truck is already building on the spot where
6225
// another truck might try to build and will fail
6226
//---------------------------------------------------------------
6227
function bool buildingSiteBlocked(DROID _truck, int _radius, int _x, int _y, bool _bAllOrders)
6230
local DROID _tempDroid;
6232
_bucket = initIterateGroupCmd(buildGr,true,false,true);
6233
_tempDroid = iterateGroupCmd(buildGr,_bucket);
6234
while(_tempDroid != NULLOBJECT)
6236
if(_tempDroid != _truck) //Not himself (_truck allowed to be NULLOBJECT)
6238
if(_tempDroid.orderx > 0)
6241
if(distBetweenTwoPoints(_x, _y, _tempDroid.orderx , _tempDroid.ordery) <= _radius)
6245
if(_tempDroid.order != DORDER_NONE)
6252
if((_tempDroid.order == DORDER_BUILD) or (_tempDroid.order == DORDER_LINEBUILD))
6254
return true; //Spot busy
6261
_tempDroid = iterateGroupCmd(buildGr,_bucket);
6267
//Don't have to be deactivated
6268
event droidDestroyed(droidDestroyedTr)
6270
local DROID _commander,_newDroid,_droid;
6271
local GROUP _cmdGroup,_group;
6272
local int _cmdIndex;
6274
//ASSERT(count >= 0 and count < MAX_PLAYERS, "wrong player index: " & count, me);
6276
//Calculate how much a player has lost in power currency
6277
lostDroids[me] = lostDroids[me] + calcDroidPower(droid);
6279
//If a commander has lost a unit give it another unit
6281
if(droid.droidType == DROID_COMMAND)
6283
_cmdGroup = droid.group;
6284
_cmdIndex = cmdToIndex(droid);
6288
_group = cmdGr[_cmdIndex]; //group a commander belonged to
6290
dbg("Destroyed commander had " & _cmdGroup.members & " attached", me);
6292
//Add all units controlled by the commander to the group commander belonged to
6293
initIterateGroup(_cmdGroup);
6294
_droid = iterateGroup(_cmdGroup);
6295
while(_droid != NULLOBJECT)
6297
groupAddDroid(_group, _droid);
6298
_droid = iterateGroup(_cmdGroup);
6301
//refill other commanders from the same group as this commander with unassigned droids
6302
assignDroidsToBestCommandersFromGroup(_group, _group);
6307
//See if a unit belonged to a commander group and find a new unit for a commander
6308
if((droid.droidType != DROID_TRANSPORTER) and (droid.droidType != DROID_COMMAND))
6310
if(droid.group != NULLOBJECT) //this droid belonged to a group
6312
if(droid.group.type == GT_COMMAND) //if it's a commander group unit belonged to
6314
dbg("Destroyed unit from a commander group", me);
6316
_commander = droid.group.commander;
6317
_cmdIndex = cmdToIndex(_commander);
6318
if(_commander != NULLOBJECT and _cmdIndex >= 0)
6320
ASSERT(_commander.droidType == DROID_COMMAND, "Droid is not a commander", me);
6322
// find a droid not in a command group closest to the commander
6323
//_newDroid = closestDroidByGroup(defendGr, _commander.x, _commander.y, false);
6324
_newDroid = closestDroidByGroup(cmdGr[_cmdIndex], _commander.x, _commander.y, false);
6326
if(_newDroid != NULLOBJECT)
6328
//make sure a new unit will not have to travel too far
6329
if(distBetweenTwoPoints(_x, _y, _droid.x, _droid.y) < MAX_CMD_ASSIGN_DIST)
6331
dbg("Assigned a new droid to a commander", me);
6332
cmdDroidAddDroid(_commander, _newDroid);
6341
event structDestroyed(inactive)
6343
local int i,_numEnemies;
6345
if(structure == NULLOBJECT)
6348
// deal with a destroyed derrick
6349
if(structure.stat == derrick)
6351
if(!isInMyBase(structure.x,structure.y))
6353
_numEnemies = enemyWeapObjCostInRange(me, structure.x, structure.y,
6354
CHECK_OIL_THREAT_RANGE, false, true);
6356
tOilAttackBegin = GAME_TIME_IN_SECS;
6357
tLastOilAttack = GAME_TIME_IN_SECS;
6358
lastOilAttackedX = structure.x;
6359
lastOilAttackedY = structure.y;
6361
//if(checkOilThreat(structure.x, structure.y))
6363
if(canStartDefendingOil())
6365
// start defending oil
6366
initializeStartDefeindingOil(structure.x, structure.y);
6373
/* Update ghost data */
6374
if(structure.player == me)
6376
if((structure.stat == wall) or (structure.stattype == REF_DEFENSE))
6378
/* Find structure that was destroyed */
6380
while(i < maxGhosts)
6382
if((ghostx[i] == structure.x) and (ghosty[i] == structure.y) and (ghostStat[i] == structure.stat))
6384
dbg("FOUND DESTROYED STRUCTURE!!!!!", me);
6385
ghostDead[i] = TRUE;
6386
i = maxGhosts; //exit
6393
/* remember we lost LasSat */
6394
if(structure.stat == lasSat)
6396
lasSatState[me] = lsNone;
6400
function bool manageOilSite(DROID _truck, STRUCTURE _derrick)
6402
local int _threatRange;
6403
local bool _bBusy,_bThreat;
6404
local STRUCTURE _enemyDerrick;
6406
_threatRange = (TILE * 8);
6410
// attack unprotected enemy derrick with defenses, if can
6411
_enemyDerrick = getClosestEnemyStructByType(_derrick.x, _derrick.y, NEXT_OIL_RANGE, REF_RESOURCE_EXTRACTOR, me);
6412
if(_enemyDerrick != NULLOBJECT)
6414
// check if there are any enemy structures or droid nearby
6416
if(threatInRange(me, _enemyDerrick.x, _enemyDerrick.y, _threatRange, false))
6421
// if there are unbuilt structures, check if there's an enemy truck that could finish building it (assume it will be faster than us)
6424
if(numEnemyWeapStructsInRange(me, _enemyDerrick.x, _enemyDerrick.y, NEXT_OIL_RANGE, false) > 0)
6426
if(closestEnemyDroidByType(_enemyDerrick.x, _enemyDerrick.x , _threatRange, DROID_CONSTRUCT) != NULLOBJECT)
6431
if(closestEnemyDroidByType(_enemyDerrick.x, _enemyDerrick.x, _threatRange, DROID_CYBORG_CONSTRUCT) != NULLOBJECT)
6438
// build defenses near enemy derrick, if it's not dangerous
6441
// build defenses near enemy derrick => destroy it
6442
if(buildDerrickDefence(_enemyDerrick, _truck))
6444
dbg("ATTACKING ENEMY DERRICK WITH DEFENSES!!!", me);
6450
// TODO: also protect burning oil derricks, with a lower priority
6452
/* check if we can build another derrick near this one */
6453
if(!structureLimitReached(derrick, me))
6455
// try to build next oil nearby, exit here if succeeded
6456
if(buildNextOil(_truck, NEXT_OIL_RANGE, true))
6463
dbg("can't build more derricks", me);
6466
// if there's threat nearby, then first try to repair structures
6467
if(threatInRange(me, _derrick.x, _derrick.y, _threatRange, false))
6469
if(repairDamagedDefenses(_derrick.x, _derrick.y, _truck, 50, RANGE_ALL_OIL_DEFENSES)){
6473
if(finishDefenses(_truck, _derrick.x, _derrick.y, RANGE_ALL_OIL_DEFENSES)){
6479
if(finishDefenses(_truck, _derrick.x, _derrick.y, RANGE_ALL_OIL_DEFENSES)){
6483
if(repairDamagedDefenses(_derrick.x, _derrick.y, _truck, 50, RANGE_ALL_OIL_DEFENSES)){
6488
if(buildDerrickDefence(_derrick, _truck))
6496
event structBuilt(inactive)
6498
local FEATURE _oilResource;
6499
local STRUCTURE _closestDerrick;
6500
local int _count,_count2;
6502
//dbg(" " & me & ") CALLBACK - built (" & structure.x & "-" & structure.y & ")", me);
6504
if(structure == NULLOBJECT)
6506
MsgBox("structBuilt - structure NULLOBJECT");
6510
if(droid == NULLOBJECT)
6512
MsgBox("structBuilt - droid NULLOBJECT");
6516
/* remember we have LasSat */
6517
if(structure.stat == lasSat)
6519
dbg("buildInitialDefenses() - lassat built", me);
6521
lasSatState[me] = lsRecharging;
6524
/* build next anti-rush defense if just finished one,
6525
don't let other building routines intercept this truck */
6526
if((droid == initialDefensesTruck) and (not initialDefensesFinished))
6528
buildInitialDefenses(TRUE);
6532
/* give allies vision of the entire map */
6533
if(structure.stat == uplink)
6538
/* check if it's the right structure type */
6539
if(structure.stattype == REF_DEFENSE)
6541
/* find derrick we were building defense for */
6542
_closestDerrick = closestDerrick(structure.x, structure.y);
6544
if(_closestDerrick == NULLOBJECT){
6548
/* exit if this defense was not built for a derrick */
6549
if(distBetweenTwoPoints(_closestDerrick.x, _closestDerrick.y,
6550
structure.x, structure.y) > oilDefensesRange){ //closest derrick - built defense
6554
structure = _closestDerrick; //remember derrick for defenses building
6556
// if(!isInMyBase(_closestDerrick.x, _closestDerrick.y))
6558
if(manageOilSite(droid, _closestDerrick))
6564
// try to find any unoccupied oil resource
6565
if(buildNextOil(droid, NEXT_OIL_RANGE, false))
6570
else if(structure.stat == derrick)
6572
// if(!isInMyBase(structure.x, structure.y))
6574
if(manageOilSite(droid, structure))
6580
// try to find any unoccupied oil resource
6581
if(buildNextOil(droid, NEXT_OIL_RANGE, false))
6586
else if(structure.stattype == REF_FACTORY) /* factory or factory module */
6588
if( isStructureAvailable(facMod,me) and (skGetFactoryCapacity(structure) < 2 ))
6590
orderDroidStatsLoc(droid, DORDER_BUILD, facMod, structure.x, structure.y); // upgrade it.
6594
else if(!defendingBase() and structure.stattype == REF_VTOL_FACTORY) /* vtol factory or vtol factory module */
6596
if( isStructureAvailable(facMod,me) and (skGetFactoryCapacity(structure) < 2 ))
6598
orderDroidStatsLoc(droid, DORDER_BUILD,facMod, structure.x,structure.y); // upgrade it.
6602
else if(!defendingBase() and structure.stattype == REF_POWER_GEN) /* power generator */
6604
if( isStructureAvailable(powMod,me) and (not testStructureModule(me, structure, 0)))
6606
orderDroidStatsLoc(droid, DORDER_BUILD,powMod, structure.x,structure.y); // upgrade it.
6615
//if(bResult){exit;} //already started building with this truck
6617
/* if(structure == NULLOBJECT){exit;} //don't have a derrick to defend
6619
if(structure.stat != derrick){exit;} //make sure we are going to build defenses for a derrick
6621
if(defendingBase()){exit;}
6623
// make the callback droid build a defence near this oil derrick
6624
buildDerrickDefence(structure, droid, NEXT_OIL_RANGE); */
6627
event droidTakeOverEv(inactive)
6629
if(droid != NULLOBJECT)
6631
if(droid.player == me)
6634
notifyAllies(strGratitude(), false);
6639
MsgBox("droidTakeOverEv - NULLOBJECT passed");
6643
//deal with a droid being built
6644
event droidBuilt(inactive)
6648
// start building trucks if we need any
6653
// start build tanks
6654
if((tech == techTanks) or (playerPower(me) > muchoPower))
6656
// if(canBuildTanks())
6663
function void assignDroid(DROID _droid)
6665
local DROID _commander;
6669
groupAddDroid(vtolGr, _droid);
6671
else if(_droid.droidType == DROID_COMMAND)
6673
assignCommander(_droid, defendGr);
6677
setDroidSecondary(_droid, DSO_ATTACK_RANGE, DSS_ARANGE_LONG);
6678
setDroidSecondary(_droid, DSO_HALTTYPE, DSS_HALT_GUARD);
6680
if((_droid.droidType == DROID_CONSTRUCT) or
6681
(_droid.droidType == DROID_CYBORG_CONSTRUCT)) // if constructor droid
6683
/* make it build anti-rush defenses if still not finished */
6684
if(!initialDefensesFinished)
6686
if((groupSizeCmds(buildGr,true,false,true) >= 5) and (initialDefensesTruck == NULLOBJECT))
6688
dbg("buildInitialDefenses() assigned truck", me);
6689
initialDefensesTruck = _droid;
6690
buildInitialDefenses(true);
6695
// add to the build group
6696
groupAddDroid(buildGr, _droid);
6698
else if(_droid.droidType == DROID_TRANSPORTER)
6700
dbg("built transporter", me);
6704
while((temp < 10) and bResult)
6706
if(transporter[temp] == NULLOBJECT)
6708
dbg("built transporter " & temp, me);
6709
transporter[temp] = _droid;
6710
orderDroidLoc(_droid, DORDER_MOVE, baseX, baseY);
6716
else if((_droid.droidType == DROID_REPAIR) or
6717
(_droid.droidType == DROID_CYBORG_REPAIR))
6719
setDroidSecondary(_droid, DSO_HALTTYPE, DSS_HALT_PERSUE);
6721
//commanders have priority
6722
_commander = bestCommanderWithoutRepairer();
6723
if(_commander != NULLOBJECT)
6725
dbg("Added repeir droid to commander " & cmdToIndex(_commander), me);
6727
ASSERT(_commander.droidType == DROID_COMMAND, "Droid is not a commander", me);
6729
groupAddDroid(cmdRepGr[ cmdToIndex(_commander) ], _droid);
6731
else //add to defenders if no commander needs repair units
6733
groupAddDroid(defendRepairGr, _droid);
6736
else if(_droid.weapon == weaponBB)
6738
//prfunction void BBs from wasting ammo on units
6739
//setDroidSecondary(_droid, DSO_ATTACK_LEVEL, DSS_ALEV_ATTACKED);
6740
groupAddDroid(defendGr, _droid);
6741
assignDroidToBestCommander(_droid, defendGr);
6747
//don't add to scouts if not early-game anymore and not enough defenders
6749
if((groupSizeCmds(defendGr,true,false,true) < numDefenders) and (GAME_TIME_IN_SECS > SCOUT_BUILD_TIME))
6754
if(defendingBase()){
6758
if(watchWindowDebug == WATCH_DEBUG_RESEARCH){
6759
setDebugMenuEntry("to scouts: " & addScout & "/" & lowMilitary & "/" & bResult2, 8);
6762
if((addScout == 0) and !lowMilitary and bResult2) //for scouts?
6764
if(groupSizeCmds(enemyScoutGr,true,false,true) < numEnemyScouts and bToEnemyScoutGr)
6766
// send to the scout location immediately
6767
if(realEnemyScoutX > 0 and realEnemyScoutY > 0){
6768
orderDroidLoc(_droid, DORDER_MOVE, realEnemyScoutX, realEnemyScoutY);
6771
groupAddDroid(enemyScoutGr, _droid);
6773
bToEnemyScoutGr = !bToEnemyScoutGr;
6775
else if(groupSizeCmds(scoutGr,true,false,true) < numOilScouts and !bToEnemyScoutGr)
6777
groupAddDroid(scoutGr, _droid);
6779
bToEnemyScoutGr = !bToEnemyScoutGr;
6783
if((addScout != 0) or !bResult) //for attackers, or scouts were full
6785
if((defendX != none) and (defendY != none))
6787
result = numFriendlyWeapObjInRange(me, defendX, defendY, (10 * 128), false, true);
6788
result2 = numEnemyWeapObjInRange(me, defendX, defendY, (10 * 128), false, true);
6790
if((groupSizeCmds(defendGr,true,false,true) >= minDefenders) or (result >= result2)) //don't send one by one or if dangerous
6792
orderDroidLoc(_droid, DORDER_SCOUT, defendX, defendY);
6796
groupAddDroid(defendGr, _droid);
6797
assignDroidToBestCommander(_droid, defendGr);
6799
/* remember we'd finished building first-time defenders */
6800
if((groupSizeCmds(defendGr,true,false,true) >= minDefenders) or (gameTime > (8 * 600))) //8 mins
6801
bFirstTimeDefenders = FALSE;
6805
if(addScout > addScoutInterval)
6807
addScout = 0; //add to scouts next one
6813
// Update scout variables
6814
function void updateMaxScouts()
6818
enemyScoutRange = (13 * 128); //revealed when within this range
6820
addScout = 0; //next tank is for scouts
6822
// addScoutInterval = (int) ( ((float)MAX_SCOUTS_PRIORITY - (float)MIN_SCOUTS_PRIORITY) /
6823
// ((float)SCOUT_MIN_OIL_RES - (float)SCOUT_MAX_OIL_RES) *
6824
// (float)numVisibleOilResInRange() + (float)MAX_SCOUTS_PRIORITY );
6826
// use more scouts if there are not many revealed oil resources [ y = mx+z => y = (x1 - x2 / y1 - y2)x + z ]
6827
addScoutInterval = (int)(((float)MIN_SCOUTS_PRIORITY - (float)MAX_SCOUTS_PRIORITY) /
6828
(MAP_REVEAL_FAC_UBOUND - MAP_REVEAL_FAC_LBOUND) *
6830
(float)MAX_SCOUTS_PRIORITY);
6831
if(watchWindowDebug == WATCH_DEBUG_RESEARCH)
6833
setDebugMenuEntry("addScoutInterval: " & addScoutInterval & "(" & min(addScoutInterval, MIN_SCOUTS_PRIORITY)
6834
& "/" & max(min(addScoutInterval, MIN_SCOUTS_PRIORITY), MAX_SCOUTS_PRIORITY) & ")", 4);
6836
// make sure addScoutInterval is between MAX_SCOUTS_PRIORITY and MIN_SCOUTS_PRIORITY
6837
addScoutInterval = min(addScoutInterval, MIN_SCOUTS_PRIORITY);
6838
addScoutInterval = max(addScoutInterval, MAX_SCOUTS_PRIORITY);
6840
// use 2 scouts when scouting has a high priority
6841
// if(addScoutInterval <= MAX_SCOUTS_PRIORITY){
6842
// maxEnemyScouts = 2;
6847
numEnemyScouts = maxEnemyScouts;
6849
if(GAME_TIME_IN_SECS <= STARTUP_PHASE_LEN){
6850
dbg("addScoutInterval = " & addScoutInterval, me);
6854
scoutStep = (25 * 128); //inacrease search area by this value
6855
scoutRange = scoutStep; //start with small area
6860
enemyScoutStep = (18 * 128);
6862
// define number of oil scouts depending on the map reveal factor (linear function)
6863
maxOilScouts = (int)((float)(MIN_OIL_SCOUTS - MAX_OIL_SCOUTS) /
6864
(MAP_REVEAL_FAC_UBOUND - MAP_REVEAL_FAC_LBOUND) *
6865
fMapRevealFactor) + MAX_OIL_SCOUTS;
6867
//adapt for big maps
6870
enemyScoutStep = (25 * 128);
6873
scoutStep = scoutStep + (TILE * 12);
6874
scoutRange = scoutStep;
6877
numOilScouts = maxOilScouts;
6880
//Group can be NULLOBJECT
6881
function DROID closestDroidByGroup(GROUP _group, int _x, int _y, bool _bIncludeCommanders)
6883
local DROID _droid,_closestDroid;
6884
local int _closestDistance,_dist,_bucket;
6886
_closestDistance = 99999;
6887
_closestDroid = NULLOBJECT;
6889
if(_group != NULLOBJECT)
6891
_bucket = initIterateGroupCmd(_group,true,_bIncludeCommanders,_bIncludeCommanders);
6892
_droid = iterateGroupCmd(_group, _bucket);
6893
while(_droid != NULLOBJECT)
6895
//calculate the distance between the _commander and droid
6896
_dist = distBetweenTwoPoints(_x, _y, _droid.x, _droid.y);
6898
if(_dist < _closestDistance)
6900
_closestDistance = _dist;
6901
_closestDroid = _droid;
6904
_droid = iterateGroupCmd(_group,_bucket);
6908
return _closestDroid;
6911
/************************************
6913
*************************************/
6914
/* Unassign all droids from all commanders belonging to a certain group */
6915
function void unassignAllDroidsFromCMDsFromGroup(GROUP _unassignGroup, GROUP _toGroup)
6917
local int _cmdIndex;
6920
while(_cmdIndex < MAX_COMMANDERS)
6922
if(cmds[_cmdIndex] != NULLOBJECT)
6924
if((_unassignGroup == NULLOBJECT) or (_unassignGroup == cmdGr[_cmdIndex]))
6926
unassignAllDroidsFromCMD(cmds[_cmdIndex], _toGroup);
6933
/* Unassign all units from a commander */
6934
function void unassignAllDroidsFromCMD(DROID _commander, GROUP _toGroup)
6936
local GROUP _cmdGroup;
6937
local DROID _groupMember;
6939
ASSERT(_commander != NULLOBJECT,
6940
"unassignAllDroidsFromCMD: _commander is NULL", me);
6942
_cmdGroup = _commander.group;
6944
initIterateGroup(_cmdGroup);
6945
_groupMember = iterateGroup(_cmdGroup);
6946
while(_groupMember != NULLOBJECT)
6948
ASSERT(_groupMember.droidType != DROID_COMMAND,
6949
"unassignAllDroidsFromCMD: unassigning a commander from a commander group?", me);
6951
//droidLeaveGroup(_groupMember);
6952
groupAddDroid(_toGroup, _groupMember);
6953
_groupMember = iterateGroup(_cmdGroup);
6957
/* Goes through all commanders from group x and assigns droids from group x to all commanders from group x in a smart way */
6958
function void assignDroidsToBestCommandersFromGroup(GROUP _fromGroup, GROUP _toGroup)
6960
local int _cmdIndex,_bestCMDKills,_tmpCmdKills,_bestCost,_tmpCost,
6961
_bucket,_bestCmdMaxDroids;
6962
local DROID _droid,_bestCMD,_bestDroid;
6967
while(!_bStop and // still have more commanders
6968
groupSizeCmds(_fromGroup, true, false, false) > 0) //only count unassigned droids
6971
_bestCMDKills = (-1);
6972
_bestCMD = NULLOBJECT;
6974
while(_cmdIndex < MAX_COMMANDERS)
6976
// find best commander with highest rank
6977
if(cmds[_cmdIndex] != NULLOBJECT)
6979
if( (_toGroup == cmdGr[_cmdIndex]) and //the right group
6980
(cmds[_cmdIndex].group.members < cmdDroidMaxGroup(cmds[_cmdIndex])) ) //commander can take more droids
6982
_tmpCmdKills = getDroidKills(cmds[_cmdIndex]);
6984
if(_tmpCmdKills > _bestCMDKills)
6986
_bestCMD = cmds[_cmdIndex];
6987
_bestCMDKills = _tmpCmdKills;
6994
//Now fill droids for the best found commander
6995
if(_bestCMD != NULLOBJECT)
6997
//find out how many droid this commander can have assigned
6998
_bestCmdMaxDroids = cmdDroidMaxGroup(_bestCMD);
7000
while( (_bestCMD.group.members < _bestCmdMaxDroids) and //while commander group not full
7001
(groupSizeCmds(_fromGroup, true, false, false) > 0) ) //while there are still more droids in the _fromGroup group
7004
_bestDroid = NULLOBJECT;
7006
//Find the most expensive droid
7007
_bucket = initIterateGroupCmd(_fromGroup,true,false,false); //don't touch units from commander group
7008
_droid = iterateGroupCmd(_fromGroup,_bucket);
7009
while(_droid != NULLOBJECT)
7011
_tmpCost = calcDroidPower(_droid);
7013
if(_tmpCost > _bestCost)
7015
_bestCost = _tmpCost;
7016
_bestDroid = _droid;
7019
_droid = iterateGroupCmd(_fromGroup,_bucket);
7022
//Add best droid to the best commander
7023
cmdDroidAddDroid(_bestCMD, _bestDroid);
7028
_bStop = true; //No more commanders left, stop here
7035
function void assignDroidToBestCommander(DROID _droid, GROUP _group)
7037
local int _cmdIndex,_tilesPerDroid,_tilesPerRank,_tileDist,_bestScore,
7038
_score,_rank,_cmdGroupSize;
7039
local DROID _bestCommander;
7041
_tilesPerDroid = (TILE * 3); //1 droid = 3 tiles
7042
_tilesPerRank = (TILE * 7); //1 rank higher = 6 tiles
7044
_bestScore = (-99999);
7045
_bestCommander = NULLOBJECT;
7047
//find the most suitable commander, consider distance to the commander, size of its group and commander rank
7049
while(_cmdIndex < MAX_COMMANDERS)
7051
if(cmds[_cmdIndex] != NULLOBJECT)
7053
//if group is specified make sure commander belongs to this group
7054
if((_group == NULLOBJECT) or (cmdGr[_cmdIndex] == _group))
7056
//skip commanders who already have a full group
7057
if(cmds[_cmdIndex].group.members < cmdDroidMaxGroup(cmds[_cmdIndex]))
7059
//calculate distance between the base range and commander (will be 0 if commander is withon the base range)
7060
_tileDist = (distBetweenTwoPoints(cmds[_cmdIndex].x, cmds[_cmdIndex].y, _droid.x, _droid.y) -
7061
(baseRange + defendCorridor)) / TILE;
7062
_tileDist = max(0, _tileDist); //make sure distance is not negative
7064
_rank = getDroidRank(cmds[_cmdIndex]);
7065
_cmdGroupSize = cmds[_cmdIndex].group.members;
7068
_score = _rank * _tilesPerRank - _cmdGroupSize * _tilesPerDroid - _dist;
7070
//check if this commander is the best one so far
7071
if(_score > _bestScore)
7073
_bestScore = _score;
7074
_bestCommander = cmds[_cmdIndex];
7083
//add droid to the group of the best suitable commander
7084
if(_bestCommander != NULLOBJECT)
7086
cmdDroidAddDroid(_bestCommander, _droid);
7090
//Store a newly built comander
7091
function void assignCommander(DROID _newCommander, GROUP _group)
7095
// FIXME: number of commander can exceed MAX_COMMANDERS
7098
while(_index < MAX_COMMANDERS)
7100
if(cmds[_index] == NULLOBJECT) //found a free slot
7103
cmds[_index] = _newCommander;
7104
cmdGr[_index] = _group; //set group commander belongs to
7106
//Add droids without commander to the new commander
7107
fillCommanderGroup(_newCommander, _group);
7115
/* Add droids to the _commander */
7116
function void fillCommanderGroup(DROID _commander, GROUP _fillFromGroup)
7118
local GROUP _cmdGroup;
7119
local DROID _droid,_closestDroid;
7120
local int _freeCapacity,_index,_closestDistance,_cmdX,_cmdY,_dist;
7122
_cmdGroup = _commander.group;
7124
//Find out how many droids this commander can have in a group
7125
_freeCapacity = cmdDroidMaxGroup(_commander) - _cmdGroup.members;
7127
_cmdX = _commander.x;
7128
_cmdY = _commander.x;
7131
while(_index < _freeCapacity)
7133
_closestDroid = NULLOBJECT;
7134
_closestDistance = 99999;
7136
_closestDroid = closestDroidByGroup(_fillFromGroup, _commander.x, _commander.y, false);
7138
//Add found droid to the _commander
7139
if(_closestDroid != NULLOBJECT)
7141
cmdDroidAddDroid(_commander, _closestDroid);
7147
dbg("Adding " & _index & "/" & _freeCapacity & " to the commander", me);
7150
/* Check if we can build commanders */
7151
function bool canUseCommanders()
7153
haveCommandTech = researchFinished(resCmd, me);
7157
if(structureBuilt(cmdCenter, me)) //make sure command center is finished building
7166
/* Returns number of commanders */
7167
function int getNumCommanders()
7169
/* local int _index,_numCmds;
7173
while(_index < MAX_COMMANDERS)
7175
if(cmds[_index] != NULLOBJECT)
7184
return numDroidsByComponent(cmdTurret, me, me);
7187
/* Returns how many units can be attached to all available commanders (_group == NULLOBJECT) or to all commanders in some group (_group != NULLOBJECT) */
7188
function int getTotalCmdsCapacity(GROUP _group, bool _bIncludeInProduction)
7190
local int _index,_numDroids;
7194
while(_index < MAX_COMMANDERS)
7196
if(cmds[_index] != NULLOBJECT)
7198
if((_group == NULLOBJECT) or (cmdGr[_index] == _group)) //make sure commander belongs to the right group
7200
_numDroids = _numDroids + cmdDroidMaxGroup(cmds[_index]);
7206
//Check if we have to include commanders that are getting built now
7207
if(_bIncludeInProduction)
7209
_numDroids = _numDroids + numCommandersInProduction() * CMD_INIT_CAPACITY;
7215
/* Returns total number of droids that can still be assigned to commanders belonging to a certain group */
7216
function int getFreeCmdsCapacityInGroup(GROUP _group)
7218
local int _index,_numDroids;
7222
while(_index < MAX_COMMANDERS)
7224
if(cmds[_index] != NULLOBJECT)
7226
if((_group == NULLOBJECT) or (cmdGr[_index] == _group)) //make sure commander belongs to the right group
7228
_numDroids = _numDroids +
7229
cmdDroidMaxGroup(cmds[_index]) - cmds[_index].group.members;
7238
/* fill commanders with highest rank into some group until some tatal capacity is reached */
7239
function void fillBestCommandersCapacity(int _maxCapacity, GROUP _newGroup,
7242
local int _curCapacity,_cmdIndex,_bestKills,_tmpKills,_bestCMDIndex;
7243
local bool _bCMDsLeftToIterate;
7244
local DROID _bestCommander;
7246
dbg("fillBestCommandersCapacity: _maxCapacity = " & _maxCapacity, me);
7251
//make sure there are commanders left in the old group we can iterate over
7252
_bCMDsLeftToIterate = (groupSizeCmds(_oldGroup, false, true, false) > 0);
7254
//iterate over all commanders until capacity is filled or no commanders left in the old group
7255
while((_curCapacity < _maxCapacity) and _bCMDsLeftToIterate)
7259
_bestCMDIndex = (-1);
7260
_bestCommander = NULLOBJECT;
7262
while(_cmdIndex < MAX_COMMANDERS)
7264
if(cmds[_cmdIndex] != NULLOBJECT)
7266
if( ((_oldGroup == NULLOBJECT) or (cmdGr[_cmdIndex] == _oldGroup)) //cmd is in the right group
7267
and (cmdGr[_cmdIndex] != _newGroup)) //make sure we won't re-add commanders we just added
7269
_tmpKills = getDroidKills(cmds[_cmdIndex]);
7271
if(_tmpKills > _bestKills)
7273
_bestCommander = cmds[_cmdIndex];
7274
_bestCMDIndex = _cmdIndex;
7275
_bestKills = _tmpKills;
7282
// add commander with the most kills to the new group
7283
if(_bestCommander != NULLOBJECT)
7285
cmdGr[_bestCMDIndex] = _newGroup; //change commander's group
7286
_curCapacity = _curCapacity + cmdDroidMaxGroup(_bestCommander);
7289
//make sure there are commanders left in the old group we can iterate over
7290
_bCMDsLeftToIterate = (groupSizeCmds(_oldGroup, false, true, false) > 0);
7294
/* Goes through all commander groups and counts how many repairers are missing in total */
7295
function int numMissingCmdRepairers(int _groupIndex, bool _bIncludeDeadCmds)
7297
local int _numMissing,_index;
7301
while(_index < MAX_COMMANDERS)
7303
if(_bIncludeDeadCmds or (cmds[_index] != NULLOBJECT))
7305
if((_groupIndex < 0) or (_index == _groupIndex))
7307
// make sure commander has any droids attached or has a high level
7308
if((cmds[_index].group.members > 0) or
7309
(getDroidRank(cmds[_index]) >= 2))
7311
_numMissing = _numMissing +
7312
max(NUM_REPAIRS_FOR_CMD - cmdRepGr[_index].members, 0); //max = don't reduce _numMissing if cmd has more than NUM_REPAIRS_FOR_CMD repairers
7322
/* Returns the commander the deserves to get a new repair unit */
7323
function DROID bestCommanderWithoutRepairer()
7325
local int _index,_tmpScore,_bestScore;
7326
local DROID _bestCommander,_commander;
7330
_bestCommander = NULLOBJECT;
7331
while(_index < MAX_COMMANDERS)
7333
if(cmds[_index] != NULLOBJECT)
7335
//make sure this commander still needs repair units
7336
if(cmdRepGr[_index].members < NUM_REPAIRS_FOR_CMD) //not to omany
7338
//best score in kills
7339
_tmpScore = getDroidKills(cmds[_index]) + // commander rank
7340
((100 - cmds[_index].health) / 2) + // damage in % / weight
7341
((NUM_REPAIRS_FOR_CMD - cmdRepGr[_index].members) * 30); //missing repairers * weight
7343
if(_tmpScore > _bestScore)
7345
_bestScore = _tmpScore;
7346
_bestCommander = cmds[_index];
7353
return _bestCommander;
7357
//==============================================================================================
7358
// >>>>>>>>>>>>>>>>>>>>>>>> MILITARY STUFF <<<<<<<<<<<<<<<<<<<<<<<<<
7359
//==============================================================================================
7361
event manageCMDRepairsEv(inactive)
7366
/* Repair and follow commanders */
7367
function void repairCMDGroup()
7369
local int _cmdIndex,_x,_y,_maxDistanceFromCMD,_bucket,_distanceFromCMD;
7370
local DROID _repairer,_droidToRepair,_commanderToRepair;
7376
while(_cmdIndex < MAX_COMMANDERS)
7378
if((cmds[_cmdIndex] != NULLOBJECT) and (cmdRepGr[_cmdIndex].members > 0))
7380
// see if we have to repair commander
7381
_commanderToRepair = NULLOBJECT;
7382
if(cmds[_cmdIndex].health < 95){
7383
_commanderToRepair = cmds[_cmdIndex];
7386
// iterate through all repair droids this commander group has and look if it is too far away from the commander
7387
_bucket = initIterateGroupCmd(cmdRepGr[_cmdIndex],true,true,true);
7388
_repairer = iterateGroupCmd(cmdRepGr[_cmdIndex],_bucket);
7389
while(_repairer != NULLOBJECT)
7393
// if not repairing commander
7394
if(! (_repairer.order == DORDER_DROIDREPAIR and // don't do anything if repairing commander already
7395
_repairer.target == cmds[_cmdIndex]) )
7397
// see if we have to repair our commander
7398
if(_commanderToRepair != NULLOBJECT)
7401
orderDroidObj(_repairer, DORDER_DROIDREPAIR, _commanderToRepair);
7403
else // see if we have to come closer to the commander if we are not already on the way to the commander
7405
// if repairer is repairing something (explicitly or implicitly) he can stay further away from the commander
7406
_maxDistanceFromCMD = MAX_REP_DIST_FROM_CMD; //if idle
7407
if(_repairer.order == DORDER_DROIDREPAIR or
7408
(droidActionDroidRepair(_repairer)))
7410
_maxDistanceFromCMD = MAX_REP_DIST_FROM_CMD_WHILE_REP;
7413
// find cur dist to the commander
7414
_distanceFromCMD = distBetweenTwoPoints(cmds[_cmdIndex].x,
7415
cmds[_cmdIndex].y, _repairer.x, _repairer.y);
7417
if(_distanceFromCMD > _maxDistanceFromCMD) // too far away from commander
7419
// already moving closer to the comander ?
7420
if( !( (_repairer.order == DORDER_MOVE) and (_repairer.orderx > 0) and
7421
(distBetweenTwoPoints(_repairer.orderx, _repairer.ordery, cmds[_cmdIndex].x, cmds[_cmdIndex].y) <
7422
(MAX_REP_DIST_FROM_CMD * 2) )) )
7424
_x = baseX; //_repairer.x;
7425
_y = baseY; //_repairer.y;
7429
circlePerimPoint(cmds[_cmdIndex].x, cmds[_cmdIndex].y, ref _x, ref _y, (MAX_REP_DIST_FROM_CMD + 1) / 2); //send back to commander
7430
orderDroidLoc(_repairer, DORDER_MOVE, _x, _y);
7432
dbg("Moving repairer to commander " & _cmdIndex & "(" & _x / TILE & "-" & _y / TILE & ")", me);
7437
// if not coming closer to the commander and not repairing commander then repair a damaged droid if we have one
7438
if(!_bBusy and (_repairer.order != DORDER_DROIDREPAIR) and
7439
!droidActionDroidRepair(_repairer)) //not busy, not repairing
7441
// find a damaged unit
7442
_droidToRepair = findCMDGroupObjectToRepair(_cmdIndex, _repairer);
7444
if(_droidToRepair != NULLOBJECT)
7446
// order repair droid to repair this unit
7447
if(_droidToRepair != NULLOBJECT){
7448
orderDroidObj(_repairer, DORDER_DROIDREPAIR, _droidToRepair);
7453
_repairer = iterateGroupCmd(cmdRepGr[_cmdIndex],_bucket);
7460
/* Find a droid commander repairs should repair */
7461
function DROID findCMDGroupObjectToRepair(int _cmdIndex, DROID _repairer)
7463
local DROID _choiceDroid,_droid,_mostDamagedDroid,_damagedRepairer;
7464
local int _mostDamage,_tempDamage,_tempScore,_bestScore,_bucket,
7465
_distScore,_damageScore,_dist;
7467
_choiceDroid = NULLOBJECT;
7468
_mostDamagedDroid = NULLOBJECT;
7470
if(_cmdIndex >= MAX_COMMANDERS){
7471
return _choiceDroid;
7474
// find a damaged repair unit
7476
_choiceDroid = NULLOBJECT;
7477
_bucket = initIterateGroupCmd(cmdRepGr[_cmdIndex],true,true,true);
7478
_damagedRepairer = iterateGroupCmd(cmdRepGr[_cmdIndex],_bucket);
7479
while(_damagedRepairer != NULLOBJECT)
7481
// make sure we are not going to repair ourselves
7482
if(_damagedRepairer != _repairer)
7484
_tempDamage = 100 - _damagedRepairer.health;
7486
// don't bother if too far away, will be ordered back anyway
7487
if(distBetweenTwoPoints(_damagedRepairer.x,_damagedRepairer.y,
7488
cmds[_cmdIndex].x, cmds[_cmdIndex].y) < MAX_REP_DIST_FROM_CMD_WHILE_REP)
7490
// remember the most damaged repair unit
7491
if(_tempDamage > _mostDamage)
7493
_mostDamage = _tempDamage;
7494
_choiceDroid = _damagedRepairer;
7498
_damagedRepairer = iterateGroupCmd(cmdRepGr[_cmdIndex],_bucket);
7501
// see if repair unit is slightly damaged
7502
if(_choiceDroid != NULLOBJECT)
7504
if(_choiceDroid.health < 90)
7506
return _choiceDroid;
7510
// find a damaged unit attached to a commander
7511
_bestScore = (-99999);
7512
_choiceDroid = NULLOBJECT;
7513
_bucket = initIterateGroupCmd(cmdRepGr[_cmdIndex],true,true,true);
7514
_droid = iterateGroupCmd(cmdRepGr[_cmdIndex],_bucket);
7515
while(_droid != NULLOBJECT)
7517
// find out how far the damaged unit is from the repairer
7518
_dist = distBetweenTwoPoints(_repairer.x,_repairer.y,_droid.x,_droid.y);
7520
// consider health and distance from the commander, make sure droid is not too far away
7521
if((_droid.health < 90) and (_dist < MAX_REP_DIST_FROM_CMD_WHILE_REP))
7523
// the closer the better
7524
_distScore = _dist / TILE;
7526
// the more damaged the better
7527
_damageScore = (100 - _droid.health);
7529
// calculate final score
7530
_tempScore = (int)((float)_damageScore * 2.3) - _distScore;
7532
// remember the most damaged repair unit
7533
if(_tempScore > _bestScore)
7535
_bestScore = _tempScore;
7536
_choiceDroid = _droid;
7540
_droid = iterateGroupCmd(cmdRepGr[_cmdIndex],_bucket);
7543
// see if this unit is really damaged and needs to be repaired
7544
if(_choiceDroid != NULLOBJECT)
7546
return _choiceDroid;
7549
_choiceDroid = NULLOBJECT;
7551
return _choiceDroid;
7554
function bool repairDamagedDefenses(int _repairx, int _repairy, DROID _truck,
7555
int _minDamage, int _maxRange)
7557
local int _def,_mostDamage,_tempDamage;
7558
local STRUCTURE _defense, _mostDamagedDefense;
7561
_mostDamagedDefense = NULLOBJECT;
7566
initEnumStruct(FALSE,def[_def],me,me);
7567
_defense = enumStruct();
7568
while(_defense != NULLOBJECT)
7570
if(distBetweenTwoPoints(_defense.x, _defense.y, _repairx, _repairy) < _maxRange)
7572
if(!buildingSiteBlocked(_truck, _maxRange, _defense.x, _defense.y, true))
7574
_tempDamage = 100 - _defense.health;
7576
// damaged at least by _minDamage %
7577
if(_tempDamage >= _minDamage)
7579
// remember the most damaged defense
7580
if(_tempDamage > _mostDamage)
7582
_mostDamage = _tempDamage;
7583
_mostDamagedDefense = _defense;
7588
_defense = enumStruct();
7594
if(_mostDamagedDefense != NULLOBJECT)
7596
orderDroidObj(_truck, DORDER_REPAIR, _mostDamagedDefense);
7603
event repairDefendDroids(inactive)
7605
if(groupSizeCmds(defendRepairGr,true,false,true) == 0){exit;}
7606
if(groupSizeCmds(defendGr,true,true,true) == 0){exit;}
7608
groupRepairGroup(defendGr, defendRepairGr);
7610
/* repair the repair droids if idle */
7611
if((groupSizeCmds(defendRepairGr,true,false,true) > 1) and (idleGroupCmd(defendRepairGr,true,false) > 0))
7613
groupRepairGroup(defendGr, defendRepairGr);
7617
function void groupRepairGroup(GROUP _damagedGr, GROUP _repairerGr)
7621
_temp = maxDamageLevels - 1; //start with heavyDamage, don't reset before loop to save CPU time
7624
_bucket = initIterateGroupCmd(_repairerGr,true,false,true);
7625
_droid = iterateGroupCmd(_repairerGr,_bucket);
7626
while(_droid != NULLOBJECT)
7628
if(_droid.order != DORDER_DROIDREPAIR) //not already busy
7630
/* look for a damaged unit, starting search with heavily damaged units */
7631
_droid2 = NULLOBJECT; //damaged droid
7632
while((_temp >= 0) and (_droid2 == NULLOBJECT)) //first look for heavilyDamaged units, going up to lightDamage
7634
/* find damaged droid no one is repairing yet */
7635
_droid2 = closestDamagedGroupDroid(me, _damagedGr, damageLevel[_temp], _droid.x, _droid.y, 0);
7636
if(_droid2 == NULLOBJECT)
7638
_temp = _temp - 1; //go to lighter damage levels
7642
if((_droid2 != NULLOBJECT) and (_droid != _droid2)) //found someone and him going to repair himself
7644
//dbg("FOUND DAMAGED UNIT!!!! (for unit " & _temp2 & ")", me);
7645
orderDroidObj(_droid, DORDER_DROIDREPAIR, _droid2);
7647
else if(droidOrderIdle(_droid) or (_droid.target == _droid)) //if idle or auto-repairing
7649
/* if idle, check it's not too far away from the base */
7650
//_range = baseRange + defendCorridor; //allow to repair defenders in the corridor as well
7651
//if((_droid.order == DORDER_NONE) and (_droid.target == NULLOBJECT)) //if not repairing
7653
// _range = baseRange; //move closer to base
7658
if(distBetweenTwoPoints(_droid.x, _droid.y, baseX, baseY) > _range)
7660
//dbg("ORDERING REPAIR UNIT BACK TO BASE", me);
7663
circlePerimPoint(baseX, baseY, ref _x, ref _y, baseRange); //send back to base
7664
orderDroidLoc(_droid, DORDER_MOVE, _x, _y);
7668
//don't reset _temp and don't start over for every repair unit, since nothing changes
7672
_droid = iterateGroupCmd(_repairerGr,_bucket);
7676
/* Goes through trucks and compares target */
7677
function DROID getTruckByTarget(BASEOBJ _target)
7682
_bucket = initIterateGroupCmd(buildGr,true,false,true);
7683
_droid = iterateGroupCmd(buildGr,_bucket);
7684
while(_droid != NULLOBJECT)
7686
if(_droid.target == _target)
7689
_droid = iterateGroupCmd(buildGr,_bucket);
7695
/* Number of BB templates a player is currently building */
7696
function int numBBsInProduction(int _player)
7698
local int _index,_numBBsInProd;
7702
while(_index < numBBTempl)
7704
_numBBsInProd = _numBBsInProd + numTemplatesInProduction(tmplBB[_index], _player);
7708
return _numBBsInProd;
7711
function int numBuildersInProduction(int _player)
7713
local int _index,_numBuildersInProd;
7717
_numBuildersInProd = 0;
7718
while(_index < numTruckTmpl)
7720
_numBuildersInProd = _numBuildersInProd +
7721
numTemplatesInProduction(truck[_index], _player);
7726
/* Cyborg Engineers */
7727
_numBuildersInProd = _numBuildersInProd +
7728
numTemplatesInProduction(cybEngineer,me); //engineers
7730
return _numBuildersInProd;
7733
function int numCommandersInProduction()
7735
local int _index,_numCmdsInProd;
7739
while(_index < numCmdTmpl)
7741
_numCmdsInProd = _numCmdsInProd + numTemplatesInProduction(tmplCmd[_index], me);
7745
return _numCmdsInProd;
7748
function bool needStartupScouts()
7750
if(GAME_TIME_IN_SECS > SCOUT_BUILD_TIME){
7754
if(groupSizeCmds(enemyScoutGr,true,false,true) == 0){
7758
if(groupSizeCmds(scoutGr,true,false,true) == 0){
7765
function bool canBuildTanks()
7767
// make sure we didn't build too many units already
7768
if(getDroidCount(me) >= unitLimit){
7772
// make sure we won't use too much of the startup power for tanks
7773
if(!needStartupScouts() or //ensure have scouts
7774
((GAME_TIME_IN_SECS > MIN_DELAY_INITIAL_TANKS) and //waited min time delay
7775
(GAME_TIME_IN_SECS > MAX_DELAY_INITIAL_TANKS or numBuildingDefenses() < 3))) //if can use power now (ie not building many defenses) or had enough time to build defenses
7783
function void buildTanks()
7785
local int _numTotalCommanders,_index,_numNeedCmds,
7786
_result,_result2,_facNum,_tmplGroup,_numDroidsNoCmd,
7787
_needTotalRepairers,_minUnassignedDroids,_needBBs,
7789
local bool _bStartedBuild;
7790
local STRUCTURE _factory;
7791
local TEMPLATE _bestTankATTemplate;
7793
//dbg(" " & me & ") Executing buildTanks()");
7797
/* decide if want to use heavy templates */
7799
// TODO: fix heavy templates
7800
// if((playerPower(me) > muchoPower) and !defendingBase())
7805
//Calculate how many commanders we have and how many are being built
7806
_numTotalCommanders = getNumCommanders() + numCommandersInProduction();
7808
// calc how many repairers we still need
7809
_needTotalRepairers = numNeedRepairers();
7812
initEnumStruct(FALSE,fac,me,me);
7813
_factory = enumStruct();
7814
while(_factory != NULLOBJECT)
7816
if(structureComplete(_factory))
7818
_facNum = _facNum + 1; //'id' of fac
7820
if(structureIdle(_factory))
7822
_bStartedBuild = FALSE;
7824
/* Build commanders */
7825
if(!_bStartedBuild and bCanUseCommanders and
7826
(_numTotalCommanders < MAX_COMMANDERS))
7828
// if( !defendingBase() )
7830
/* Calculate how many commanders we need */
7831
_numDroidsNoCmd = max(0, totalWeapUnits() - getTotalCmdsCapacity(NULLOBJECT, true)); //num of droids without commander or 0
7833
// droids need a new commander if there are more than _minUnassignedDroids of them
7834
_minUnassignedDroids = 4;
7835
if( defendingBase() ){
7836
_minUnassignedDroids = CMD_INIT_CAPACITY;
7839
// calculate how many commanders we need
7840
_numNeedCmds = (_numDroidsNoCmd + CMD_INIT_CAPACITY - _minUnassignedDroids) / CMD_INIT_CAPACITY;
7842
//if some droids left without commanders (droid need a new commander if there are more than (CMD_INIT_CAPACITY / 2) of them)
7843
// if( modulo( max(0, _numDroidsNoCmd - (CMD_INIT_CAPACITY / 2)) , CMD_INIT_CAPACITY) > 0 )
7848
dbg("need " & _numNeedCmds & " commanders for " & _numDroidsNoCmd & " droids", me);
7850
if((_numNeedCmds > 0) and ( (_numTotalCommanders + _numNeedCmds) < MAX_COMMANDERS))
7852
//Find best commander template
7854
_result = numCmdTmpl;
7855
while((_result > 0) and (_result2 == 0))
7858
if(skCanBuildTemplate(me,_factory, tmplCmd[_result]))
7860
tmplOK[_result2] = tmplCmd[_result];
7865
if(_result2 > 0) //found a template to build
7867
_bStartedBuild = TRUE;
7868
buildDroid(tmplOK[0], _factory, me, 1);
7869
_numTotalCommanders++;
7876
//------------------
7877
if(!_bStartedBuild and haveBB and (groupSizeCmds(defendGr,true,false,true)
7878
>= (numDefenders + 4))) //BB researched and not low on tanks
7880
if(!lowMilitary and !alert and !defendingBase())
7882
_result = numBBsInProduction(me); //how many already building
7883
if(_result < 1) //not too many already
7885
_result = _result + numDroidsByComponent(weaponBB, me, me); //num BBs
7887
_needBBs = min(numBB, numAvailableAttackers() / 9 - _result); //1 bb for 9 droids
7889
if(_needBBs > 0) //not too many
7891
//Find best BB template
7893
_result = numBBTempl;
7894
while((_result > 0) and (_result2 == 0))
7897
if(skCanBuildTemplate(me, _factory, tmplBB[_result]))
7899
tmplOK[_result2] = tmplBB[_result];
7904
if(_result2 > 0) //found a template to build
7906
_bStartedBuild = TRUE;
7907
buildDroid(tmplOK[0], _factory, me, 1);
7915
//Build repair units for defenders and commanders
7916
//--------------------------------------------------------
7917
if(!_bStartedBuild and playerPower(me) >= highPower) //don't build expensive repairs if low on power
7919
// make facs pump tanks to prevent rush at the beginning of the game
7922
// if need repairers, build one at a time
7923
if((_needTotalRepairers > 0) and (numNonCybRepairsInProd() == 0))
7925
_result = numRepairTmpl - 1;
7926
while(!_bStartedBuild and (_result >= 0))
7928
if(skCanBuildTemplate(me, _factory, tmplRep[_result]))
7930
_bStartedBuild = true;
7931
_needTotalRepairers--;
7932
buildDroid(tmplRep[_result], _factory, me, 1);
7941
//Build attack units
7942
//--------------------
7943
if(not _bStartedBuild) //didn't start building BB or repair unit
7945
// get max template size a factory cab build
7946
_maxBodySize = skGetFactoryCapacity(_factory);
7948
// find best anti-tank template
7949
_bestTankATTemplate = getBestTankATTemplate(_maxBodySize);
7951
if(_bestTankATTemplate != NULLTEMPLATE)
7953
if(skCanBuildTemplate(me, _factory, _bestTankATTemplate))
7955
_bStartedBuild = TRUE;
7956
buildDroid(_bestTankATTemplate, _factory, me, 1);
7960
ASSERT(false, "buildTanks(): factory with size " &
7961
_maxBodySize & " can't build template", me);
7966
dbg("found no tank template to build", me);
7971
/* build tanks only in first 3 factories (-trucks) if alert of non-military type */
7972
if(( (_facNum - numBuildersInProduction(me)) >= 3) and
7973
(alert and (not lowMilitary)))
7978
_factory = enumStruct();
7981
// Build cyborg mechanicsif we are still low on repairers
7982
initEnumStruct(false,cybfac,me,me);
7983
_factory = enumStruct();
7984
while((_factory != NULLOBJECT) and (_needTotalRepairers > 0))
7986
if(structureComplete(_factory))
7988
if(structureIdle(_factory))
7990
//Try to build a mechanic
7991
if( skCanBuildTemplate(me,_factory, cybMechanic) )
7993
buildDroid(cybMechanic, _factory, me, 1);
7994
_needTotalRepairers++;
7998
_factory = enumStruct();
8002
initEnumStruct(false,cybfac,me,me);
8003
_factory = enumStruct();
8004
while(_factory != NULLOBJECT)
8006
// make sure we won't build too many of them
8007
if( (numDroidsByType(me, DROID_CYBORG) + numDroidsByType(me, DROID_CYBORG_SUPER)) < maxAttackCyborgs)
8009
if( structureIdle(_factory) )
8011
cybFactorBuildCyborg(_factory);
8014
_factory = enumStruct();
8017
//dbg(" " & me & ") End buildTanks()");
8020
function int numDroidsByType(int _player, int _droidType)
8022
local int _numDroids;
8025
InitEnumDroids(_player,me);
8026
_droid = EnumDroid();
8027
while(_droid != NULLOBJECT)
8029
if(_droid.droidType == _droidType)
8033
_droid = EnumDroid();
8039
function void cybFactorBuildCyborg(STRUCTURE _factory)
8041
local int _tmplIndex,_tmplChosenIndex;
8043
if(_factory == NULLOBJECT){
8044
dbg("cybFactorBuildCyborg: factory is NULLOBJECT", me);
8048
_tmplIndex = numLightCyborgs - 1;
8049
_tmplChosenIndex = 0;
8050
while( (_tmplIndex >= 0) and (_tmplChosenIndex < MAX_CHOICE_LIGHT_CYB) )
8052
if( skCanBuildTemplate(me,_factory, cybTempl[_tmplIndex]) )
8054
tmplOK[_tmplChosenIndex] = cybTempl[_tmplIndex];
8059
if(_tmplChosenIndex > 0)
8061
buildDroid(tmplOK[random(_tmplChosenIndex)], _factory, me, 1);
8066
// calculate how many repairers we still need
8067
function int numNeedRepairers()
8069
local int _needCmdRepairers,_numDefendRepairers,_needDefendRepairers,
8070
_numRepInProd,_needTotalRepairers;
8073
_needCmdRepairers = 0;
8074
if(bCanUseCommanders){
8075
_needCmdRepairers = numMissingCmdRepairers(-1, false);
8078
_numDefendRepairers = groupSizeCmds(defendRepairGr,true,false,true);
8080
//1 rep for 4 defenders, cap at "maxDefendRepairers"
8081
_needDefendRepairers = min(maxDefendRepairers,
8082
(groupSizeCmds(defendGr,true,false,false) / NUM_DEFENDERS_PER_REPAIRER)
8083
- _numDefendRepairers);
8085
if(_needDefendRepairers < 0){
8086
_needDefendRepairers = 0;
8089
_numRepInProd = totalRepairersInProduction();
8091
// calc how many we still need
8092
_needTotalRepairers = _needCmdRepairers + _needDefendRepairers - _numRepInProd;
8094
return _needTotalRepairers;
8097
function void buildVTOLs()
8099
if(getDroidCount(me) >= unitLimit)
8105
/* decide if want to use heavy templates */
8107
//if((playerPower(me) > muchoPower) and (state != stDefendingBase))
8112
initEnumStruct(FALSE,vtolfac,me,me);
8113
structure = enumStruct();
8114
while(structure != NULLOBJECT)
8116
if(structureComplete(structure))
8118
count = count + 1; //'id' of fac
8120
if(structureIdle(structure))
8123
//Build attack units
8124
//-------------------
8125
//if(not bResult) //didn't start building BB or repair unit
8127
//Find best available templates
8128
result = numVtolTemplates;
8130
while((result > 0) and (result2 < 2)) //2 best tmplates
8132
result = result - 1;
8133
if(skCanBuildTemplate(me,structure, vtoltmpl[count3][result]))
8135
tmplOK[result2] = vtoltmpl[count3][result];
8136
result2 = result2 + 1;
8140
if(result2 > 0) //found a template to build
8142
buildDroid(tmplOK[random(result2)], structure, me, 1);
8147
/* build vtols only in first 3 factories, if alert of non-military type */
8148
if((count >= 3) and (alert and (not lowMilitary)))
8153
structure = enumStruct();
8158
//����������������������������������������������������������������������������������������������
8160
//����������������������������������������������������������������������������������������������
8162
function int totalRepairersInProduction()
8164
local int _numRepairers;
8167
_numRepairers = numNonCybRepairsInProd() + numCybRepairsInProd();
8169
return _numRepairers;
8172
function int numCybRepairsInProd()
8174
local int _numRepairers;
8179
_numRepairers = numTemplatesInProduction(cybMechanic,me); //mechanics
8181
return _numRepairers;
8184
function int numNonCybRepairsInProd()
8186
local int _repTmplIndex,_numRepairers;
8191
// wheeled, tracked repairs
8192
while(_repTmplIndex < numRepairTmpl)
8194
_numRepairers = _numRepairers + numTemplatesInProduction(tmplRep[_repTmplIndex],me);
8198
return _numRepairers;
8201
//how many trucks are building defenses
8202
function int numBuildingDefenses()
8204
//return - number of busy trucks
8206
temp2 = 0; //How many are ordered to build a defense
8208
while(temp < numDef)
8210
if(isStructureAvailable(def[temp],me))
8212
temp3 = numStatBusy(def[temp], TRUE); //How many going to build it
8213
temp2 = temp2 + temp3;
8222
function int numBuildingBaseDefenses()
8226
//return - number of busy trucks
8228
temp2 = 0; //How many are ordered to build a defense
8230
while(temp < numDef)
8232
if(isStructureAvailable(def[temp],me))
8235
_bucket = initIterateGroupCmd(buildGr,true,false,true);
8236
tempDroid = iterateGroupCmd(buildGr,_bucket);
8237
while(tempDroid != NULLOBJECT)
8239
if(tempDroid.order == DORDER_BUILD)
8241
if(tempDroid.stat == def[temp]) //going to build it
8243
if(distBetweenTwoPoints(tempDroid.orderx, tempDroid.ordery, baseX, baseY) <= (baseRange + defendCorridor)) //within base
8249
tempDroid = iterateGroupCmd(buildGr,_bucket);
8253
temp2 = temp2 + temp3;
8262
function int numBuildingNoBaseDefenses()
8264
local int _bucket,_numBuildingDef,_defTypeIndex,_nonBaseDef;
8267
//return - number of busy trucks
8269
_numBuildingDef = 0; //How many are ordered to build a defense
8271
while(_defTypeIndex < numDef)
8273
if(isStructureAvailable(def[_defTypeIndex],me))
8276
_bucket = initIterateGroupCmd(buildGr,true,false,true);
8277
_truck = iterateGroupCmd(buildGr,_bucket);
8278
while(_truck != NULLOBJECT)
8280
if(_truck.order == DORDER_BUILD)
8282
if(_truck.stat == def[_defTypeIndex]) //going to build it
8284
if(distBetweenTwoPoints(_truck.orderx, _truck.ordery, baseX, baseY) > (baseRange + defendCorridor)) //not within base
8290
_truck = iterateGroupCmd(buildGr,_bucket);
8294
_numBuildingDef = _numBuildingDef + _nonBaseDef;
8300
return(_numBuildingDef);
8303
function DROID closestIdleTruck(int _x, int _y)
8305
local DROID _closestTruck,_tempTruck;
8306
local int _closestDist,_tempDist,_bucket;
8308
_closestTruck = NULLOBJECT;
8309
_closestDist = 99999;
8311
_bucket = initIterateGroupCmd(buildGr,true,false,true);
8312
_tempTruck = iterateGroupCmd(buildGr,_bucket);
8313
while(_tempTruck != NULLOBJECT)
8315
if(droidOrderIdle(_tempTruck))
8317
_tempDist = distBetweenTwoPoints(_x, _y, _tempTruck.x, _tempTruck.y);
8318
if(_tempDist < _closestDist)
8320
_closestDist = _tempDist;
8321
_closestTruck = _tempTruck;
8324
_tempTruck = iterateGroupCmd(buildGr,_bucket);
8327
return _closestTruck;
8330
//------------------------------------------------
8331
//Build some defenses on startup to prevent rushes
8332
//------------------------------------------------
8333
function void buildInitialDefenses(bool _bForceBuild) //returns TRUE if finished
8335
//_bForceBuild - if returned from callback, truck order is not reste to DORDER_NONE yet, but it's idle
8337
if(not bLearn){return;} //only uses learn data so far
8338
if(defendingBase()){return;} //don't waste power
8340
/* if no builder, find one */
8341
if(initialDefensesTruck == NULLOBJECT)
8343
if(groupSizeCmds(buildGr,true,false,true) >= 5) //don't take away any trucks if low on them
8345
initialDefensesTruck = closestIdleTruck(baseX, baseY);
8349
if(initialDefensesTruck == NULLOBJECT)
8351
//dbg("buildInitialDefenses() - no truck", me);
8352
return; //try again later
8355
if((initialDefensesTruck.order != DORDER_NONE) and (not _bForceBuild))
8357
//dbg("buildInitialDefenses() - truck busy", me);
8358
return; //try again later
8361
range = BASE_DEFENSES_RANGE; //"too-many-built-in-range" range
8362
best = none; //Best defense
8364
/* find best defense */
8365
best = findBestDefense();
8366
if(best == none){return;} //No defenses researched
8368
//Now iterate through the stored locations
8369
//----------------------------------------
8370
result2 = getBaseDefendLocCount(); //how many locations there are stored (max)
8372
while(curInitialBaseDef <= maxInitialBaseDef)
8374
count = 0; //start from the first stored location again
8376
while((count < result2) and (count < maxInitialDefSites)) //don't build at more than maxInitialDefSites in total
8378
if(recallBaseDefendLoc(me, count, ref x, ref y, ref result3)) //TRUE if stored
8380
if(result3 > 0) //attacked atleast 1 time (highest priority is always at the top)
8382
//move coords closer to base
8383
circlePerimPoint(baseX, baseY, ref x, ref y, (baseRange + defendCorridor / 2)); //move locations to the base perimeter
8385
buildX = x; //remember coords before using pickStructLocation() to check if corrected coords too far away
8388
//count if not too many built on this site already (using corrected coords!)
8389
if(numFriendlyWeapStructsInRange(me, buildX, buildY, range, false) < curInitialBaseDef) //don't build too many
8391
if(pickStructLocation(def[best], ref buildX, ref buildY, me))
8393
//don't allow to build outside of the range
8394
if(distBetweenTwoPoints(buildX, buildY, x, y) < range) //coords corrected with pickStructLocation() not too far away from orig
8396
orderDroidStatsLoc(initialDefensesTruck, DORDER_BUILD, def[best], buildX, buildY);
8398
//dbg("buildInitialDefenses() - started", me);
8400
return; /* this one successfull, try again next time */
8408
curInitialBaseDef = curInitialBaseDef + 1; /* finished this round, rise defenses number per site and start over again if not finished */
8409
dbg("buildInitialDefenses() - RAISED curInitialBaseDef", me);
8413
//stopInitialDefenses();
8417
function void stopInitialDefenses()
8419
/* finished for real: no open sites with no defenses left, stop the whole process */
8420
initialDefensesFinished = true;
8421
dbg("buildInitialDefenses() - FINISHED", me);
8423
/* add builder back to the buildGr if finished */
8424
if(initialDefensesTruck != NULLOBJECT)
8426
dbg("buildInitialDefenses() - ADDED BACK THE TRUCK", me);
8427
groupAddDroid(buildGr, initialDefensesTruck);
8428
initialDefensesTruck = NULLOBJECT;
8432
function void buildBaseDefenses()
8434
local bool _buildStarted;
8436
//dbg(" " & me & ") buildBaseDefenses()");
8438
if(not bLearn){exit;}
8439
if(idleGroupCmd(buildGr,true,false) == 0){exit;}
8441
//MsgBox("buildBaseDefenses()");
8443
best = none; //Best defense
8445
//How many are ordered to build a defense?
8446
result = numBuildingBaseDefenses();
8447
if(result >= maxBaseDefenseTrucks){exit;} //Not too many busy with defenses already
8449
/* find best defense */
8450
best = findBestDefense();
8451
if(best == none){exit;} //No defenses researched
8453
bResult = FALSE; //started to build anything?
8455
//Now iterate through the stored locations
8456
//---------------------------------------
8457
result2 = getBaseDefendLocCount(); //how many locations there are stored (max)
8460
//look at maxBaseDefenseLoc defend locs nad pick MAX_BASE_DEFENSE_LOCATIONS best ones
8462
while((count < result2) and (count4 < MAX_BASE_DEFENSE_LOCATIONS) and
8463
(count < maxBaseDefenseLoc))
8465
if(recallBaseDefendLoc(me, count, ref x, ref y, ref result3)) //TRUE if stored
8467
if(result3 > MIN_BASE_RECALL_PRIORITY) //at least priority of MIN_BASE_RECALL_PRIORITY + 1
8469
//move coords closer to base
8470
circlePerimPoint(baseX, baseY, ref x, ref y, (baseRange + defendCorridor / 2)); //move locations to the base perimeter
8472
buildX = x; //remember coords before using pickStructLocation() to check if corrected coords too far away
8475
//count if not too many built on this site already (using corrected coords!)
8476
//if(numStructsByTypeInRange(me, me, REF_DEFENSE, buildX, buildY, range) < numBaseDef) //max
8477
if(numFriendlyWeapStructsInRange(me, buildX, buildY, BASE_DEFENSES_RANGE, false) < numBaseDef)
8479
if(pickStructLocation(def[best], ref buildX, ref buildY, me))
8481
//don't allow to build outside of the range
8482
if(distBetweenTwoPoints(buildX, buildY, x, y) < BASE_DEFENSES_RANGE) //coords corrected with pickStructLocation() not too far away from orig
8484
//Make sure not too many building already
8485
//--------------------------------------------
8486
retInt = numTrucksOrderInRange(buildX, buildY, BASE_DEFENSES_RANGE, DORDER_BUILD);
8488
if(retInt < maxBaseDefendDefLocTrucks)
8490
intOK[count4] = count;
8491
count4 = count4 + 1; //picked another one
8501
if(count4 == 0){exit;} //couldn't recall any locations
8503
//Choose a random site
8504
//--------------------------------------------
8505
result = intOK[random(count4 - 1)];
8507
//dbg(" " & me & ") defendDefenses() - building defense at location #" & result & " !!!!!!!!!!!!");
8509
recallBaseDefendLoc(me, result, ref x, ref y, ref temp2);
8511
//move coords closer to base
8512
circlePerimPoint(baseX, baseY, ref x, ref y, (baseRange + defendCorridor / 2));
8514
buildX = x; //remember coords before using pickStructLocation() to check if corrected coords too far away
8517
if(pickStructLocation(def[best], ref buildX, ref buildY, me))
8519
//don't allow to build outside of the range
8520
if(distBetweenTwoPoints(buildX, buildY, x, y) < BASE_DEFENSES_RANGE) //coords corrected with pickStructLocation() not too far away from orig
8522
_buildStarted = buildUsingClosestTruck(def[best], buildX, buildY, 1);
8526
bResult = TRUE; //Build successfull
8528
tLastBaseDefense = GAME_TIME_IN_SECS;
8530
//dbg(" " & me & ") building on base defense location # " & result & " !!!!!");
8531
//if((result + count3) >= 5){exit;} //Not too many busy with defenses already
8536
//dbg(" " & me & ") * buildBaseDefenses()");
8539
function int numDefenses()
8543
while(temp < numDef)
8545
retInt = retInt + getNumStructures(def[temp],me);
8552
function int numBaseDefenses()
8556
while(temp < numDef)
8558
initEnumStruct(FALSE,def[temp],me,me);
8559
tempStruct = enumStruct();
8560
while(tempStruct != NULLOBJECT)
8562
if((tempStruct.x < maxx) and (tempStruct.x > minx))
8564
if((tempStruct.y < maxy) and (tempStruct.y > miny))
8566
retInt = retInt + 1;
8569
tempStruct = enumStruct();
8579
event objectAttacked(inactive)
8581
local int _bucket,_defendersWeaponRange,_maxReachRange;
8584
if(obj == NULLOBJECT){exit;}
8585
if(obj2 == NULLOBJECT){exit;}
8587
if(obj.player == obj2.player){exit;}
8589
attacked[obj2.player] = attacked[obj2.player] + 1; //remember how many times attacked by him
8591
//check if attacked object is in the base
8592
//---------------------------------------
8593
if(distBetweenTwoPoints(baseX, baseY, obj.x, obj.y) < (baseRange + defendCorridor)) //baseRange + corridor where defenders can stay
8595
// if this weapon has a big range
8596
//if(objectHasIndirectWeapon(obj2) and (obj2.longRange > (TILE * 9)))
8598
// check if attacked by a vtol
8600
if(obj2.type == OBJ_DROID)
8602
if(isVtol(objToDroid(obj2)))
8611
_defendersWeaponRange = TILE * 10; //longer than lancer
8612
_maxReachRange = baseRange + defendCorridor + _defendersWeaponRange;
8614
// make sure we can't reach the enemy by staying inside the defence radius
8615
// even if it's not arty
8616
if(distBetweenTwoPoints(obj2.x, obj2.y, baseX, baseY) > _maxReachRange)
8618
dbg("attacked by long-range weapon in the base", me);
8620
if(!isNearEnemyBase(obj2.x, obj2.y)) // enemy arty could be too heavily defended
8622
if(canStartArtyCouterAttack(obj2.player, obj2.x, obj2.y))
8624
// make sure not doing anything important
8625
if(!defendingBase() and !counteringArty())
8627
// stop what we were doing, if anything
8632
//TODO: take out arty sensors with VTOLs
8634
startArtyCounterAttack(obj2.player, obj2.x, obj2.y);
8636
dbg("attacking arty", me);
8640
// request help if for some reason we couldn't defend ourself against arty
8641
if(!counteringArty())
8643
// stop what we were doing, if anything unimportant
8644
if(!idling() and !defendingBase())
8649
if(canRequestHelp())
8651
// we have not enough firepower, request help
8652
requestHelp(obj2.x, obj2.y);
8654
dbg("requested help because of arty", me);
8660
// start attacking attacker's base if can
8663
if(canStartAttack(obj2.player))
8665
startEnemyBaseAttack(obj2.player);
8666
requestStartAttack(obj2.player, curBase[obj2.player][0], curBase[obj2.player][1]);
8674
if(obj2.type == OBJ_DROID) //attacker is a droid
8676
if(!_bVtol) //not vtol
8680
storeBaseDefLocEv();
8683
else /* check if we have to build some AAs asap */
8685
if(knowBase[obj2.player])
8687
exit; //other routine does it in this case
8692
range = INBASE_AA_DEF_MAX_RANGE; //too many on spot range
8694
if(numAAinRange(me, me, x, y, range) >= MAX_INBASE_AA_DEF)
8699
best = findBestAA();
8700
if(best == none){exit;}
8702
buildX = x; buildY = y;
8703
/* make sure we can build and won't be built too far away from orig loc */
8704
if(!pickStructLocation(AA[best], ref buildX, ref buildY, me))
8709
if(distBetweenTwoPoints(buildX, buildY, x, y) > range) //build loc moved too far away
8711
exit; //original site was probably blocked, don't build too far away from orig site
8714
dbg("building AA defense, since don't see attacker's base", me);
8717
buildOnMap(AA[best], buildX, buildY, 2);
8721
else //outside of the base
8723
/* learn oil defense location */
8724
//result = isNearOil(obj.x, obj.y);
8726
if(isNearOil(obj.x, obj.y))
8733
// decide if we have to defend oil derrick
8734
dealWithOilAttacked(obj.x, obj.y);
8738
/* check if we can take them down easily, even outside of the base */
8739
if(obj2.type == OBJ_DROID) //attacker is a droid
8741
if(isVtol(objToDroid(obj2))) //vtol
8747
range = baseRange * 3 / 2; //1.5
8748
if(objectHasIndirectWeapon(obj2))
8750
range = baseRange * 2; //can be further away
8753
// if(distBetweenTwoPoints(baseX, baseY, obj2.x, obj2.y) < range) //not too far
8755
// if(numEnemyWeapObjInRange(me, obj2.x, obj2.y, (6 * 128), false, true) < (groupSizeCmds(defendGr,true,false,true) - 1)) //safe
8758
// baseDefendObj = obj2;
8760
// /* attack with idle defenders */
8761
// _bucket = initIterateGroupCmd(defendGr,true,true,true);
8762
// droid = iterateGroupCmd(defendGr,_bucket);
8763
// while(droid != NULLOBJECT)
8765
// if((droid.order != DORDER_ATTACK) and (droid.order != DORDER_EMBARK))
8767
// orderDroidObj(droid, DORDER_ATTACK, baseDefendObj); //attack enemy
8769
// droid = iterateGroupCmd(defendGr,_bucket);
8775
event droidAttacked(inactive)
8777
if(droid.player != me)
8780
/* Make defenders retreat if heavily damaged to save units */
8781
if(groupMember(defendGr, droid))
8783
if(droid.health < 45)
8785
if(distBetweenTwoPoints(baseX, baseY, droid.x, droid.y) > baseRange)
8787
if(defendGr.health > 50) //wouldn't make sense if all half-dead
8791
circlePerimPoint(baseX, baseY, ref x, ref y, baseRange - (2 * 128)); //retreat behind defense lines
8792
orderDroidLoc(droid, DORDER_MOVE, x, y);
8799
//-----------------------------------------------------------
8800
//Structure attacked CALLBACK
8801
//-----------------------------------------------------------
8802
event structureAttacked(inactive)
8804
local int _maxRepairers;
8808
if(structure != NULLOBJECT)
8810
/* recycle structure if will be dead with the next shot anyway */
8811
if(lowOnPower() and (structure.health <= structNoLiveHealth)) //Doesn't make sense if we've got alot of power though
8813
/* See if any track is working on this structure */
8814
_truck = getTruckByTarget(structure);
8815
if(_truck != NULLOBJECT)
8817
/* Order to recycle */
8818
dbg("demolishing structure", me);
8819
orderDroidObj(_truck, DORDER_DEMOLISH, structure);
8824
/* Repair damaged structure */
8828
if(distBetweenTwoPoints(baseX, baseY, structure.x, structure.y) < (baseRange + (8 * 128)))
8832
_maxRepairers = 2; //use more trucks for base structures
8835
if(not((not bResult) and (alert))) //don't repair if low on power and not a base structure
8837
retInt = repairStructure(structure, _maxRepairers);
8843
/* returns TRUE if we don't have much spare ower */
8844
function bool lowOnPower()
8846
if(playerPower(me) < highPower)
8852
//---------------------------------------------------------
8853
// Returns true if location is near a derrick or oil resource
8854
//---------------------------------------------------------
8855
function bool isNearOil(int _x, int _y)
8858
local STRUCTURE _derrick;
8861
_range = (6 * 128); //near oil range
8864
initEnumStruct(false,derrick,me,me);
8865
_derrick = enumStruct();
8866
while(_derrick != NULLOBJECT)
8868
if(distBetweenTwoPoints(_x, _y, _derrick.x, _derrick.y) < _range) //close to a derrick
8873
_derrick = enumStruct();
8876
// check oil resources
8877
initGetFeature(oilRes,me,me);
8878
_oil = getFeatureB(me);
8879
while(_oil != NULLOBJECT)
8881
if(distBetweenTwoPoints(_x, _y, _oil.x, _oil.y) < _range) //close to a derrick
8885
_oil = getFeatureB(me);
8891
//-----------------------------------------------------------
8892
//Check all damaged structures and repair them
8893
//-----------------------------------------------------------
8894
function void repairStructures()
8896
if(idleGroupCmd(buildGr,true,false) == 0)
8899
//How many already repairing
8900
result = numTrucksSameOrder(DORDER_REPAIR);
8902
result3 = 5; //max repairers
8904
if(result >= result3)
8908
structure2 = NULLOBJECT;
8909
range = 90; //repair if below
8911
//check base structures first
8912
//----------------------------
8914
while(count < numBaseStructs)
8916
initEnumStruct(FALSE,baseStructs[count],me,me);
8917
structure = enumStruct();
8918
while(structure != NULLOBJECT)
8920
if(structure.health < range)
8922
result2 = repairStructure(structure, 3); //use 3 trucks max
8924
result = result + result2; //one more busy?
8926
if(result >= result3){exit;} //exit if too many busy
8928
structure = enumStruct();
8933
//now check all other structures
8934
//---------------------------------
8935
initEnumStruct(TRUE,fac,me,me);
8936
structure = enumStruct();
8937
while(structure != NULLOBJECT)
8939
if(structure.health < range)
8941
result2 = repairStructure(structure, 1); //use 1 truck max
8943
result = result + result2; //one more busy?
8945
if(result >= result3){exit;} //exit if too many busy
8947
structure = enumStruct();
8951
function int repairStructure(STRUCTURE _damagedStruct, int _maxRepairers)
8953
//Make sure not too many repairing already
8954
//----------------------------------------
8955
temp2 = numTrucksSameOrderLoc(_damagedStruct.x, _damagedStruct.y, DORDER_REPAIR);
8957
if(temp2 < _maxRepairers) //not too many already
8959
//Find closest idle truck
8960
//---------------------------------------
8961
tempDroid = closestIdleTruck(_damagedStruct.x, _damagedStruct.y);
8963
if(tempDroid != NULLOBJECT)
8965
if(distBetweenTwoPoints(tempDroid.x, tempDroid.y, _damagedStruct.x, _damagedStruct.y) < (25 * 128)) //not too far
8967
//don't repair if outside of the base and dangerous
8968
if(not((not isInMyBase(_damagedStruct.x, _damagedStruct.y)) and (threatInRange(me, _damagedStruct.x, _damagedStruct.y, threatRange, FALSE)) ) )
8970
orderDroidObj(tempDroid, DORDER_REPAIR, _damagedStruct);
8980
//����������������������������������������������������������������������������������������������
8982
//����������������������������������������������������������������������������������������������
8983
event doScout(inactive)
8987
//dbg(" " & me & ") doScout()");
8988
if(idleGroupCmd(scoutGr,true,true) == 0){exit;}
8990
_bucket = initIterateGroupCmd(scoutGr,true,true,false); // find all units in scout group.
8991
droid = iterateGroupCmd(scoutGr,_bucket);
8992
while(droid != NULLOBJECT)
8994
//dbg(" " & me & ") doScout() - droid.orderx: " & droid.orderx & ", droid.ordery: " & droid.ordery);
8996
if( (distBetweenTwoPoints(droid.x, droid.y, droid.orderx, droid.ordery) < 384) or (scoutX <= 0) or droidOrderIdle(droid) ) //Some of them reached destination or first time
8998
//dbg(" " & me & ") doScout() - setting new scouting destination (**********)");
9000
//find next closest unrevealed tile (into buildX and buildY)
9001
//bResult = fogTileInRange(ref buildX, ref buildY, droid.x, droid.y, baseX, baseY, scoutRange, me);
9002
bResult = fogTileInRange(ref buildX, ref buildY, droid.x, droid.y, baseX, baseY, -1, me, threatRange);
9004
//bResult = fogTileInRange(ref buildX, ref buildY, 33, 44, 55, 66, 77, 88);
9009
//dbg(" " & me & ") doScout() - failed to find scout loc (**********)");
9011
//scoutRange = scoutRange + scoutStep; //and try next time
9013
//see if whole map revealed
9014
//if( ((scoutRange / 128) > mapWidth) and ((scoutRange / 128) > mapHeight))
9016
dbg("doScout() - STOP SCOUTING, MAP REVEALED (!!!!!!!!!!!!!)", me);
9018
//fMapRevealFactor = MAP_REVEAL_FAC_UBOUND;
9020
groupAddGroupCmd(defendGr, scoutGr);
9021
setEventTrigger(doScout, inactive); //stop scouting
9026
//dbg(" " & me & ") doScout() x: " & (droid.x/128) & ", y: " & (droid.x/128) & "newx: " & (buildX/128) & "newy :" & (buildY/128));
9031
orderDroidLoc(droid, DORDER_MOVE, scoutX, scoutY);
9035
droid = iterateGroupCmd(scoutGr,_bucket);
9038
//dbg(" " & me & ") * doScout()");
9041
event scoutForEnemy(inactive)
9045
//dbg(" " & me & ") scoutForEnemy()");
9047
// only scout if the group is full, otherwise will lose units too quickly
9048
/* if(groupSizeCmds(enemyScoutGr,true,false,true) < maxEnemyScouts){
9052
bResult = FALSE; //no idle scouts
9054
// most of the group is idle
9055
if(idleGroupCmd(enemyScoutGr,true,false) > (groupSizeCmds(enemyScoutGr,true,false,true)) / 2){
9059
// see if reached destination already
9062
// count how many scouts have reached destination points
9063
_bucket = initIterateGroupCmd(enemyScoutGr,true,true,false); // find all units in group
9064
droid = iterateGroupCmd(enemyScoutGr,_bucket);
9065
while(droid != NULLOBJECT)
9067
if((distBetweenTwoPoints(droid.x, droid.y, droid.orderx, droid.ordery) < 384)) //Some of them reached destination
9069
//dbg(" " & me & ") scout reached");
9072
droid = iterateGroupCmd(enemyScoutGr,_bucket);
9076
if(not bResult){exit;}
9079
if((enemyScoutX > 0) and (enemyScoutY > 0))
9081
//find a valid spot we can send droid to
9082
//bResult = fogTileInRange(ref x, ref y, enemyScoutX, enemyScoutY, enemyScoutX, enemyScoutY, -1, me);
9083
bResult = chooseValidLoc(ref realEnemyScoutX, ref realEnemyScoutY,
9084
enemyScoutX, enemyScoutY, me, (11 * 128));
9088
dbg("couldn't send enemy scouts to " & enemyScoutX & ", " & enemyScoutY, me);
9092
realEnemyScoutX = 0;
9093
realEnemyScoutY = 0;
9095
//fMapRevealFactor = MAP_REVEAL_FAC_UBOUND;
9097
groupAddGroupCmd(defendGr, enemyScoutGr);
9098
setEventTrigger(scoutForEnemy, inactive); //deactivate
9102
orderGroupLocCmd(enemyScoutGr, DORDER_MOVE, realEnemyScoutX, realEnemyScoutY);
9103
//dbg(" " & me & ") sending enemy scout to: " & x & ", " & y);
9109
dbg("scoutForEnemy() - no valid coords", me);
9113
//find coords for the next time
9114
//--------------------------------------
9115
count = 0; //times tried
9117
if((enemyScoutX > 0) and (enemyScoutY > 0))
9119
realEnemyScoutX = enemyScoutX;
9120
realEnemyScoutY = enemyScoutY;
9124
realEnemyScoutX = baseX;
9125
realEnemyScoutY = baseY;
9128
bResult = TRUE; //revealed
9129
while(bResult and (count < 200)) //until finds a not revealed loc
9131
getNextScoutCoord(realEnemyScoutX, realEnemyScoutY); //Sets enemyScoutX and Y vars
9132
realEnemyScoutX = enemyScoutX;
9133
realEnemyScoutY = enemyScoutY;
9135
// only go there if not already revealed and no threat around
9136
bResult = mapRevealedInRange(realEnemyScoutX, realEnemyScoutY,
9137
enemyScoutRange, me) or //check if has already visited this area
9138
threatInRange(me, realEnemyScoutX, realEnemyScoutY, (TILE * 10), FALSE);
9143
if(bResult) //no new coords found
9145
dbg("couldn't find next spot after: " & enemyScoutX & ", " & enemyScoutY, me);
9149
groupAddGroupCmd(defendGr, enemyScoutGr);
9150
setEventTrigger(scoutForEnemy, inactive); //deactivate
9154
// dbg(" " & me & ") found new enemy scout coords");
9158
function void getNextScoutCoord(int _lastX, int _lastY)
9160
temp = (9 * 128); //border offset
9165
if(bEnemyScoutHor) //horizontal - main direction
9167
if(bEnemyScoutToRight)
9169
tempX = tempX + enemyScoutStep;
9171
//check if unit too close to hor edge already
9172
if(tempX > ((mapWidth * 128) - temp)) //too close to edge
9174
//dbg(" " & me & ") ----reached right edge");
9176
tempX = ((mapWidth * 128) - temp);
9177
bEnemyScoutToRight = FALSE;
9179
//have to skip a vert line now
9181
if(not bEnemyScoutToBottom) //going to top
9183
tempY = tempY - enemyScoutStep;
9185
//check vertical edge now
9186
if(tempY < temp) //reached top
9188
//dbg(" " & me & ") ----reached top edge");
9190
bEnemyScoutToBottom = TRUE;
9193
else //going to bottom
9195
tempY = tempY + enemyScoutStep;
9196
//check vertical edge now
9197
if(tempY > ((mapHeight * 128) - temp)) //reached bottom
9199
//dbg(" " & me & ") ----reached bottom edge");
9200
tempY = ((mapHeight * 128) - temp);
9201
bEnemyScoutToBottom = FALSE;
9210
tempX = tempX - enemyScoutStep;
9212
//check if unit too close to hor edge already
9213
if(tempX < temp) //too close to edge
9215
//dbg(" " & me & ") ----reached left edge");
9217
bEnemyScoutToRight = TRUE; //change dir next time
9219
//have to skip a vert line now
9221
if(not bEnemyScoutToBottom) //going to top
9223
tempY = tempY - enemyScoutStep;
9225
//check vertical edge now
9226
if(tempY < temp) //reached top
9228
//dbg(" " & me & ") ----reached top edge");
9230
bEnemyScoutToBottom = TRUE;
9233
else //going to bottom
9235
tempY = tempY + enemyScoutStep;
9236
//check vertical edge now
9237
if(tempY > ((mapHeight * 128) - temp)) //reached bottom
9239
//dbg(" " & me & ") ----reached bottom edge");
9240
tempY = (mapHeight * 128) - temp;
9241
bEnemyScoutToBottom = FALSE;
9247
else //main dir = vert
9249
if(bEnemyScoutToBottom)
9251
tempY = tempY + enemyScoutStep;
9253
//check if unit too close to ver edge already
9254
if(tempY > ((mapHeight * 128) - temp)) //too close to edge
9256
//dbg(" " & me & ") ----reached bottom edge");
9257
tempY = (mapHeight * 128) - temp;
9258
bEnemyScoutToBottom = FALSE; //change dir
9260
//have to skip a hor line now
9262
if(not bEnemyScoutToRight) //going left
9264
tempX = tempX - enemyScoutStep;
9266
//check hor edge now
9267
if(tempX < temp) //reached left
9269
//dbg(" " & me & ") ----reached left edge");
9271
bEnemyScoutToRight = TRUE;
9276
tempX = tempX + enemyScoutStep;
9277
//check hor edge now
9278
if(tempX > ((mapWidth * 128) - temp)) //reached right
9280
//dbg(" " & me & ") ----reached right edge");
9281
tempX = (mapWidth * 128) - temp;
9282
bEnemyScoutToRight = FALSE;
9291
tempY = tempY - enemyScoutStep;
9293
//check if unit too close to ver edge already
9294
if(tempY < temp) //too close to edge
9297
bEnemyScoutToBottom = TRUE; //change dir
9299
//have to skip a hor line now
9301
if(not bEnemyScoutToRight) //going left
9303
tempX = tempX - enemyScoutStep;
9305
//check hor edge now
9306
if(tempX < temp) //reached left
9308
//dbg(" " & me & ") ----reached left edge");
9310
bEnemyScoutToRight = TRUE;
9315
tempX = tempX + enemyScoutStep;
9316
//check hor edge now
9317
if(tempX > ((mapWidth * 128) - temp)) //reached right
9319
//dbg(" " & me & ") ----reached right edge");
9320
tempX = (mapWidth * 128) - temp;
9321
bEnemyScoutToRight = FALSE;
9328
enemyScoutX = tempX;
9329
enemyScoutY = tempY;
9332
//---------------------------------------------------------------
9333
// Returns closest corner based on arguments
9334
//---------------------------------------------------------------
9335
function void getClosestCorner(int _x, int _y)
9337
temp = (12 * 128); //border offset
9340
retInt = temp; //left
9341
if(_x > ((mapWidth * 128) / 2))
9343
retInt = (mapWidth * 128) - temp; //right
9348
retInt2 = temp; //top
9349
if(_y > ((mapHeight * 128) / 2))
9351
retInt2 = (mapHeight * 128) - temp; //bottom
9355
//Calculate number of defenders to leave in the base when going out with the main force to attack stuff
9356
function void updateNumDefenders()
9358
local int _attackDistance,_numActiveEnemies,_numActiveAllies,_player,
9360
local float _enemyFactor;
9364
/* If we are not using additional base defenders, leave minimum in the base */
9365
if(NO_BASE_DEFENDERS)
9367
numDefenders = minDefenders;
9370
else if(PROGRESSIVE_DEFENDERS)
9372
//leave almost no defenses when the game has just started
9373
minDefenders = MIN_DEFENDERS;
9374
if(GAME_TIME_IN_SECS < (MINUTE * 12)){
9375
minDefenders = (MIN_DEFENDERS / (MINUTE * 12)) * GAME_TIME_IN_SECS; //0 for 0 mins, 3 for 12 mins
9378
// leave 9 defenders for 40 and 18 for total 80 units
9379
numDefenders = max(minDefenders, (int)((float)numAvailableAttackers() / 5.44));
9383
// make sure we have all the necessary values
9384
if(sendForceX <= 0 or baseX <= 0){
9388
if( !(state == stAttacking or state == stHelpingAlly) ){
9392
//Count all our base defenses
9393
_numBaseDefenses = numFriendlyWeapStructsInRange(me, baseX, baseY, COUNT_BASE_OBJECTS_RANGE, true) / STR_UNIT_DEFENSE_FACTOR;
9395
//Count active allies and enemies
9397
_numActiveEnemies = 0;
9398
while(_player < MAX_PLAYERS)
9402
//make sure this player is still alive
9403
if(not dead[_player])
9405
//we assume that if we attack a certain enemy or help a certain ally this player doesn't count, since can't send units to our base
9406
if( !( (state == stAttacking or state == stHelpingAlly) and
9407
(_player == enemy)) )
9409
if(not allianceExistsBetween(me, _player))
9411
_numActiveEnemies++;
9415
//Our ally can't help us if he's defending its base
9416
if(allyState[_player] != stDefendingBase)
9427
//Calculate enemy factor, depends on number of enemies and allies, allies are not that important when it comes to defending our base
9428
_enemyFactor = (float)_numActiveEnemies - (float)_numActiveAllies / 4.1; //4.1, so we won't get div by 0 error
9430
//find out how far we are going with our main force
9431
_attackDistance = distBetweenTwoPoints(sendForceX, sendForceY, baseX, baseY) / TILE;
9434
//Calculate number of defenders to leave in the base when going out with the main force to attack stuff
9435
numDefenders = (int)((float)_attackDistance / ((float)UNIT_HOLD_SECS / _enemyFactor)) -
9436
_numBaseDefenses / STR_UNIT_DEFENSE_FACTOR;
9439
function void updateMilitaryStatus()
9441
noBaseTargets = TRUE; //reset here, set by checkBase()
9444
while(count < multiPlayerMaxPlayers)
9448
ally[count] = FALSE;
9450
if(allianceExistsBetween(count ,me) )
9455
/* check if can see any enemy object */
9456
//only check if not dead already, OBJ_SEEN will make him alive if it sees anything
9460
//count2 = checkPlayerDead(count);
9461
if(checkPlayerDead(count))
9465
dbg(getPlayerName(count) & " IS DEAD !!!!!!!!!!!!!!!!++++", me);
9467
notifyPlayerDead(count);
9481
/* Some military checks */
9482
function void militarySelftest()
9484
if(researchFinished(resBB, me)) //BB
9489
bCanUseCommanders = canUseCommanders();
9491
// how much of the map do we have revealed?
9492
/* if(fMapRevealFactor < MAP_REVEAL_FAC_UBOUND)
9494
fMapRevealFactor = (MAP_REVEAL_FAC_UBOUND - MAP_REVEAL_FAC_LBOUND) /
9495
(MAP_REVEAL_MAX_OIL_RES - MAP_REVEAL_MIN_OIL_RES) *
9496
(float)numTotalOilInRange(-1,-1,-1);
9498
fMapRevealFactor = fmax(MAP_REVEAL_FAC_LBOUND, fMapRevealFactor);
9499
fMapRevealFactor = fmin(MAP_REVEAL_FAC_UBOUND, fMapRevealFactor);
9503
function void findAlternateTarget()
9505
//Only choose alternate target if already ready to attack, otherwise
9506
//if a real target will be found afterwards, it won't be assigned as main target
9507
//------------------------------------------------------------------------------
9509
//find any other structure left
9510
structure = getClosestEnemyStructByType(baseX, baseY, -1, REF_DEFENSE, me);
9511
if(structure == NULLOBJECT)
9513
structure = getClosestEnemyStructByType(baseX, baseY, -1, REF_RESOURCE_EXTRACTOR, me);
9517
if(structure != NULLOBJECT)
9519
//centreView(structure);
9521
result = structure.player;
9522
dbg("no valid base targets, found an alternative target for " & getPlayerName(result), me);
9524
seeBase[result] = TRUE;
9525
knowBase[result] = TRUE;
9527
//dead[result] = FALSE;
9528
//killedBase[result] = FALSE;
9530
curBase[result][0] = structure.x;
9531
curBase[result][1] = structure.y;
9533
if(curHelpX[result] <= 0)
9535
curHelpX[result] = curBase[result][0];
9536
curHelpY[result] = curBase[result][1];
9539
//if((base[result][0] <= 0) or (base[result][1] <= 0))
9541
// base[result][0] = structure.x;
9542
// base[result][1] = structure.y;
9545
noBaseTargets = FALSE;
9549
function bool canStartAttack(int _enemy)
9551
if(numAvailableAttackers() < numPlayerAttackers[_enemy])
9556
// make sure we found enemy base
9557
if(curBase[_enemy][0] < 0 or curBase[_enemy][1] < 0)
9565
function bool canStartArtyCouterAttack(int _enemy, int _x, int _y)
9567
if(!haveTheoreticallyMinAttackers(false))
9572
if(numEnemyWeapObjInRange(me, _x, _y, (TILE * 7), false, true) > numAvailableAttackers())
9580
//count current attackers as well
9581
function bool canTheoreticallyStartAttack()
9583
if(numAvailableAttackers() >= numAttackers)
9591
// have *any* attackers? (count current attackers as well)
9592
function bool haveTheoreticallyMinAttackers(bool _bSafeToSendLittleAttackers)
9594
if(_bSafeToSendLittleAttackers) //it's ok to send little attackers, for example if joining forces with other players
9596
if((totalWeapUnits() - minDefenders) >= minAttackers)
9601
else //too dangerous to send little attackers, wait until we get more units
9603
if(numAvailableAttackers() >= minAttackers)
9613
/* All units - number of required defenders */
9614
function int numAvailableAttackers()
9616
return max(totalWeapUnits() - numDefenders, 0);
9619
/* Total units that can attack, including defenders */
9620
function int totalWeapUnits()
9622
return groupSizeCmds(attackGr,true,false,true) +
9623
groupSizeCmds(sendAttackGr,true,false,true) +
9624
groupSizeCmds(defendGr,true,false,true);
9627
//Get number of members of a group including units assigned to commanders that belong to this group too
9628
function int groupSizeCmds(GROUP _groupToCount, bool _bIncludeUnassigned,
9629
bool _bIncludeCmds, bool _bInclDroidsAssignedToCmds)
9631
local int _index,_numDroids;
9632
local bool _bCMDsOnly;
9634
// Optimization: equivalent to _groupToCount.members
9635
if(_bIncludeUnassigned and !_bIncludeCmds and !_bInclDroidsAssignedToCmds){
9636
return _groupToCount.members;
9639
//_groupToCount can only be NULL if we are counting commanders only
9640
if((_groupToCount == NULLOBJECT) and
9641
(_bIncludeCmds == TRUE && _bInclDroidsAssignedToCmds == FALSE))
9646
if(!_bCMDsOnly and _bIncludeUnassigned){
9647
_numDroids = _groupToCount.members; //count droids not assigned to a comamdner
9650
while(_index < MAX_COMMANDERS)
9652
//make sure this commander isn't dead and belongs to the desired group
9653
if((cmds[_index] != NULLOBJECT) and
9654
((cmdGr[_index] == _groupToCount) or _bCMDsOnly) )
9656
//Include units assigned to this commander
9657
if(_bInclDroidsAssignedToCmds)
9659
if(cmds[_index].group == NULLOBJECT)
9661
debug("commander " & _index & " group is null");
9663
_numDroids = _numDroids + cmds[_index].group.members; //count droids in the commander group
9666
//Count the commander
9678
//Order group and all commanders belonging to this group to move to some location
9679
function void orderGroupLocCmd(GROUP _groupToOrder, int _order, int _x, int _y)
9681
local int _cmdIndex;
9683
//Order droids without commander
9684
orderGroupLoc(_groupToOrder, _order, _x, _y);
9686
//Order commanders belonging to this group
9688
while(_cmdIndex < MAX_COMMANDERS)
9690
if(cmds[_cmdIndex] != NULLOBJECT)
9692
if(cmdGr[_cmdIndex] == _groupToOrder)
9694
orderDroidLoc(cmds[_cmdIndex], _order, _x, _y);
9701
/* Add Commander to some group */
9702
function void groupAddCmd(GROUP _group, DROID _commander)
9704
ASSERT(_commander != NULLOBJECT,
9705
"groupAddCmd: commander is NULL", me);
9707
//set group for a commander
9708
cmdGr[cmdToIndex(_commander)] = _group;
9711
/* Returns index of a commander */
9712
function int cmdToIndex(DROID _commander)
9716
ASSERT(_commander != NULLOBJECT,
9717
"cmdToIndex: commander is NULL", me);
9720
while(_index< MAX_COMMANDERS)
9722
if(_commander == cmds[_index])
9729
ASSERT(_index >= 0, "cmdToIndex: couldn't find commander", me);
9731
return -1; //not found
9734
//Move droids and all commanders belonging to a certain group to another group
9735
function void groupAddGroupCmd(GROUP _groupTo, GROUP _groupFrom)
9737
local int _cmdIndex;
9739
groupAddGroup(_groupTo, _groupFrom);
9741
//Move all commanders to a new group
9743
while(_cmdIndex < MAX_COMMANDERS)
9745
if(cmds[_cmdIndex] != NULLOBJECT)
9747
if(cmdGr[_cmdIndex] == _groupFrom)
9749
cmdGr[_cmdIndex] = _groupTo;
9756
// Returns x coordinate of the group, takes commanders into account
9757
function int groupCMD_x(GROUP _group)
9759
local int _x,_numUnits,_cmdIndex;
9762
_numUnits = _group.members;
9765
while(_cmdIndex < MAX_COMMANDERS)
9767
if(cmds[_cmdIndex] != NULLOBJECT)
9769
if(cmdGr[_cmdIndex] == _group)
9772
_x = _x + cmds[_cmdIndex].x;
9775
// count units assigned to commander
9776
_x = _x + cmds[_cmdIndex].group.x;
9777
_numUnits = _numUnits + cmds[_cmdIndex].group.members;
9787
return (_x / _numUnits);
9790
// Returns y coordinate of the group, takes commanders into account
9791
function int groupCMD_y(GROUP _group)
9793
local int _y,_numUnits,_cmdIndex;
9796
_numUnits = _group.members;
9799
while(_cmdIndex < MAX_COMMANDERS)
9801
if(cmds[_cmdIndex] != NULLOBJECT)
9803
if(cmdGr[_cmdIndex] == _group)
9806
_y = _y + cmds[_cmdIndex].y;
9809
// count units assigned to commander
9810
_y = _y + cmds[_cmdIndex].group.y;
9811
_numUnits = _numUnits + cmds[_cmdIndex].group.members;
9821
return (_y / _numUnits);
9824
function int idleGroupCmd(GROUP _idleGroup, bool _bIncludeNonCmds, bool _bIncludeCmds)
9826
local int _cmdIndex,_numIdle;
9828
_numIdle = idleGroup(_idleGroup);
9830
// if(_bIncludeCmds)
9833
while(_cmdIndex < MAX_COMMANDERS)
9835
if(cmds[_cmdIndex] != NULLOBJECT)
9837
if(cmdGr[_cmdIndex] == _idleGroup)
9842
if((cmds[_cmdIndex].order == DORDER_NONE) ||
9843
(cmds[_cmdIndex].order == DORDER_GUARD and cmds[_cmdIndex].target == NULLOBJECT))
9849
// units attached to a commander
9850
if(_bIncludeNonCmds)
9852
_numIdle = _numIdle + idleGroup(cmds[_cmdIndex].group);
9863
//Same as initIterateGroup() but also returns commanders belonging to this group
9864
function int initIterateGroupCmd(GROUP _groupToIterate, bool _bReturnNonCmds,
9865
bool _bReturnCmds, bool _bReturnCmdAssignedDroids)
9867
local int _cmdIndex;
9869
/* dbg("initIterateGroupCmd: " & _bReturnNonCmds & "," &
9870
_bReturnCmds & "," & _bReturnCmdAssignedDroids , me); */
9872
ASSERT(_bReturnNonCmds or _bReturnCmds or _bReturnCmdAssignedDroids,
9873
"initIterateGroupCmd: no units to return", me);
9875
// make sure we start a new iteration, if we are already iterating (iteration inside iteration)
9876
// we assume there are MAX_GROUP_ITERATE_BUCKET iterations at most
9877
groupIterateBucket++;
9878
groupIterateBucket = modulo(groupIterateBucket, MAX_GROUP_ITERATE_BUCKET);
9880
//dbg("New groupIterateBucket = " & groupIterateBucket, me);
9882
ASSERT(groupIterateBucket < MAX_GROUP_ITERATE_BUCKET,
9883
"initIterateGroupCmd: can't start any more iterations (" &
9884
groupIterateBucket & ")", me);
9886
//Remember iteration settings
9887
groupToIterate[groupIterateBucket] = _groupToIterate; //remember group we are iterating over
9888
iterateCmdGroup[groupIterateBucket] = NULLOBJECT; //commander group we are currently iterating over
9889
bIterateNonCommanders[groupIterateBucket] = _bReturnNonCmds;
9890
bIterateCommanders[groupIterateBucket] = _bReturnCmds;
9891
bIterateCmdAssignedDroids[groupIterateBucket] = _bReturnCmdAssignedDroids; //whether to iterate over the droids assigned to a commander
9892
iterateCommanderIndex[groupIterateBucket] = 0; //starting with the first commander
9894
iterateGroupDroid[groupIterateBucket] = NULLOBJECT;
9896
iterateStage[groupIterateBucket] = 3; //nothing left
9898
//Prepare first non-commander droid
9899
if(bIterateNonCommanders[groupIterateBucket])
9901
iterateStage[groupIterateBucket] = 0; //iterating over main group
9902
initIterateGroup(groupToIterate[groupIterateBucket]);
9903
iterateGroupDroid[groupIterateBucket] = iterateGroup(groupToIterate[groupIterateBucket]);
9906
if(iterateGroupDroid[groupIterateBucket] == NULLOBJECT)
9908
if(bIterateCommanders[groupIterateBucket])
9910
iterateStage[groupIterateBucket] = 1;
9912
//Iterate through all commanders
9914
while((_cmdIndex < MAX_COMMANDERS) and (iterateGroupDroid[groupIterateBucket] == NULLOBJECT))
9916
if(cmds[_cmdIndex] != NULLOBJECT)
9918
if(cmdGr[_cmdIndex] == groupToIterate[groupIterateBucket])
9920
//return this commander
9921
iterateGroupDroid[groupIterateBucket] = cmds[_cmdIndex];
9922
iterateCommanderIndex[groupIterateBucket] = _cmdIndex + 1; //access next commander next time
9930
if(iterateGroupDroid[groupIterateBucket] == NULLOBJECT)
9932
if(bIterateCmdAssignedDroids[groupIterateBucket])
9934
iterateStage[groupIterateBucket] = 2;
9936
//Iterate through all droids assigned to commanders
9938
while((_cmdIndex < MAX_COMMANDERS) and (iterateGroupDroid[groupIterateBucket] == NULLOBJECT))
9940
if(cmds[_cmdIndex] != NULLOBJECT)
9942
if(cmdGr[_cmdIndex] == groupToIterate[groupIterateBucket])
9944
//return first droid of this commander's group
9945
iterateCmdGroup[groupIterateBucket] = cmds[_cmdIndex].group;
9946
initIterateGroup(iterateCmdGroup[groupIterateBucket]);
9947
iterateGroupDroid[groupIterateBucket] = iterateGroup(iterateCmdGroup[groupIterateBucket]);
9949
iterateCommanderIndex[groupIterateBucket] = _cmdIndex; //access this commander again next time
9957
if(iterateGroupDroid[groupIterateBucket] == NULLOBJECT)
9959
iterateStage[groupIterateBucket] = 3;
9962
return groupIterateBucket;
9965
//Same as iterateGroup() but also returns commanders
9966
function DROID iterateGroupCmd(GROUP _groupToIterate, int _bucket)
9968
local DROID _preparedDroid;
9969
local int _cmdIndex;
9972
// ASSERT(_bucket <= groupIterateBucket,
9973
// "iterateGroupCmd: wrong bucket: " & _bucket & "/" & groupIterateBucket, me);
9975
ASSERT(_groupToIterate == groupToIterate[_bucket],
9976
"iterateGroupCmd: wrong group passed", me);
9978
ASSERT(bIterateNonCommanders[_bucket] or bIterateCommanders[_bucket] or
9979
bIterateCmdAssignedDroids[_bucket],
9980
"iterateGroupCmd: no units to return", me);
9982
// decrease bucket, since we are done now
9983
if(iterateStage[_bucket] == 3)
9985
//dbg("Decreasing groupIterateBucket from " & groupIterateBucket, me);
9987
// ASSERT(_preparedDroid != NULLOBJECT,
9988
// "iterateGroupCmd: _preparedDroid is NULL, called this function after it returned NULL?", me);
9990
groupToIterate[_bucket] = NULLOBJECT; // mark this iteration as finished
9992
// reset some values
9993
bIterateNonCommanders[_bucket] = false;
9994
bIterateCommanders[_bucket] = false;
9995
bIterateCmdAssignedDroids[_bucket] = false;
9997
// groupIterateBucket--; // will only get once to this part, since values are reseat and checked before this place
9999
ASSERT(groupIterateBucket >= 0,
10000
"iterateGroupCmd: groupIterateBucket = " & groupIterateBucket, me);
10002
_preparedDroid = NULLOBJECT;
10004
return _preparedDroid;
10007
//store prepared droid
10008
_preparedDroid = iterateGroupDroid[_bucket];
10009
iterateGroupDroid[_bucket] = NULLOBJECT;
10011
//Get next droid from the main group
10012
if(iterateStage[_bucket] == 0)
10014
iterateGroupDroid[_bucket] = iterateGroup(groupToIterate[_bucket]);
10016
if(iterateGroupDroid[_bucket] == NULLOBJECT)
10018
iterateStage[_bucket] = 1;
10022
if(iterateStage[_bucket] == 1)
10024
if(bIterateCommanders[_bucket])
10026
//Iterate through all commanders
10027
_cmdIndex = iterateCommanderIndex[_bucket];
10028
while((_cmdIndex < MAX_COMMANDERS) and (iterateGroupDroid[_bucket] == NULLOBJECT))
10030
if(cmds[_cmdIndex] != NULLOBJECT)
10032
if(cmdGr[_cmdIndex] == groupToIterate[_bucket])
10034
iterateGroupDroid[_bucket] = cmds[_cmdIndex];
10035
iterateCommanderIndex[_bucket] = _cmdIndex + 1; //access next commander next time
10041
//Check if no commanders left
10042
if(iterateGroupDroid[_bucket] == NULLOBJECT)
10044
iterateStage[_bucket] = 2;
10045
iterateCommanderIndex[_bucket] = 0;
10046
iterateCmdGroup[_bucket] = NULLOBJECT;
10051
iterateStage[_bucket] = 2; //start iterating droids assigned to commanders if needed
10052
iterateCommanderIndex[_bucket] = 0;
10053
iterateCmdGroup[_bucket] = NULLOBJECT;
10057
if(iterateStage[_bucket] == 2)
10059
if(bIterateCmdAssignedDroids[_bucket])
10062
_cmdIndex = iterateCommanderIndex[_bucket];
10063
while(!_bStop and (iterateCommanderIndex[_bucket] < MAX_COMMANDERS) and (iterateGroupDroid[_bucket] == NULLOBJECT))
10065
//Find next commander that belongs to the right group
10066
_cmdIndex = iterateCommanderIndex[_bucket];
10067
while((iterateCmdGroup[_bucket] == NULLOBJECT) and (_cmdIndex < MAX_COMMANDERS))
10069
if(cmds[_cmdIndex] != NULLOBJECT)
10071
if(cmdGr[_cmdIndex] == groupToIterate[_bucket])
10073
iterateCmdGroup[_bucket] = cmds[_cmdIndex].group;
10074
initIterateGroup(iterateCmdGroup[_bucket]);
10075
iterateCommanderIndex[_bucket] = _cmdIndex;
10081
//Get next droid of this commander
10082
if(iterateCmdGroup[_bucket] != NULLOBJECT) //any suitable commander left?
10084
iterateGroupDroid[_bucket] = iterateGroup(iterateCmdGroup[_bucket]);
10086
//It was the last droid of this commander, try next commander
10087
if(iterateGroupDroid[_bucket] == NULLOBJECT)
10089
iterateCmdGroup[_bucket] = NULLOBJECT;
10090
iterateCommanderIndex[_bucket] = iterateCommanderIndex[_bucket] + 1;
10092
if(iterateCommanderIndex[_bucket] >= MAX_COMMANDERS)
10095
iterateStage[_bucket] = 3;
10102
iterateStage[_bucket] = 3;
10108
iterateStage[_bucket] = 3;
10112
return _preparedDroid;
10115
//---------------------------------------------------------------
10116
// Check base coords are valid for a certain player
10117
//---------------------------------------------------------------
10118
function void checkBase(int _player)
10120
local bool _bCanSeeBase;
10122
ASSERT(_player >= 0, "checkBase - _player < 0", me);
10124
if(bCheckBaseDebug)dbg("--checkBase--", me);
10126
if(knowBase[_player])
10128
if(bCheckBaseDebug)dbg("checkBase: know base for " & _player, me);
10130
if((curBase[_player][0] <= 0) or (curBase[_player][1] <= 0))
10131
MsgBox("checkBase() - curBase <= 0");
10133
if(mapRevealedInRange(curBase[_player][0],curBase[_player][1], (2 * 128), me)) //can tell if it's empty only if visited this place (in case recalled it from memory)
10135
if(bCheckBaseDebug)dbg("checkBase: for revealed for " & _player, me);
10137
// check if base location is inside radar range
10138
if((curBase[_player][0] > 0) and (curBase[_player][1] > 0)){
10139
_bCanSeeBase = canSeeLoc(curBase[_player][0], curBase[_player][1]);
10142
if(bCheckBaseDebug && _bCanSeeBase)dbg("checkBase: can see loc for player " & _player, me);
10144
if(_bCanSeeBase and !enemyTargetInRange(_player, curBase[_player][0], curBase[_player][1], (2 * 128)) )
10146
if(bCheckBaseDebug)dbg("checkBase: have no targets for " & _player, me);
10148
//if((curBase[_player][0] == base[_player][0]) and (curBase[_player][1] == base[_player][1]))
10150
// dbg(" " & me & ") recalled location is empty for " & _player & " !!!!!!!!!!!!!!!!!!!!!!!");
10154
//temp = findBase(_player);
10156
if(findBase(_player)) //found new location of the base for this player
10158
dbg("Corrected base coords for player" & _player, me);
10160
curBase[_player][0] = retInt;
10161
curBase[_player][1] = retInt2;
10163
if(curHelpX[_player] <= 0)
10165
curHelpX[_player] = curBase[_player][0];
10166
curHelpY[_player] = curBase[_player][1];
10169
/* update destination coords if going to this player */
10170
if(attackingEnemyBase(_player))
10172
dbg("Enemy cords updated", me);
10174
updateStateCoord(curBase[_player][0], curBase[_player][1]);
10177
seeBase[_player] = TRUE; //found base
10179
if(not ally[_player])
10180
noBaseTargets = FALSE;
10182
dbg("found a different enemy base location for " & _player, me);
10184
//if no real base found yet, only an alternate loc, then remember real base now
10185
if((base[_player][0] <= 0) or (base[_player][1] <= 0))
10187
base[_player][0] = retInt;
10188
base[_player][1] = retInt2;
10191
//learn this location
10194
if(not canRememberPlayerBaseLoc(me, _player)) //not already in memory
10196
learnPlayerBaseLoc(me, _player, retInt, retInt2);
10200
else //couldn't find anything
10202
if(_player == enemy) //attacking this one right now
10204
if(canSeePlayerBase(_player)) //warn only once, when just lost the base
10206
dbg("lost current enemy " & getPlayerName(_player) & " !!!!!!!!!!!!!!!!!!!!!", me);
10210
else if(canSeePlayerBase(_player)) //lost it now
10212
dbg("lost base loc for enemy " & getPlayerName(_player), me);
10215
seeBase[_player] = FALSE; //lost
10216
//knowBase[_player] = FALSE; //disabled 15.05.05 because of phSearchingForBase was skipped because of this
10220
else //enemy base still there
10222
if(bCheckBaseDebug)dbg("checkBase: still have targets for " & _player, me);
10224
if(not allianceExistsBetween(me , _player)) //this player is not our ally
10225
noBaseTargets = FALSE;
10227
/* make sure allies see newly found enemy base */
10228
if(not canSeePlayerBase(_player)) //just found
10229
refreshAllyRadar();
10231
seeBase[_player] = TRUE; //can see base
10234
else //enemy base still there (probably recalled it)
10236
if(not ally[_player])
10237
noBaseTargets = FALSE;
10240
else //don't have enemy base loc
10243
//temp = findBase(_player);
10245
if(findBase(_player)) //found new location of the base for this player
10247
curBase[_player][0] = retInt;
10248
curBase[_player][1] = retInt2;
10250
if(curHelpX[_player] <=0)
10252
curHelpX[_player] = curBase[_player][0];
10253
curHelpY[_player] = curBase[_player][1];
10256
knowBase[_player] = TRUE;
10257
seeBase[_player] = TRUE; //found base
10259
if(not ally[_player])
10261
noBaseTargets = FALSE;
10264
dbg("found new enemy base for " & getPlayerName(_player) & " at " & (curBase[_player][0] / 128) & " - " & (curBase[_player][1] / 128) & " !!!!!!!!!", me);
10266
//if no real base found yet, only an alternate loc, then remember real base now
10267
if((base[_player][0] <= 0) or (base[_player][1] <= 0))
10269
base[_player][0] = retInt;
10270
base[_player][1] = retInt2;
10273
//learn this location
10276
if(not canRememberPlayerBaseLoc(me, _player)) //not already in memory
10278
learnPlayerBaseLoc(me, _player, retInt, retInt2);
10282
refreshAllyRadar();
10286
// dead[_player] = TRUE;
10291
function bool checkPlayerDead(int _player)
10293
if(knowBase[_player] and (not canSeePlayerBase(_player))) //know location, but don't see it
10295
if(mapRevealedInRange(curBase[_player][0],curBase[_player][1], (2 * 128), me)) //make sure can see the location where the base should be
10297
//_temp = canSeePlayer(_player); //can see any other objects?
10299
if(not canSeePlayer(_player))
10301
return(TRUE); //dead
10309
function bool canSeePlayer(int _player)
10311
_bResult = FALSE; //not found
10313
initEnumStruct(TRUE,wall,_player,me);
10314
_structure = enumStruct();
10315
while((_structure != NULLOBJECT) and (not _bResult))
10317
_temp = getStructureType(_structure);
10318
if((_temp != 7) and (_temp != 8) and (_temp != 6) and (_temp != 6)) //wall, cornerwall, defense, rearm
10322
_structure = enumStruct();
10325
if(not _bResult) //no structures
10327
InitEnumDroids(_player,me);
10328
_droid = EnumDroid();
10329
if(_droid == NULLOBJECT)
10338
function bool findBase(int _targetPlayer)
10340
local int _structType;
10342
ASSERT(_targetPlayer >= 0, "findBase - _targetPlayer < 0", me);
10345
while(_structType < numBaseStructs)
10347
tempStruct = getStructureVis(baseStructs[_structType], _targetPlayer, me);
10348
if(tempStruct !=NULLOBJECT)
10350
retInt = tempStruct.x;
10351
retInt2 = tempStruct.y;
10354
_structType = _structType + 1;
10360
function int chooseEnemyToDrop()
10362
//choose the most annoying one
10365
temp4 = (-1); //num times attacked by an enemy
10368
while(temp < multiPlayerMaxPlayers)
10370
if((not allianceExistsBetween(temp, me)) and (temp != me))
10372
if((not dead[temp]) and knowBase[temp] and canSeePlayerBase(temp)) //found player's base and know this player is active since can se him
10374
temp2 = numAlliesDroppingPlayer(temp);
10376
temp3 = numActiveEnemyDrop(temp);
10378
if((temp3 == 0) and (temp2 < maxAllyDroppers)) //not too many and not already dropping
10380
if(attacked[temp] > temp4)
10382
temp4 = attacked[temp];
10394
function int chooseEnemy()
10396
local int _bestEnemy,_enemy,_tileDist;
10397
local int _bestWeight,_tempWeight;
10398
//return - suited enemy to attack
10401
_bestWeight = -99999;
10403
if(offeredEnemy != none) //anyone already attacking someone?
10405
if((not ally[offeredEnemy]) and (not dead[offeredEnemy]) and (knowBase[offeredEnemy]) and (offeredEnemy != me))
10407
dbg("choosing offered enemy", me);
10408
_bestEnemy = offeredEnemy;
10409
offeredEnemy = none; //don't choose it again after destroying it
10413
if(_bestEnemy == none) //didn't set offeredEnemy as the enemy
10415
// now look for bases that were not yet destroyed and which we can see
10417
while(_enemy < multiPlayerMaxPlayers)
10419
if((not ally[_enemy]) and (_enemy != me))
10421
if(knowBase[_enemy] and (not dead[_enemy]) and
10422
(not killedBase[_enemy]) and canSeePlayerBase(_enemy)) //found player's base
10424
_tileDist = distBetweenTwoPoints(baseX, baseY, curBase[_enemy][0], curBase[_enemy][1]) / 128;
10426
// Now calculate enemy weight
10427
_tempWeight = (int)(W_LOST_UNITS * (float)lostDroids[_enemy] -
10428
W_BASE_DISTANCE * (float)_tileDist * TILE_TRAVEL_COST);
10430
if(_tempWeight > _bestWeight)
10432
_bestWeight = _tempWeight;
10433
_bestEnemy = _enemy; //enemy so far
10440
// now also include those bases we can't see
10441
if(_bestEnemy == none)
10444
while(_enemy < multiPlayerMaxPlayers)
10446
if((not ally[_enemy]) and (_enemy != me))
10448
if(knowBase[_enemy] and (not dead[_enemy]) and
10449
(not killedBase[_enemy])) //found player's base
10451
_tileDist = distBetweenTwoPoints(baseX, baseY, curBase[_enemy][0], curBase[_enemy][1]) / 128;
10453
// Now calculate enemy weight
10454
_tempWeight = (int)(W_LOST_UNITS * (float)lostDroids[_enemy] -
10455
W_BASE_DISTANCE * (float)_tileDist * TILE_TRAVEL_COST);
10457
if(_tempWeight > _bestWeight)
10459
_bestWeight = _tempWeight;
10460
_bestEnemy = _enemy; //enemy so far
10468
// now also include those bases that were already destroyed
10469
if(_bestEnemy == none)
10472
while(_enemy < multiPlayerMaxPlayers)
10474
if((not ally[_enemy]) and (_enemy != me))
10476
//if(knowBase[_enemy] and (not dead[_enemy])) //found player's base
10477
if(knowBase[_enemy]) //found player's base
10479
//TODO: must choose a random one here, since will keep choosing the closest one
10480
_tileDist = distBetweenTwoPoints(baseX, baseY, curBase[_enemy][0], curBase[_enemy][1]) / 128;
10482
// Now calculate enemy weight
10483
_tempWeight = (int)(W_LOST_UNITS * (float)lostDroids[_enemy] -
10484
W_BASE_DISTANCE * (float)_tileDist * TILE_TRAVEL_COST);
10486
if(_tempWeight > _bestWeight)
10488
_bestWeight = _tempWeight;
10489
_bestEnemy = _enemy; //enemy so far
10498
return(_bestEnemy);
10501
/* function int chooseEnemy()
10503
local int _bestEnemy,_bestDistance,_enemy,_tempDistance;
10504
local int _bestWeight;
10505
//return - suited enemy to attack
10507
_bestDistance = 99999;
10510
if(offeredEnemy != none) //anyone already attacking someone?
10512
//if((not ally[offeredEnemy]) and (not dead[offeredEnemy]) and (knowBase[offeredEnemy]) and (offeredEnemy != me) and (not killedBase[offeredEnemy]))
10513
if((not ally[offeredEnemy]) and (not dead[offeredEnemy]) and (knowBase[offeredEnemy]) and (offeredEnemy != me))
10515
dbg("choosing offered enemy", me);
10516
_bestEnemy = offeredEnemy;
10517
offeredEnemy = none; //don't choose it again after destroying it
10521
if(_bestEnemy == none) //didn't set offeredEnemy as the enemy
10523
// now look for bases that were not yet destroyed and which we can see
10525
while(_enemy < multiPlayerMaxPlayers)
10527
if((not ally[_enemy]) and (_enemy != me))
10529
if(knowBase[_enemy] and (not dead[_enemy]) and (not killedBase[_enemy]) and seeBase[_enemy]) //found player's base
10531
_tempDistance = distBetweenTwoPoints(baseX, baseY, curBase[_enemy][0], curBase[_enemy][1]);
10532
if(_tempDistance < _bestDistance)
10534
_bestDistance = _tempDistance;
10535
_bestEnemy = _enemy; //enemy so far
10542
// now also include those bases we can't see
10543
if(_bestEnemy == none)
10546
while(_enemy < multiPlayerMaxPlayers)
10548
if((not ally[_enemy]) and (_enemy != me))
10550
if(knowBase[_enemy] and (not dead[_enemy]) and (not killedBase[_enemy])) //found player's base
10552
_tempDistance = distBetweenTwoPoints(baseX, baseY, curBase[_enemy][0], curBase[_enemy][1]);
10553
if(_tempDistance < _bestDistance)
10555
_bestDistance = _tempDistance;
10556
_bestEnemy = _enemy; //enemy so far
10564
// now also include those bases that were already destroyed
10565
if(_bestEnemy == none)
10568
while(_enemy < multiPlayerMaxPlayers)
10570
if((not ally[_enemy]) and (_enemy != me))
10572
//if(knowBase[_enemy] and (not dead[_enemy])) //found player's base
10573
if(knowBase[_enemy]) //found player's base
10575
//TODO: must choose a random one here, since will keep choosing the closest one
10576
_tempDistance = distBetweenTwoPoints(baseX, baseY, curBase[_enemy][0], curBase[_enemy][1]);
10577
if(_tempDistance < _bestDistance)
10579
_bestDistance = _tempDistance;
10580
_bestEnemy = _enemy; //enemy so far
10589
return(_bestEnemy);
10592
function void checkBaseThreat()
10594
local int _attacker,_attackerUnitForce,_attackerStructureForce,_counterEnemy,_bestEnemyForce;
10595
local int _enemyUnits,_enemyStructures,_allyUnits,_allyStructures;
10596
local int _totalEnemies,_totalAllies,_range;
10597
local int _enemyX,_enemyY,_counterEnemyForce;
10600
// _range = (29 * 128);
10602
_range = COUNT_BASE_OBJECTS_RANGE;
10604
//showRangeAtPos(baseX, baseY, _range);
10606
/* Check if base is in danger */
10607
// _totalEnemies enemy units and structures
10609
_enemyStructures = 0;
10611
// don't reset counterenemy if we are defending
10612
if(!defendingBase()) {
10613
_counterEnemy = -1;
10616
_bestEnemyForce = 0;
10618
while(_attacker < MAX_PLAYERS)
10620
if((not allianceExistsBetween(_attacker, me)) and (_attacker != me))
10622
_attackerUnitForce = numPlayerWeapDroidsInRange(_attacker, me, baseX, baseY, _range, FALSE);
10623
_enemyUnits = _enemyUnits + _attackerUnitForce;
10625
_attackerStructureForce = numPlayerWeapStructsInRange(_attacker, me, baseX, baseY, _range, true);
10626
_enemyStructures = _enemyStructures + _attackerStructureForce;
10629
//console(_attacker & " " & _attackerUnitForce & "/" & _attackerStructureForce);
10631
// see if this enemy dominates in the area and if so remember him as enemy to counter
10632
if((_counterEnemy < 0) or ((_attackerUnitForce + _attackerStructureForce / STR_UNIT_DEFENSE_FACTOR) > _bestEnemyForce))
10634
_bestEnemyForce = _attackerUnitForce + _attackerStructureForce / STR_UNIT_DEFENSE_FACTOR;
10636
// don't reset counterenemy if we are defending
10637
if(!defendingBase()) {
10638
_counterEnemy = _attacker;
10644
_enemyStructures = _enemyStructures / STR_UNIT_DEFENSE_FACTOR;
10646
//_enemyUnits = numEnemyWeapDroidsInRange(me, baseX, baseY, _range, FALSE);
10647
//_enemyStructures = numEnemyWeapStructsInRange(me, baseX, baseY, _range) / 3;
10649
_allyUnits = numFriendlyWeapDroidsInRange(me, baseX, baseY, _range, FALSE);
10650
_allyStructures = numFriendlyWeapStructsInRange(me, baseX, baseY, _range, true) / STR_UNIT_DEFENSE_FACTOR;
10652
_totalEnemies = _enemyUnits + _enemyStructures; //total enemies
10653
_totalAllies = _allyUnits + _allyStructures; //total allies
10655
if(_enemyUnits > 0)
10656
dbg("Num enemies = " & _enemyUnits & "/" & _enemyStructures & " (" & _allyUnits & "/" & _allyStructures & ") - " & (_range / TILE), me);
10658
/* pre-warn allies (only units _totalEnemies) */
10659
if(_enemyUnits >= 7)
10661
if(!defendingBase()) //do only once/attack
10663
if(timeNotifyEnemyInBase <= 0)
10665
notifyEnemyAtBase();
10667
attackedCount++; //remember how many times we were attacked
10672
/* Check if base in danger */
10673
if((_enemyUnits > _totalAllies) or ((_enemyUnits >= maxBaseEnemies) and ((_totalEnemies - _totalAllies) < 4)) or (_totalEnemies > _totalAllies) //they have more units than all our defenses
10674
or ((_allyUnits < minDefenders) and alert and (_enemyUnits >= 2) and (_allyStructures < 20)) ) //if we are low on defenders and power next attack might wipe us out (dangerous especially on big maps)
10676
if(gameTime > 2800)
10678
dbg("BASE: too many enemies in the base !!!!!!", me);
10680
if(!defendingBase())
10682
if(state != stNone)
10687
//TODO: with _attacker = playerDominanceInArea() find out if attacker's base is closer than our own base
10688
//and attack enemy base instead
10690
taunt(_counterEnemy, TAUNT_BASE_DEFENSE, 50);
10692
startDefending(_counterEnemy);
10693
requestHelp(baseX, baseY);
10698
/* check if can stop defending */
10699
else if(defendingBase() and (_enemyUnits == 0)) //all enemies are gone
10701
if(groupSizeCmds(defendGr,true,false,true) >= minDefenders) //make sure can defend on our own
10703
dbg("base is safe again", me);
10705
_counterEnemy = counterEnemy;
10706
stopDefendingBase();
10708
taunt(_counterEnemy, TAUNT_BASE_OK, 55);
10710
notifyAllies("i'm ok", FALSE); //tell allies we are ok now
10712
/* See if we can counterattack */
10713
if((state == stNone) and (_counterEnemy != none))
10715
if(not allianceExistsBetween(_counterEnemy, me))
10717
if(totalWeapUnits() >= MIN_COUNTERATTACKERS)
10719
if(knowBase[_counterEnemy])
10721
_enemyX = curBase[_counterEnemy][0];
10722
_enemyY = curBase[_counterEnemy][1];
10723
_range = (20 * TILE);
10725
// see if we have a chance to win
10726
_counterEnemyForce = numPlayerWeapDroidsInRange(_counterEnemy, me, _enemyX, _enemyY, -1, FALSE) +
10727
numPlayerWeapStructsInRange(_counterEnemy, me, _enemyX, _enemyY, _range, true) / 3;
10729
if(totalWeapUnits() > _counterEnemyForce)
10731
dbg("counterattacking", me);
10732
startEnemyBaseAttack(_counterEnemy);
10733
requestStartAttack(_counterEnemy, _enemyX, _enemyY);
10736
dbg("counterattack: too dangerous: " & totalWeapUnits() & "/" & _counterEnemyForce, me);
10740
dbg("counterattack: don't have base of " & _counterEnemy, me);
10744
dbg("counterattack: not enough attackers " & totalWeapUnits(), me);
10748
dbg("counterattack: counterEnemy is ally: " & _counterEnemy, me);
10752
dbg("counterattack: busy: " & state & " : " & _counterEnemy, me);
10759
function bool canRequestHelp()
10761
if(requestHelpTime <= 0)
10769
function void requestHelp(int _x, int _y)
10772
while(_temp < multiPlayerMaxPlayers)
10774
if(allianceExistsBetween(me , _temp))
10776
giftRadar(me, _temp, FALSE);
10777
dropBeacon("help", _temp, me, _x, _y, 0);
10778
msg("help", me, _temp);
10783
requestHelpTime = maxRequestHelpTime;
10786
/* Request status from allies */
10787
function void checkRequestStatus()
10790
while(_temp < multiPlayerMaxPlayers)
10792
if(allianceExistsBetween(me , _temp) and (tRequestStatus[_temp] <= 0))
10794
requestStatus(_temp);
10800
function void requestStatus(int _player)
10802
msg("status?" ,me , _player);
10804
tRequestStatus[ _player] = tMaxRequestStatus + random(700);
10807
function void requestEnemy(int _toAskPlayer)
10809
msg("who's your target?" ,me , _toAskPlayer);
10811
tWaitPlayerReply[_toAskPlayer] = tMaxWaitPlayerReply; //start timer
10815
function void notifyPlayerDead(int deadPlayer)
10820
while(_temp < multiPlayerMaxPlayers)
10822
if(allianceExistsBetween(me , _temp))
10824
if(deadPlayer == me)
10826
msg("ok, i'm dead, cya" ,me , _temp);
10830
msg(getPlayerName(deadPlayer) & " is dead" ,me , _temp);
10837
function void notifyPlayerAlive(int _alivePlayer)
10842
exit; //engine bugs at startup
10845
while(_temp < multiPlayerMaxPlayers)
10847
if(allianceExistsBetween(me , _temp))
10849
msg(getPlayerName(_alivePlayer) & " is alive" ,me , _temp);
10855
function void notifyPlayerBaseDestroyed(int _destroyedPlayer)
10857
notifyAllies("destroyed " & getPlayerName(_destroyedPlayer) & "'s base", FALSE);
10860
function void notifyLost()
10863
while(_temp < multiPlayerMaxPlayers)
10865
if(allianceExistsBetween(me , _temp))
10867
msg("cya" ,me , _temp);
10873
/* Notify we are idle, if failed to take over enemy derrick or if attack failed */
10874
function void notifyIdle(bool bAfterFailure)
10878
notifyAllies("building more units", false); //make sure allies are aware of our current state
10884
notifyAllies("getting units", false);
10886
notifyAllies("building an army", false);
10891
function void taunt(int targetPlayer, int type, int tauntProbability)
10893
local string sTarget,sPlayer;
10895
if(random(100) >= tauntProbability)
10900
// see if we are refering to some player
10901
if(targetPlayer != NONE)
10903
sPlayer = getPlayerName(targetPlayer);
10904
sTarget = getPlayerName(targetPlayer) & ", ";
10909
if(type == TAUNT_SUCCESS)
10913
notifyAll(sTarget & "you suck.");
10917
notifyAll("too easy");
10921
notifyAll("I get what I want");
10924
else if(type == TAUNT_FAILURE) // state failed
10927
notifyAll(sTarget & "screw you!!");
10929
notifyAll(sTarget & "stop turtling");
10932
else if(type == TAUNT_POSSESSION_LOSS) // lost a derrick etc
10935
notifyAll(sTarget & "I didn't need it anyway");
10936
}else if(dice < 8){
10937
notifyAll(sTarget & "next time i'll kick your ass!");
10939
notifyAll(sTarget & "i'll get it back");
10942
else if(type == TAUNT_GAME_LOSS)
10946
}else if(dice < 8){
10947
notifyAll("rematch?");
10948
}else if(dice < 9){
10949
notifyAll("I can do better");
10951
notifyAll("it's not my day..");
10954
else if(type == TAUNT_BASE_DEFENSE)
10957
notifyAll(sTarget & "bring it on!");
10959
notifyAll(sTarget & "I've been waiting for you");
10962
else if(type == TAUNT_BASE_OK)
10965
notifyAll(sPlayer & " is a noob");
10966
}else if(dice < 6){
10967
notifyAll(sTarget & "maybe next time");
10968
}else if(dice < 8){
10969
notifyAll(sTarget & "so how did you like it?");
10970
}else if(dice < 9){
10971
notifyAll(sTarget & "ain't I good?");
10973
notifyAll(sTarget & "is that all you got?");
10976
else if(type == TAUNT_REDISCOVERED_BASE)
10979
notifyAll(sTarget & "found ya");
10980
}else if(dice < 6){
10981
notifyAll(sTarget & "there you are");
10982
}else if(dice < 8){
10983
notifyAll(sTarget & "let me finish you..");
10984
}else if(dice < 9){
10985
notifyAll(sTarget & "you thought I wouldn't find you?");
10987
notifyAll(sTarget & "you can run but you can't hide");
10990
else if(type == TAUNT_LOST_BASE)
10993
notifyAll(sTarget & "do you have anything left?");
10994
}else if(dice < 6){
10995
notifyAll(sTarget & "that felt good");
10996
}else if(dice < 8){
10997
notifyAll(sTarget & "you can't hide forever");
10999
notifyAll("like a knife through butter");
11004
function void notifyReadyAttack()
11009
notifyAllies("go?", FALSE);
11010
}else if(dice == 0){
11011
notifyAllies("ready", FALSE);
11013
notifyAllies("I'm ready", FALSE);
11016
notifyReadyAttackTime = maxNotifyReadyAttackTime;
11018
bNotifiedReadyAttack = FALSE; //remember not notified yet
11020
dbg("ATTACK: allies notified", me);
11023
function void notifyReadyToDrop()
11026
while(_temp < multiPlayerMaxPlayers)
11028
if(allianceExistsBetween(me , _temp))
11030
//if(allyEnemy[_temp] == enemy) //only if he's attacking the same enemy
11032
msg("ready to drop" ,me , _temp);
11038
dbg("ATTACK: allies notified of drop", me);
11041
function void refreshAllyRadar()
11044
while(_temp < multiPlayerMaxPlayers)
11046
if(allianceExistsBetween(me , _temp))
11048
giftRadar(me, _temp, FALSE);
11054
// one function for all notifications
11055
function void notifyAllies(STRING _cstr, bool _bUpdateRadar)
11060
while(i < multiPlayerMaxPlayers)
11062
if(allianceExistsBetween(me, i))
11066
giftRadar(me, i, FALSE);
11074
/* Send a message to all players */
11075
function void notifyAll(STRING _cstr)
11080
while(player < multiPlayerMaxPlayers)
11082
msg(_cstr, me, player);
11087
function void notifyTakeOil(int _enemy, int _x, int _y)
11089
dropAllyBeacon("gonna get " & getPlayerName(_enemy) & "'s derrick", _x, _y);
11090
notifyAllies("gonna get " & getPlayerName(_enemy) & "'s derrick", TRUE);
11093
function void dropAllyBeacon(STRING _cstr, int _x, int _y)
11098
dropBeacon(_cstr, me, me, _x, _y, 0);
11101
while(i < multiPlayerMaxPlayers)
11103
if((allianceExistsBetween(me, i)) and (i != me))
11105
dropBeacon(_cstr, i, me, _x, _y, 0);
11111
function void requestPrepareDrop()
11113
if(enemy == none){MsgBox("requestPrepareDrop() - enemy == none"); exit;}
11116
while(_temp < multiPlayerMaxPlayers)
11118
if(allianceExistsBetween(me , _temp))
11120
giftRadar(me, _temp, FALSE);
11121
msg("drop " & enemy, me , _temp);
11127
function void notifyPrepareDrop()
11129
if(enemy == none){MsgBox("notifyPrepareDrop() - enemy == none"); exit;}
11132
while(_temp < multiPlayerMaxPlayers)
11134
if(allianceExistsBetween(me , _temp))
11136
giftRadar(me, _temp, FALSE);
11137
msg("dropping " & enemy, me , _temp);
11138
msg("preparing drop", me , _temp);
11144
function void notifyStartDrop()
11147
while(_temp < multiPlayerMaxPlayers)
11149
if(allianceExistsBetween(me , _temp))
11151
msg("transporting units", me , _temp);
11157
function void notifyCantDrop()
11160
while(_temp < multiPlayerMaxPlayers)
11162
if(allianceExistsBetween(me , _temp))
11164
if(allyEnemy[_temp] == enemy)
11166
msg("can't drop", me , _temp);
11173
function void notifyLoadedTransporters()
11176
while(_temp < multiPlayerMaxPlayers)
11178
if(allianceExistsBetween(me , _temp))
11180
if(allyEnemy[_temp] == enemy)
11182
msg("loaded transporters", me , _temp);
11189
function void requestStartAttack(int _enemy, int _x, int _y)
11191
if(_enemy == none){MsgBox("requestStartAttack() - _enemy == none"); exit;}
11194
while(_temp < multiPlayerMaxPlayers)
11196
if(allianceExistsBetween(me , _temp))
11198
giftRadar(me, _temp, FALSE);
11199
msg("go " & getPlayerName(_enemy), me , _temp);
11200
//dropBeacon("go " & getPlayerName(_enemy), _temp, me, _x, _y, 0);
11205
dropAllyBeacon("go " & getPlayerName(_enemy), _x, _y);
11208
function void notifyPlayerHasVTOLs(int _playerWithVTOLs)
11210
notifyAllies(getPlayerName(_playerWithVTOLs) & " got vtols", FALSE);
11213
function void notifyStatusAll()
11218
while(i < multiPlayerMaxPlayers)
11220
if(allianceExistsBetween(me , i))
11228
function void notifyStatus(int _playerToNotify)
11230
if(state == stDefendingBase)
11232
notifyAllies(getPlayerName(_playerToNotify) & ": help" , false);
11236
notifyAllies(getPlayerName(_playerToNotify) & ": defending oil" , false);
11237
dropAllyBeacon("defending oil", sendForceX, sendForceY);
11239
else if(state == stAttacking)
11241
notifyAllies(getPlayerName(_playerToNotify) & ": attacking " & getPlayerName(enemy), false);
11243
else if(state == stHelpingAlly)
11245
notifyAllies(getPlayerName(_playerToNotify) & ": helping " & getPlayerName(enemy), false);
11247
else if(state == stTakingOil)
11249
notifyAllies(getPlayerName(_playerToNotify) & ": hunting " & getPlayerName(enemy) & "'s oil" , false);
11250
dropAllyBeacon("hunting " & getPlayerName(enemy) & "'s oil", sendForceX, sendForceY);
11252
else if(((state == stDrop) or (state == stTransporting)) and (enemy != none))
11254
notifyAllies(getPlayerName(_playerToNotify) & ": dropping " & getPlayerName(enemy), false);
11256
if(phase <= phGettingUnits)
11258
notifyAllies(getPlayerName(_playerToNotify) & ": preparing drop", false);
11260
else if(phase == phWaitAllies)
11262
notifyAllies(getPlayerName(_playerToNotify) & ": ready to drop", false);
11264
else if(phase == phLoadingTransport)
11266
notifyAllies(getPlayerName(_playerToNotify) & ": loading transport", false);
11268
else if(phase == phSendDrop)
11270
notifyAllies(getPlayerName(_playerToNotify) & ": transporting units", false);
11275
function void notifyPower(int _targetPlayer)
11277
if(playerPower(me) <= noPower)
11279
msg("nope", me , _targetPlayer);
11281
else if(playerPower(me) <= lowPower)
11283
msg("not much", me , _targetPlayer);
11287
msg("yeah", me , _targetPlayer);
11291
function void notifyEnemyAtBase()
11294
while(_temp < multiPlayerMaxPlayers)
11298
if(attackedCount == 0) //first time
11300
_temp2 = random(3); //100%
11303
msg("oh no, here we go..." ,me , _temp);
11305
else if(_temp2 == 1)
11307
msg("it started" ,me , _temp);
11309
else if(_temp2 == 2)
11311
msg("they are at my base" ,me , _temp);
11314
else if((attackedCount > 0) and (attackedCount < 4))
11316
_temp2 = random(5);
11319
msg("not again..." ,me , _temp);
11321
else if(_temp2 == 1)
11323
msg("they're after my base" ,me , _temp);
11325
else if(_temp2 == 2)
11327
msg("incoming" ,me , _temp);
11330
else if((attackedCount >= 4) and (attackedCount < 10))
11332
_temp2 = random(6);
11335
msg("this is getting annoying..." ,me , _temp);
11337
else if(_temp2 == 1)
11339
msg("this sucks!" ,me , _temp);
11341
else if(_temp2 == 2)
11343
msg("duh..." ,me , _temp);
11345
else if(_temp2 == 3)
11347
msg("thery're after my base again" ,me , _temp);
11352
_temp2 = random(8);
11355
msg("why is it always my base???" ,me , _temp);
11357
else if(_temp2 == 1)
11359
msg("this sucks..." ,me , _temp);
11361
else if(_temp2 == 2)
11363
msg("duh..." ,me , _temp);
11365
else if(_temp2 == 3)
11367
msg("sooner or later they're gonna get me" ,me , _temp);
11369
else if(_temp2 == 4)
11371
msg("today is not my day..." ,me , _temp);
11373
else if((_temp2 == 5) or (_temp2 == 6))
11375
msg("they already attacked me " & attackedCount & " times!!! ... yes, I count!" ,me , _temp);
11383
timeNotifyEnemyInBase = maxTimeNotifyEnemyInBase;
11386
event defendBase(inactive)
11388
local int _cmdIndex,_edgeX,_edgeY,_numAttacked,_x,_y,_bucket;
11390
// if attacking en enemy, check if it's still safe to do so otherwise retreat
11391
/* if(baseDefendObj != NULLOBJECT)
11393
if(numEnemyWeapObjInRange(me, baseDefendObj.x, baseDefendObj.y, (6 * 128), false, true) >=
11394
(groupSizeCmds(defendGr,true,false,true) - 1))
11396
//dbg("NOT SAFE TO FOLLOW ATTACKER ANYMORE", me);
11398
//calc perim coords
11399
x = baseDefendObj.x;
11400
y = baseDefendObj.y;
11402
circlePerimPoint(baseX, baseY, ref x, ref y, (baseRange + defendCorridor / 2)); //move defense locations to the base perimeter
11404
// return those who were attacking him back to the base
11405
_bucket = initIterateGroupCmd(defendGr,true,true,false);
11406
droid = iterateGroupCmd(defendGr,_bucket);
11407
while(droid != NULLOBJECT)
11409
if((droid.target != NULLOBJECT) and (droid.target == baseDefendObj))
11411
orderDroidLoc(droid, DORDER_MOVE, x, y); //don't SCOUT
11413
droid = iterateGroupCmd(defendGr,_bucket);
11419
/* Attack any base intruders */
11420
defendArea(defendGr, baseRange, baseX, baseY, defendCorridor, minDefenders);
11422
/* Make newly built droids leave the center of the base */
11426
// we were not attacked during this game so far, recall a location from past experience
11429
if(getBaseDefendLocCount() > 0) //any locations stored?
11431
// highest priority location is always at the top
11432
if(recallBaseDefendLoc(me, 0, ref _x, ref _y, ref _numAttacked))
11434
// did we really get attacked at this location?
11435
if(_numAttacked > 0 and _x > 0 and _y > 0)
11437
// make defenders go to this location when they get built
11445
// now move defenders to this location
11446
if(_edgeX > 0 and _edgeY > 0){
11447
cleanBaseCenter(defendGr, baseRange, baseX, baseY, _edgeX, _edgeY, defendCorridor);
11451
function void cleanBaseCenter(GROUP _group, int _range, int _defendX, int _defendY,
11452
int _edgeX, int _edgeY, int _defendCorridor)
11454
local DROID _droid;
11457
/* go to the defend area perimeter, if too close to the defend area center */
11458
_bucket = initIterateGroupCmd(_group,true,true,false);
11459
_droid = iterateGroupCmd(_group,_bucket);
11460
while(_droid != NULLOBJECT)
11462
if( distBetweenTwoPoints(_droid.x, _droid.y, _defendX, _defendY) < (_range / 2)) //too close to the defend area center -> can stuck in it's our base
11464
if( !droidActionAttacking(_droid) ) //retreat even if busy but not directly attacking
11466
//make sure not going to the perimeter already
11467
// NOTE: all distances must match with those ones in defendArea()
11468
if( ! ( !droidOrderIdle(_droid) and (_droid.orderx > 0) and // moving
11469
( (distBetweenTwoPoints(_droid.orderx, _droid.ordery, _defendX, _defendY) <= (_range + _defendCorridor / 2)) and // inside defence range
11470
(distBetweenTwoPoints(_droid.orderx, _droid.ordery, _defendX, _defendY) >= (_range / 2)) ))) // not too close to the base
11472
// move to base perimeter, just before base defenses
11473
goToPerim(_defendX, _defendY, _edgeX, _edgeY,
11474
(_range + _defendCorridor / 2 - 128), DORDER_MOVE, _droid);
11478
_droid = iterateGroupCmd(_group,_bucket);
11483
function void defendArea(GROUP _defendGr, int _range, int _defendX, int _defendY, int _defendCorridor, int _minDefenders)
11485
local BASEOBJ _target;
11486
local DROID _droid;
11487
local bool _bHaveTarget,_bHaveCloserEnemy,_bEnemyInBase;
11488
local int _targetX,_targetY,_result,_result2,_reactToEnemyCorridor, _dist,_order;
11489
local int _moveCloserThreshold,_tempX,_tempY,_bucket;
11491
if(groupSizeCmds(_defendGr,true,false,true) == 0) //TODO: commanders must retreat
11496
_bHaveTarget = FALSE;
11497
_target = NULLOBJECT;
11498
_reactToEnemyCorridor = 10 * 128; //when enemy in this range, we move closer to the edge of the defence radius
11499
_order = DORDER_SCOUT;
11500
_moveCloserThreshold = 5 * 128; //if new enemy is closer by this than the old one, then make sure we assign it as a new target
11502
/* Check if have to defend anything */
11504
//look at all visible objects close to base
11505
_target = getClosestEnemy(_defendX, _defendY, _range + _defendCorridor + _reactToEnemyCorridor, FALSE, FALSE, me);
11506
if(_target != NULLOBJECT)
11508
//result = isInMyBase(obj.x, obj.y); //check in base
11510
//if(distBetweenTwoPoints(_target.x, _target.y, _defendX, _defendY) <= _range) //within defend location
11512
_bHaveTarget = TRUE;
11513
_targetX = _target.x;
11514
_targetY = _target.y;
11519
if(_bHaveTarget) //found target
11521
/* if outside of the base and too dangerous to attack directly, move to the perimeter */
11522
_bEnemyInBase = FALSE; //outside?
11523
if(distBetweenTwoPoints(_defendX, _defendY, _targetX, _targetY) >
11524
(_range + _defendCorridor))
11526
_bEnemyInBase = TRUE;
11528
//calc perim coords
11531
circlePerimPoint(_defendX, _defendY, ref _tempX, ref _tempY, (_range + _defendCorridor / 2)); //move defense locations to the base perimeter
11533
/* If for base defenders, then remember defend location for newly built units */
11534
if(_defendGr == defendGr)
11541
_result = numFriendlyWeapObjInRange(me, _targetX, _targetY, (10 * 128), false, true);
11542
_result2 = numEnemyWeapObjInRange(me, _targetX, _targetY, (10 * 128), false, true);
11544
if((groupSizeCmds(_defendGr,true,false,true) >= _minDefenders) or (_result >= _result2)) //don't send one by one or if dangerous
11546
_bucket = initIterateGroupCmd(_defendGr,true,true,true);
11547
_droid = iterateGroupCmd(_defendGr,_bucket);
11548
while(_droid != NULLOBJECT)
11550
_order = DORDER_SCOUT; //default defend order
11552
/* if unit already going to defend loc, check if there's actually an enemy left at that loc */
11553
_bHaveCloserEnemy = FALSE;
11555
//if we have an enemy inside, then cancel order to the perim
11556
if(_bEnemyInBase and (_droid.orderx > 0) and (numEnemyWeapObjInRange(me, _droid.orderx, _droid.ordery, (7 * 128), false, true) == 0))
11558
_bHaveCloserEnemy = TRUE;
11561
/* Check if there's a new target which is closer to the base heart */
11562
if(not _bHaveCloserEnemy) //won't move defender already anyway
11564
if(_droid.orderx > 0)
11566
_dist = distBetweenTwoPoints(_defendX, _defendY, _droid.orderx, _droid.ordery) - distBetweenTwoPoints(_defendX, _defendY, _targetX, _targetY);
11567
if(_dist > _moveCloserThreshold) //if much closer
11569
_bHaveCloserEnemy = TRUE; //move back a bit
11570
_order = DORDER_MOVE; //make sure will go directly to the closest enemy
11571
dbg("FOUND A CLOSER ENEMY!!!", me);
11576
//nothing or returning to base
11577
if(droidOrderIdle(_droid) or (_droid.order == DORDER_MOVE) or _bHaveCloserEnemy)
11579
//don't touch if attacking arty and don't make it 'break-dance', if already there
11580
if((_droid.order != DORDER_ATTACK) and (distBetweenTwoPoints(_droid.x, _droid.y, _targetX, _targetY) > _moveCloserThreshold))
11582
orderDroidLoc(_droid, _order, _targetX, _targetY);
11586
_droid = iterateGroupCmd(_defendGr,_bucket);
11591
/* check if defenders went too far from defend location */
11592
_bucket = initIterateGroupCmd(_defendGr,true,true,true);
11593
_droid = iterateGroupCmd(_defendGr,_bucket);
11594
while(_droid != NULLOBJECT)
11596
if( (distBetweenTwoPoints(_droid.x, _droid.y, _defendX, _defendY) >
11597
(_range + _defendCorridor)))//too far from base
11599
if( _droid.order != DORDER_ATTACK ) //retreat even if busy but not directly attacking
11601
//make sure not returning already
11602
// if( ! ( !droidOrderIdle(_droid) and (_droid.orderx > 0) and // moving
11603
// ( (distBetweenTwoPoints(_droid.orderx, _droid.ordery, _defendX, _defendY) <= (_range + _defendCorridor / 2)) and // inside defence range
11604
// (distBetweenTwoPoints(_droid.orderx, _droid.ordery, _defendX, _defendY) >= (_range / 2)) ))) // not too close to the base
11605
if( ! ( !droidOrderIdle(_droid) and (_droid.orderx > 0) and // moving
11606
(distBetweenTwoPoints(_droid.orderx, _droid.ordery, _defendX, _defendY) <= (_range + _defendCorridor / 2) ) )) // inside defence range
11608
// move to base perimeter, just before base defenses
11609
goToPerim(_defendX, _defendY, _droid.x, _droid.y,
11610
(_range + _defendCorridor / 2 - TILE), DORDER_MOVE, _droid);
11615
_droid = iterateGroupCmd(_defendGr,_bucket);
11618
//dbg(" " & me & ") END defendBase");
11621
function void goToPerim(int _centerX, int _centerY, int _fromX,
11622
int _fromY, int _perimRange, int _order, DROID _droid)
11624
// find a closest point at a base perimeter to retreat to
11625
circlePerimPoint(_centerX, _centerY, ref _fromX, ref _fromY, _perimRange);
11628
orderDroidLoc(_droid, _order, _fromX, _fromY);
11631
function void findFreeSpot(int _x, int _y)
11638
if(pickStructLocation(fac, ref _temp, ref _temp2, me))
11640
retInt = _temp; retInt2 = _temp2;
11647
function void findFreeSpotMedium(int _x, int _y)
11654
if(pickStructLocation(powGen, ref _temp, ref _temp2, me))
11656
retInt = _temp; retInt2 = _temp2;
11663
function void findFreeSpotSmall(int _x, int _y)
11670
if(pickStructLocation(wall, ref _temp, ref _temp2, me))
11672
retInt = _temp; retInt2 = _temp2;
11676
function void startCollecting()
11678
setState(stCollecting);
11680
dbg("COLLECT: started collecting state", me);
11682
setCollectingLoc();
11684
startCollectingPhase();
11688
function void startCollectingPhase()
11690
setPhase(phCollecting, NONE);
11692
orderGroupLocCmd(sendAttackGr, DORDER_MOVE, collectX, collectY); //use move, cause far away units may keep attacking forever
11694
collectTime = maxCollectTime;
11696
dbg("COLLECT: started collecting at " & collectX / 128 & " - " & collectY / 128, me);
11699
function void setCollectingLoc()
11701
collectX = groupCMD_x(sendAttackGr); collectY = groupCMD_y(sendAttackGr);
11703
dbg("setCollectingLoc() - mostOfGroup(): " & collectX / 128 & " - " & collectY / 128, me);
11705
//result3 = findFreeSpot(collectX, collectY); //a lot of free space
11706
//collectX = retInt; collectY = retInt2;
11708
dbg("setCollectingLoc() - set collect at " & collectX / 128 & " - " & collectY / 128, me);
11711
//gathered units or time is up
11712
function bool canStopCollecting()
11717
if(collectTime <= 0)
11722
//temp = finishedCollecting();
11724
return(finishedCollecting());
11728
function bool finishedCollecting()
11732
/* most of them collected */
11733
if(distBetweenTwoPoints(collectX, collectY, groupCMD_x(sendAttackGr), groupCMD_y(sendAttackGr)) < (5 * 128))
11741
function bool enoughDroppers()
11743
if((groupSizeCmds(attackGr,true,false,true) + groupSizeCmds(sendAttackGr,true,false,true) +
11744
groupSizeCmds(defendGr,true,false,true) - numDefenders) >= numDroppers)
11752
function bool alliesReadyToDrop()
11757
while(_temp < multiPlayerMaxPlayers)
11759
if(allianceExistsBetween(me , _temp))
11761
if(allyState[_temp] == stDrop) //gonna drop
11763
if(allyEnemy[_temp] == enemy) //dropping the same enemy as me
11765
if(allyPhase[_temp] < phWaitAllies)
11767
return(FALSE); //not ready yet
11775
return(TRUE); //all ok
11778
function int getNumTransporters()
11782
//Iterate through all player droids
11783
InitEnumDroids(me,me);
11784
_droid = EnumDroid();
11785
while(_droid != NULLOBJECT)
11787
if(_droid.droidType == DROID_TRANSPORTER)
11792
_droid = EnumDroid();
11798
function bool enoughTransporters()
11800
temp = numTransporters;
11802
temp2 = getNumTransporters();
11812
function void buildTransporters()
11814
temp = numTransporters;
11816
/* how many got already */
11817
temp2 = getNumTransporters();
11818
//temp2 = temp2 + numTemplatesInProduction(tmplUnitransporter,me); //FIXME
11820
//if(temp2 >= temp){exit;}
11822
/* build transporters */
11823
initEnumStruct(FALSE,vtolfac,me,me);
11824
tempStruct = enumStruct();
11825
while((tempStruct != NULLOBJECT) and (temp2 < temp))
11827
if(structureIdle(tempStruct))
11829
//if(skCanBuildTemplate(me, tempStruct, tmplUnitransporter))
11830
if(skGetFactoryCapacity(tempStruct) >= 2) //fully upgraded
11832
dbg("started to build transporter", me);
11833
//buildDroid(tmplUnitransporter, tempStruct, me, 1); //FIXME
11838
tempStruct = enumStruct();
11842
function void fillDroppers()
11846
temp = groupSizeCmds(defendGr,true,true,true) - numDefenders;
11850
while((temp > 0) and (temp2 < numDroppers)) //leave 'numDefenders' number of units in the defendGr
11853
tempDroid2 = NULLOBJECT;
11855
/* get closest tank */
11856
_bucket = initIterateGroupCmd(defendGr,true,false,true); //TODO: make work with commanders
11857
tempDroid = iterateGroupCmd(defendGr,_bucket);
11858
while(tempDroid != NULLOBJECT)
11860
temp3 = distBetweenTwoPoints(baseX, baseY, tempDroid.x, tempDroid.y);
11864
tempDroid2 = tempDroid;
11866
tempDroid = iterateGroupCmd(defendGr,_bucket);
11869
if(tempDroid2 != NULLOBJECT) //got closest
11871
groupAddDroid(sendAttackGr, tempDroid2);
11875
temp2 = numDroppers; //exit loop
11878
temp = temp - 1; //one less left in defendGr
11879
temp2 = temp2 + 1; //one more loaded
11882
selectGroup(sendAttackGr, TRUE);
11885
function void dropLoadTransport()
11891
dbg("loading total " & numTransporters & " transporters (" & groupSizeCmds(transportGr,true,true,true) & " units)",me);
11893
if(groupSizeCmds(transportGr,true,true,true) == 0){exit;} //include commanders
11895
/* load transports */
11898
while(temp < maxTransporters)
11900
if(transporter[temp] != NULLOBJECT)
11902
temp5 = transporterCapacity(transporter[temp]);
11903
//dbg("transporterCapacity[" & temp & "] = " & temp5, me);
11908
tempDroid2 = NULLOBJECT;
11910
/* get closest tank */
11911
_bucket = initIterateGroupCmd(transportGr,true,false,true); //TODO: make work with commanders
11912
tempDroid = iterateGroupCmd(transportGr,_bucket);
11913
while(tempDroid != NULLOBJECT)
11915
if(tempDroid.order != DORDER_EMBARK)
11917
//dbg("!= DORDER_EMBARK", me);
11919
temp3 = distBetweenTwoPoints(transporter[temp].x, transporter[temp].y, tempDroid.x, tempDroid.y);
11923
tempDroid2 = tempDroid;
11926
tempDroid = iterateGroupCmd(transportGr,_bucket);
11929
if(tempDroid2 != NULLOBJECT) //got closest
11931
//dbg("Unit embarking", me);
11932
orderDroidObj(tempDroid2, DORDER_EMBARK, transporter[temp]);
11943
function bool transporterLoaded()
11945
/* check if anyone is still waiting to be loaded */
11946
if(groupSizeCmds(transportGr,true,true,true) <= numTransporters) // > 90% loaded
11948
dbg("transporter loaded!!!", me);
11952
/* check if loaded max number of droids (for example 20 for 2 transporters) */
11953
temp = numDroidsLoaded();
11954
temp2 = getNumTransporters();
11956
if(temp >= (temp2 * 10))
11958
dbg("transporter loaded!!! 2", me);
11962
//dbg("transporter not loaded", me);
11966
//returns how many drois were loaded into transporters
11967
function int numDroidsLoaded()
11969
/* load transports */
11971
_temp2 = 0; //how many loaded
11973
while(_temp < maxTransporters)
11975
if(transporter[_temp] != NULLOBJECT)
11977
_temp2 = (10 - transporterCapacity(transporter[_temp])) + _temp2;
11986
function int numActiveEnemyDrop(int _enemyToCheck)
11988
if(_enemyToCheck < 0){return(maxAllyDroppers);}
11992
while(_temp < multiPlayerMaxPlayers)
11994
if((_temp != me) and (allianceExistsBetween(me , _temp)))
11996
if((allyState[_temp] == stDrop) and (allyEnemy[_temp] == _enemyToCheck) and (allyPhase[_temp] >= phWaitAllies)) //will drop very soon
11998
retInt = retInt + 1;
12007
function int numAlliesDroppingPlayer(int _player)
12009
if(_player < 0){return(maxAllyDroppers);}
12013
while(_temp < multiPlayerMaxPlayers)
12015
if((_temp != me) and (allianceExistsBetween(me , _temp)))
12017
if((allyState[_temp] == stDrop) and (allyEnemy[_temp] == _player))
12019
retInt = retInt + 1;
12028
function bool timeToDrop()
12030
//drop if we are further away from the enemy than all allies or if our turn has came
12032
if((curBase[enemy][0] <= 0) or (curBase[enemy][1] <= 0))
12034
MsgBox("timeToDrop - curBase[enemy][x/y] <= 0 (" & me & ")");
12039
MsgBox("timeToDrop - no enemy set (" & me & ")");
12043
_range = distBetweenTwoPoints(baseX, baseY, curBase[enemy][0], curBase[enemy][1]) + (3 * 128); //+ (3 * 128) := reduce the cahnce that no one starts since all players store different ally coords
12046
while(_temp < multiPlayerMaxPlayers)
12048
if((_temp != me) and (allianceExistsBetween(me , _temp)))
12050
//if((allyState[_temp] == stDrop) and (allyEnemy[_temp] == enemy) and (allyPhase[_temp] >= phWaitAllies)) //check only those allies that are dropping the same enemy and are potentially ready
12051
if((allyState[_temp] == stDrop) and (allyEnemy[_temp] == enemy))
12053
if(allyPhase[_temp] < phSync) //someone not loaded transporters yet
12059
dbg("Ally phase is " & allyPhase[_temp], me);
12062
if((curBase[_temp][0] > 0) and (curBase[_temp][1] > 0)) //know where this ally is
12064
_temp2 = distBetweenTwoPoints(curBase[_temp][0], curBase[_temp][1], curBase[enemy][0], curBase[enemy][1]);
12066
/* is he farther away than all */
12067
if(_temp2 > _range)
12070
_temp3 = _temp; //remember furtherst ally
12079
if(_temp3 == me) //no ally is farther than us or we're the only player dropping
12081
dbg("timeToDrop - i'm furthest!!!!!", me);
12082
return TRUE; //we are first
12085
/* check if anyone has started transporting already */
12086
if(dropStartTime == none)
12088
return(FALSE); //wait for the furtherst player to start dropping
12091
/* check how much time passed since first ally started drop, assuming sped = 1 tile/s */
12092
_temp = distBetweenTwoPoints(curBase[_temp3][0], curBase[_temp3][1], curBase[enemy][0], curBase[enemy][1]) - distBetweenTwoPoints(baseX, baseY, curBase[enemy][0], curBase[enemy][1]); //dist diff ((ally - enemy) - (me - enemy))
12093
if((GAME_TIME_IN_SECS - dropStartTime) >= (_temp / 128)) //more time passed in secs than the diff in tiles between (furtherst ally - enemy) and (me - enemy)
12095
dbg("timeToDrop() - syncing drop!!!!!", me);
12096
return(TRUE); //now!!
12099
return(FALSE); //not yet, wait to sync drop
12102
function void doDrop()
12104
if((transportX <= 0) or (transportY <= 0))
12106
MsgBox("doDrop - transportX <= 0 (" & me & ")");
12110
dbg("doDrop!!!", me);
12112
notifyStartDrop(); //tell we are starting to drop now
12114
/* if some units could not be loaded into transporters, add to defenders */
12115
if(groupSizeCmds(transportGr,true,true,true) > 0) //TODO: deal with commanders
12117
_temp = groupSizeCmds(transportGr,true,true,true);
12118
groupAddGroupCmd(defendGr, transportGr);
12119
dbg(" " & _temp & " units could not be loaded", me);
12123
while(temp < numTransporters)
12125
if(transporter[temp] != NULLOBJECT)
12127
orderTranspDisembark(transporter[temp], transportX, transportY);
12132
/* return those who were not loaded back to defenders */
12133
groupAddGroupCmd(defendGr, transportGr);
12136
//---------------------------------------------
12137
// order transporter to send
12138
//---------------------------------------------
12139
function void orderTranspDisembark(DROID _transporter, int _coordx, int _coordy)
12141
bTempResult = chooseValidLoc(ref temp2, ref temp3, _coordx, _coordy, me, -1); //no threat check
12144
dbg("ordered to disembark", me);
12145
orderDroidLoc(_transporter, DORDER_DISEMBARK, temp2, temp3);
12149
dbg("couldn't find a valid location for DISEMBARK!!!!!!!!!!!", me);
12153
event transLanded(inactive)
12155
dbg("Transporter landed", me);
12157
if(groupSizeCmds(tempGr,true,true,true) == 0){exit;}
12159
if((state == stNone) or defendingBase()) //not doing anything, so unload to defenders
12161
groupAddGroupCmd(defendGr, tempGr);
12165
dbg("Added " & groupSizeCmds(tempGr,true,true,true) & " units to sendAttackGr", me);
12166
groupAddGroupCmd(sendAttackGr, tempGr); //TODO: won't work with commanders?
12169
/* check if have to fly it back to the base */
12170
if(not isInMyBase(droid.x, droid.y))
12172
dbg("ordering transporter back to base", me);
12174
findFreeSpotSmall(baseX, baseY);
12175
temp2 = retInt; temp3 = retInt2;
12177
orderDroidLoc(droid, DORDER_MOVE, temp2, temp3);
12181
function bool checkTransportersLanded()
12183
local bool _bLanded;
12185
_bLanded = TRUE; //all landed
12188
while(temp < numTransporters)
12190
if(transporter[temp] != NULLOBJECT)
12192
if(transporterCapacity(transporter[temp]) < 10) //not all unloaded
12203
function int setNumDroppers()
12205
retInt = maxDroppers;
12207
/* check how much we will have to invest into this drop */
12208
if(playerPower(me) < highPower)
12210
temp = numAvailableAttackers();
12213
if((retInt - temp) > 10) //can't afford building this many
12215
retInt = medDroppers;
12216
dbg("Medium droppers", me);
12219
temp = calcNumRequiredTransporters(retInt);
12221
temp2 = getNumTransporters();
12223
/* check transporters */
12224
if((temp - temp2) >= 1) //allow to build only 1 new transp for every drop
12226
retInt = (temp2 + 1) * 10; //as many as we have transporters already + 1
12227
//if(temp2 <= 0) //no transporters yet
12229
// retInt = minDroppers; //smallest drop possible
12230
// dbg("Min droppers", me);
12233
dbg("Min droppers", me);
12235
/* make sure we stay in bounds */
12236
if(retInt > maxDroppers)
12238
retInt = maxDroppers;
12246
function int calcNumRequiredTransporters(int _numUnits)
12248
/* decide how many transporters we need */
12249
_retInt = _numUnits / 10;
12250
if((_retInt * 10) != _numUnits) //fix integer div
12252
_retInt = _retInt + 1;
12255
if(_retInt > maxTransporters)
12257
_retInt = maxTransporters;
12263
function void prepareTransporters()
12267
while(temp < numTransporters)
12269
if(transporter[temp] != NULLOBJECT)
12271
if(groupSizeCmds(transportGr,true,true,true) > 0)
12273
temp2 = groupCMD_x(transportGr);
12274
temp3 = groupCMD_y(transportGr);
12276
circlePerimPoint(baseX, baseY, ref temp2, ref temp3, baseRange);
12278
findFreeSpotMedium(temp2, temp3);
12279
temp2 = retInt; temp3 = retInt2;
12281
orderDroidLoc(transporter[temp], DORDER_MOVE, temp2, temp3);
12289
function void updateDropPhase()
12291
/* check if already can build transporter */
12292
if(phase == phGettingTech)
12294
//if(researchFinished(resUnitTransporter, me))
12296
setPhase(phGettingUnits, NONE);
12300
if(phase == phGettingUnits)
12302
result3 = getNumTransporters();
12304
/* if we hit unit limit, we'll never be able to build transporters */
12305
if((result3 < numTransporters) and (getDroidCount(me) >= unitLimit))
12307
if(result3 > 0) //got at least 1 transp
12309
numTransporters = result3; //continue with whatever we have
12310
numDroppers = numTransporters * 10;
12314
/* check if have enough units and transp for drop */
12315
//result = enoughDroppers();
12316
//result2 = enoughTransporters();
12318
if(enoughDroppers() and enoughTransporters())
12320
/* notify allies and start waiting for other allies */
12321
notifyReadyToDrop();
12322
prepareTransporters(); //make sure units can reach them
12323
tWaitAlliesDrop = tMaxWaitAlliesDrop; //start wait-for-allies timer
12325
setPhase(phWaitAllies, NONE); //wait for others
12329
if(phase == phWaitAllies)
12331
/* check if other allies are also ready to drop */
12332
if(alliesReadyToDrop() or (tWaitAlliesDrop <= 0)) //all ready or waited for too long
12336
startTransportState(sendAttackGr, curBase[enemy][0], curBase[enemy][1]);
12340
/* we are back from transport state */
12341
if(phase == phTransportDone)
12343
stopDropState(); //can stop drop now and resume any paused state (if any)
12347
function void updateTransport()
12349
if(phase == phLoadingTransport)
12351
if(transporterLoaded()) //loaded
12353
setPhase(phSync, NONE);
12355
tSyncDrop = tMaxSyncDrop; //start sync with allies countdown
12356
notifyLoadedTransporters();
12357
//exit; //if just finished dropping enemy, give allies time to reset their states, otherwise will think they are still dropping some enemy
12359
else if((tWaitLoadDrop <= 0) or (dropStartTime != none)) //waited too long, or someone has started drop already!!!, drop now
12361
temp = numDroidsLoaded();
12363
temp2 = numAlliesDroppingPlayer(enemy);
12365
if((temp >= (numDroppers * 30 / 100)) or ((temp2 > 0) and (temp > 0))) // 30% of all droppers were loaded or not the only one dropping and loaded something
12367
setPhase(phSync, NONE);
12369
tSyncDrop = tMaxSyncDrop; //start sync with allies countdown
12370
notifyLoadedTransporters();
12371
//exit; //if just finished dropping enemy, give allies time to reset their states, otherwise will think they are still dropping this enemy
12375
cancelTransportState(); //couldn't load enough
12380
dropLoadTransport();
12384
/* syncronize drop with allies, wait if needed */
12385
if(phase == phSync)
12387
if(timeToDrop() or (tSyncDrop <= 0)) //can drop now or waited too long
12391
dbg("tSyncDrop timeout - time to drop!!!!", me);
12395
dbg("timeToDrop() - time to drop!!!!", me);
12398
setPhase(phSendDrop, NONE); //on the way to the enemy
12404
dbg("waiting for my turn to drop", me);
12408
/* watch for transporters to arrive */
12409
if(phase == phSendDrop)
12411
if( checkTransportersLanded() ) //all unloaded
12413
dbg("Transporter landed!!!!!!!!!!!", me);
12414
stopTransportState();
12418
//dbg("phase = " & phase, me);
12421
function void startTransportState(GROUP _groupToTransport, int _destinationX, int _destinationY)
12423
dbg("Starting transport phase!!!!!!", me);
12425
transportX = _destinationX;
12426
transportY = _destinationY;
12427
transportGr = _groupToTransport;
12429
temp = getNumTransporters();
12432
cancelTransportState();
12436
if(state != stNone)
12438
saveCurrentState();
12441
endState(); //init vars of the original state
12443
setState(stTransporting);
12445
setPhase(phLoadingTransport, NONE);
12447
tWaitLoadDrop = tMaxWaitLoadDrop;
12449
dropLoadTransport();
12452
function void saveCurrentState()
12454
savedState = state;
12455
//savedPhase = phase;
12456
//savedEnemy = enemy;
12459
function void loadSavedState()
12461
dbg("loading saved state!!!!!!!!", me);
12463
if(savedState == stDrop)
12465
/* after drop complete start attacking enemy */
12467
dbg("loaded drop state!!!!!!!!", me);
12469
setState(savedState);
12471
else //?, just init state and phase vars
12473
stopTransportState();
12477
eraseLoadSavedState();
12480
function void eraseLoadSavedState()
12482
savedState = stNone;
12483
savedPhase = phNone;
12487
function void resortTransporters()
12490
while(temp < maxTransporters)
12492
if(transporter[temp] == NULLOBJECT)
12494
/* check if we have a droid up in the array */
12495
temp2 = temp + 1; //go up from current, assume bottom fixed
12496
while((temp2 < maxTransporters) and (transporter[temp] == NULLOBJECT))
12498
if(transporter[temp2] != NULLOBJECT)
12500
/* swap in array */
12501
transporter[temp] = transporter[temp2];
12502
transporter[temp2] = NULLOBJECT;
12514
function void startDropPhase()
12516
if(enemy < 0){MsgBox("startDropPhase - enemy < 0"); return;}
12517
if((curBase[enemy][0] <= 0) or (curBase[enemy][1] <= 0)){MsgBox("startDropPhase - enemy coords < 0"); return;}
12518
if(not knowBase[enemy]){MsgBox("startDropPhase - knowBase[enemy] == FALSE"); return;}
12522
setPhase(phGettingTech, NONE);
12524
tempReinfCount[enemy] = 0; //reset here
12525
dropStartTime = none;
12528
/* decide how many units we will drop */
12529
numDroppers = setNumDroppers();
12531
/* decide how many transporters we need */
12532
numTransporters = calcNumRequiredTransporters(numDroppers);
12534
dbg("Preparing drop at " & getPlayerName(enemy) & " with " & numDroppers & " units and " & numTransporters & " transporters!!", me);
12536
updateStateCoord(curBase[enemy][0], curBase[enemy][1]);
12538
resortTransporters(); //resort array
12543
function void updateStateCoord(int _newx, int _newy)
12545
sendForceX = _newx;
12546
sendForceY = _newy;
12549
/* Fill attackers, prepare commanders etc */
12550
function void prepareAttackers(bool _bHighPriorityTask)
12552
local int _numNeedToBeAssigned;
12554
/* Unassign all units from all commanders in the defendGr to the defendGr */
12555
unassignAllDroidsFromCMDsFromGroup(defendGr, defendGr);
12557
/* Add required number of units from defendGr to sendAttackGr (non-commanders only) */
12558
fillAttackers(numAttackersFromPriorty(_bHighPriorityTask));
12560
/* Make commanders fromattack group take over units without commander from attackGr */
12561
assignDroidsToBestCommandersFromGroup(attackGr,attackGr);
12563
/* Make commanders fromattack group take over units without commander from sendAttackGr */
12564
assignDroidsToBestCommandersFromGroup(attackGr,sendAttackGr);
12566
/* Count how many droids will end up being unassigned after using all commanders in sendAttackGr and attackGr groups */
12567
_numNeedToBeAssigned = groupSizeCmds(sendAttackGr, true, false, false) + //count unassigned droids
12568
groupSizeCmds(attackGr, true, false, false) -
12569
getFreeCmdsCapacityInGroup(sendAttackGr) -
12570
getFreeCmdsCapacityInGroup(attackGr);
12572
/* Add commanders to the sendAttackGr until we have enough commanders to assign all droids to them */
12573
if(_numNeedToBeAssigned > 0){
12574
fillBestCommandersCapacity(_numNeedToBeAssigned, sendAttackGr, defendGr);
12577
dbg("Num new commanders attacking: " &
12578
groupSizeCmds(sendAttackGr, false, true, false), me);
12580
/* Make new commanders from group sendAttackGr take over unassigned droids from sendAttackGr,
12581
unassigned units from attackGr will be taken over after this new commanders have reached attack loc,
12582
to make sure unassigned units will not travel back to the base to meet the need commander */
12583
assignDroidsToBestCommandersFromGroup(sendAttackGr, sendAttackGr);
12585
/* Make commanders left in the defendGr take over the rest of the unassigned droids from group defendGr */
12586
assignDroidsToBestCommandersFromGroup(defendGr, defendGr);
12588
/* NOTE: unassigned droids from attackGr will get assigned to the coming commanders
12589
* after commanders have reached destination point and get assigned to the attackGr */
12592
/* Start attacking enemy base - a Wrapper for startAttack() */
12593
function void startEnemyBaseAttack(int _enemy)
12595
attackReason = ATTACK_BASE;
12597
startAttack(_enemy, curBase[_enemy][0], curBase[_enemy][1]);
12600
/* Start attacking enemy arty - a Wrapper for startAttack() */
12601
function void startArtyCounterAttack(int _enemy, int _x, int _y)
12603
attackReason = ATTACK_COUNTER_ARTY;
12605
startAttack(_enemy, _x, _y);
12608
function void startAttack(int _enemy, int _x, int _y)
12613
MsgBox("startAttack - enemy (" & _enemy & ") < 0");
12617
if((_x <= 0) or (_y <= 0)){MsgBox("startAttack - enemy coords < 0"); return;}
12618
//if(not knowBase[enemy]){MsgBox("startAttack - knowBase[enemy] == FALSE"); return;}
12620
//if(state != stNone){return;}
12622
dbg("Starting attack at " & getPlayerName(_enemy) & " !!!!!", me);
12624
setState(stAttacking);
12628
updateStateCoord(_x, _y);
12630
/* Set minimum number of defenders to leave in the base */
12631
updateNumDefenders();
12633
/* Assign attackers and commanders to groups */
12634
prepareAttackers(false);
12638
/* reset notification stuff */
12639
bNotifiedReadyAttack = FALSE;
12640
notifyReadyAttackTime = 0;
12642
reinfCount[enemy] = reinfCount[enemy] + 1;
12643
tempReinfCount[enemy] = tempReinfCount[enemy] + 1;
12645
countTakeOil = 0; //allow hunting oil again
12648
//Attack enemy base with VTOLs
12649
function void vStartAttackBase(int _enemy)
12651
if(_enemy < 0){MsgBox("startAttack - _enemy < 0"); return;}
12652
if((_x <= 0) or (_y <= 0)){MsgBox("startAttack - enemy coords < 0"); return;}
12653
if(not knowBase[_enemy]){return;}
12655
//if(state != stNone){return;}
12657
dbg("Starting attack at " & getPlayerName(_enemy) & " !!!!!", me);
12659
//vstate = stAttackBase;
12663
//sendForceX = curBase[venemy][0];
12664
//sendForceY = curBase[venemy][1];
12666
//VTOLAttackBase(venemy);
12670
function void vAttackBase(int _enemy)
12672
local BASEOBJ _newTarget;
12674
if(vtolGr.members < minVtolAttackers)
12680
//check if too well defended
12681
if(not vtolSafe(vsendForceX, vsendForceY))
12688
if(idleGroupCmd(vtolGr) >= (vtolGr.members / 2))
12691
_newTarget = vBaseTarget(_enemy);
12693
if(_newTarget == NULLOBJECT)
12695
vstopState(); //nothing to attack
12699
vDoAttackObj(vtolGr, _newTarget);
12704
function void startMovePhase()
12706
if((sendForceX <= 0) or (sendForceY <= 0)){MsgBox("startMovePhase() - sendForceXY <= 0"); return;}
12708
orderGroupLocCmd(sendAttackGr, DORDER_SCOUT, sendForceX, sendForceY);
12710
reinfTime = maxReinfTime; //start "cancel attack" countdown
12712
setPhase(phMoveToLoc, NONE);
12714
dbg("MOVE PHASE: started", me);
12717
function void startTakingOil(STRUCTURE _enemyDerrick)
12719
local int _numAttackers;
12721
if(_enemyDerrick == NULLOBJECT){MsgBox("startTakingOil - derrick == NULLOBJECT"); return;}
12723
//if(enemy < 0){MsgBox("startTakingOil - enemy < 0"); exit;}
12724
//if((sendForceX <= 0) or (sendForceY <= 0)){MsgBox("startTakingOil - sendForceXY <= 0"); exit;}
12726
setState(stTakingOil);
12728
enemy = _enemyDerrick.player;
12729
tempReinfCount[enemy] = 0; //reset
12731
updateStateCoord(_enemyDerrick.x, _enemyDerrick.y);
12733
/* Set minimum number of defenders to leave in the base */
12734
updateNumDefenders();
12736
dbg("Starting taking " & getPlayerName(enemy) & "'s oil at " & sendForceX / 128 & " - " & sendForceY / 128 & "!!!!!", me);
12738
/* Assign attackers and commanders to groups */
12739
prepareAttackers(false);
12743
timeGuardPos = 0; //cancel countdown
12744
tTakeOil = tMaxTakeOil;
12746
countTakeOil = countTakeOil + 1; //remember how many times we took oil
12748
//phase = phMoveToLoc;
12751
/* Changes state and returns old state */
12752
function void setState(int _newState)
12754
local int _oldState;
12756
/* Initialize state time */
12762
//return _oldState;
12765
/* Changes vtol state and returns old state */
12766
function void vsetState(int _newState)
12768
local int _oldState;
12770
/* Initialize state time */
12773
_oldState = vstate;
12774
vstate = _newState;
12776
//return _oldState;
12779
//don't leave BBs in defend group
12780
function int sortOutBBs()
12782
local DROID _bbDroid;
12783
local int _bucket,_numBBs;
12785
_bucket = initIterateGroupCmd(defendGr,true,false,true);
12786
_bbDroid = iterateGroupCmd(defendGr,_bucket);
12787
while(_bbDroid != NULLOBJECT)
12789
if(_bbDroid.weapon == weaponBB)
12791
groupAddDroid(sendAttackGr,_bbDroid);
12794
_bbDroid = iterateGroupCmd(defendGr,_bucket);
12800
function void doAttack()
12803
local BASEOBJ _target;
12805
//dbg(" " & me & ") doAttack()");
12807
//if(state != stAttacking){return;}
12809
//if going back to base, check if already there
12810
//-----------------------------------------------
12814
range = (20 * 128); //attacker reached home base range
12815
initIterateGroup(sendAttackGr);
12816
droid = iterateGroup(sendAttackGr);
12817
while(droid != NULLOBJECT)
12819
if(distBetweenTwoPoints(droid.x, droid.y, droid.orderx, droid.ordery) < range)
12821
groupAddDroid(defendGr,droid);
12822
}//check if going back to base
12823
else if(distBetweenTwoPoints(baseX, baseY, droid.orderx, droid.ordery) >= range)
12825
orderDroid(droid, DORDER_RTB); //send back to base
12828
droid = iterateGroup(sendAttackGr);
12831
//Migration not over yet?
12832
if(sendAttackGr.members <= 5)
12834
groupAddGroup(defendGr, sendAttackGr);
12836
dbg("attackers backin the base !!!", me);
12841
//all real attack stuff comes here
12842
//-----------------------------------------------
12845
if(enemy < 0){MsgBox("doAttack - enemy < 0");return;}
12847
/* check if someone has destroyed our enemy */
12848
//if(dead[enemy] or ((not knowBase[enemy]) and (phase < phAttackingLoc))) //only if phAttacking < attacking => someone else did it
12849
if(dead[enemy] and (phase < phAttackingLoc)) //only if phAttacking < attacking => someone else did it
12851
dbg("someone destroyed enemy, cancel attack", me);
12856
if((curBase[enemy][0] <= 0) or (curBase[enemy][1] <= 0)){MsgBox("doAttack - enemy (" & enemy & ")coords < 0"); return;}
12860
/* Update coordinates */
12861
//if(curBase[enemy][0] > 0 and curBase[enemy][1] > 0) //only update if set?
12864
// Update current goto location to the new base location of current enemy if we are attacking its base
12865
if(attackingEnemyBase(enemy))
12867
updateStateCoord(curBase[enemy][0], curBase[enemy][1]);
12871
//------------------------------------------------------------------------------
12872
//if we lost enemy base, were looking for it and found it, switch back to attack
12873
//------------------------------------------------------------------------------
12874
if((phase == phSearchingForBase) and canSeePlayerBase(enemy))
12876
dbg("after revealing found enemy base again, attack (!!!!!!!!!!!!)", me);
12877
setPhase(phMoveToLoc, NONE); //go to the new enemy base location
12879
taunt(enemy, TAUNT_REDISCOVERED_BASE, 40);
12882
//--------------------------------------------------
12883
//send reinforcements
12884
//--------------------------------------------------
12885
//result = defendGr.members - numDefenders; //available units
12886
//if((result >= minReinforcements) or ((result >= minReinforcements / 2) and (attackGr.members >= numAttackers / 2)) ) //enough reinf, or still many attackers and some reinf
12889
//------------------------------------------------
12891
//------------------------------------------------
12893
//if there are enemy structures left, move closer to them to attack, don't run away
12895
//if((phase == phAttackingLoc) and (seeBase[enemy])) //not revealing the base territory already
12897
if(phase != phSearchingForBase) //not already revealing
12899
if((sendForceX > 0) and (sendForceY > 0))
12901
if(canSeeLoc(sendForceX, sendForceY)) //no targets, check if any unrevealed territory left
12903
//if this loc is not recalled from memory (loc will be invisible then)
12904
//if((curBase[enemy][0] != base[enemy][0]) or (curBase[enemy][1]) != base[enemy][1])
12905
//if(mapRevealedInRange(sendForceX, sendForceY, (2 * 128), me)) //if revealed so can judge if there's nothing
12907
if(!enemyTargetInRange(enemy, sendForceX, sendForceY, (TILE * 3)))
12909
_target = findEnemyTargetInRange(enemy, sendForceX, sendForceY, (TILE * 13), true, true);
12911
// go to that target
12912
if(_target != NULLOBJECT)
12914
dbg("found new target at " & _target.x / TILE & " - " & _target.y / TILE, me);
12916
updateStateCoord(_target.x, _target.y);
12920
dbg("ATTACK: No visible enemy structures left, revealing territory !!!!!", me);
12922
setPhase(phSearchingForBase, MINUTE * 2); // 2 mins max
12924
taunt(enemy, TAUNT_LOST_BASE, 40);
12932
//reveal territory near the enemy base
12933
if(phase == phSearchingForBase)
12935
range = (TILE * 16); //search for enemy structures in en base range
12937
_bucket = initIterateGroupCmd(attackGr,true,true,true);
12938
droid = iterateGroupCmd(attackGr,_bucket);
12939
while(droid != NULLOBJECT)
12941
if(droidOrderIdle(droid) and !droidActionAttacking(droid))
12943
//reveal more territory in the range of the enemy base, no threat check
12944
if(fogTileInRange(ref x, ref y, droid.x, droid.y, sendForceX, sendForceY, range, me, -1)) //no threat check
12946
orderDroidLoc(droid, DORDER_SCOUT, x, y);
12948
else if(phase != phLostBase)
12950
dbg("nothing to reveal anymore, lost enemy base !!!", me);
12951
setPhase(phLostBase, MINUTE * 1); //no more unrevealed territory
12954
droid = iterateGroupCmd(attackGr,_bucket);
12958
//dbg(" " & me & ") END doAttack()");
12961
/* range in world units!!!! */
12962
function void findAttackBaseTarget(DROID _looker, int _x, int _y, int _radius)
12964
ASSERT(_looker != NULLOBJECT, "findAttackBaseTarget: _looker is NULLOBJECT", me);
12966
retObj = NULLOBJECT;
12968
//dbg(" " & me & ") findAttackBaseTarget");
12971
if((_looker.order == DORDER_NONE) or (_looker.order == DORDER_SCOUT) or (_looker.order == DORDER_MOVE))
12972
//if(_looker.order != DORDER_ATTACK)
12974
//dbg(" " & me & ") no order");
12975
if(objHasWeapon(_looker))
12977
//dbg(" " & me & ") has weapon");
12979
/* Use weapon range if no radius specified */
12983
_radius = objWeaponMaxRange(_looker); //objWeaponMaxRange is in world units
12984
_radius = _radius + (2 * 128); //target range = droid weapon range + 2 tiles
12989
/* Use unit coords if no position set where to look for units */
12996
/* see any trucks? */
12997
tempDroid = getClosestEnemyDroidByType(_x, _y, _radius, DROID_CONSTRUCT, FALSE, me);
12999
if(tempDroid == NULLOBJECT)
13001
/* any repairers? */
13002
tempDroid = getClosestEnemyDroidByType(_x, _y, _radius, DROID_REPAIR, FALSE, me);
13004
if(tempDroid != NULLOBJECT)
13006
if(tempDroid.action == DACTION_REPAIR) //only if repairing
13008
retObj = tempDroid;
13012
if(retObj == NULLOBJECT)
13014
if(((_looker.action == DACTION_NONE) or (_looker.action == DACTION_DROIDREPAIR)) and (_looker.order == DORDER_NONE)) //didn't see a target that is actually near it
13016
retObj = getClosestEnemy(_x, _y, _radius, TRUE, FALSE, me);
13022
retObj = tempDroid;
13030
function void findBBAttackBaseTarget(DROID _looker)
13032
retObj = NULLOBJECT;
13034
//temp = (2 * 128); //"reached the destination" range
13036
if(_looker.order != DORDER_ATTACK)
13038
//dbg(" " & me & ") BB no order");
13039
if(objHasWeapon(_looker))
13041
//dbg(" " & me & ") BB has weapon");
13043
temp = objWeaponMaxRange(_looker); //objWeaponMaxRange is in world units
13046
//dbg(" " & me & ") BB has range");
13048
temp2 = (temp + (3 * 128)); //target range = droid weapon range + 3 tiles
13050
tempStruct = getClosestEnemyStructByType(_looker.x, _looker.y, temp2, REF_DEFENSE, me);
13051
if(tempStruct == NULLOBJECT)
13053
tempStruct = getClosestEnemyStructByType(_looker.x, _looker.y, temp2, REF_WALL, me);
13054
if(tempStruct == NULLOBJECT)
13056
tempStruct = getClosestEnemyStructByType(_looker.x, _looker.y, temp2, REF_WALLCORNER, me);
13059
if(tempStruct == NULLOBJECT)
13061
tempStruct = getClosestEnemyStructByType(_looker.x, _looker.y, temp2, -1, me); //any structure
13062
if(tempStruct != NULLOBJECT)
13064
//dbg(" " & me & ") BB found some structure");
13065
retObj = tempStruct;
13070
//dbg(" " & me & ") BB found wall");
13071
retObj = tempStruct;
13076
//dbg(" " & me & ") BB found defense");
13077
retObj = tempStruct;
13085
function void checkStopAttack()
13087
if(state != stAttacking){return;} //exit if doAttack() already called stopAttack()
13091
MsgBox("checkStopAttack() - enemy < 0");
13096
//------------------------------------------------------------------------------
13097
//Check if we failed
13098
//------------------------------------------------------------------------------
13099
if((reinfTime <= 0) and (phase < phAttackingLoc) and
13100
(groupSizeCmds(sendAttackGr,true,false,true) <= minAttackers)) //not actively attacking or searching for base
13102
dbg("cancelling attack !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!", me);
13104
numPlayerAttackers[enemy] = max(minAttackers, numPlayerAttackers[enemy] + random(attackersIncrease));
13106
numPlayerAttackers[enemy] = min(numPlayerAttackers[enemy], maxAttackers);
13111
//------------------------------------------------------------------------------
13112
//Check we succeeded
13113
//------------------------------------------------------------------------------
13114
else if((phase == phLostBase) and (not canSeePlayerBase(enemy))) //no enemy structures left (found)
13116
dbg("cancelling attack, RTB", me);
13118
//knowBase[enemy] = FALSE; //disabled 15.05.05 because phSearchingFor base was skipped because of this
13120
if(attackingEnemyBase(enemy))
13122
killedBase[enemy] = TRUE; //remember this one's done, but doesn't have to be completely dead, so no dead[x] = TRUE;
13124
notifyPlayerBaseDestroyed(enemy);
13132
function void gatewayDefenses()
13134
result = numTrucksSameOrder(DORDER_LINEBUILD);
13136
if(result > 0){return;} //max 1 truck can be busy with gateway defenses
13138
droid = closestIdleTruck(baseX, baseY);
13140
if(droid == NULLOBJECT)
13150
count = numGatewayDef - 1;
13152
while(bResult and (count >= 0) )
13154
if(isStructureAvailable(gatewayDef[count],me))
13157
bResult = FALSE; //found best one
13163
skDefenseLocationB(ref x,ref y,wall,gatewayDef[count2],droid,me);
13167
//---------------------------------------------------------
13168
// Store experience
13169
//---------------------------------------------------------
13170
function void storeBaseDefLocEv()
13172
if(obj2 == NULLOBJECT)
13174
MsgBox("storeBaseDefLocEv - obj2 is NULLOBJECT");
13178
//Don't store if not enough time passed since the last save, but store new locations in any case
13179
if((getBaseDefendLocIndex(me, obj2.x, obj2.y) < 0) or (storeBaseDefTime[obj2.player] <= 0))
13181
//move coords closer to base
13186
learnBaseDefendLoc(me, obj2.player, obj2.x, obj2.y);
13188
storeBaseDefTime[obj2.player] = storeTime; //start countdown
13193
function void storeOilDefLocEv()
13195
if(obj2 == NULLOBJECT)
13197
MsgBox("storeOilDefLocEv - obj2 is NULLOBJECT");
13201
//Don't store if not enough time passed since the last save, but store new locations in any case
13202
if((getOilDefendLocIndex(me, obj2.x, obj2.y) < 0) or (storeOilDefTime[obj2.player] <= 0))
13204
learnOilDefendLoc(me, obj2.player, obj2.x, obj2.y);
13206
storeOilDefTime[obj2.player] = storeTime; //start countdown
13211
//---------------------------------
13212
//Go meet ally's force
13213
//---------------------------------
13214
function void joinForces(int _joinPlayer, int _x, int _y)
13216
dbg("joining forces with " & _joinPlayer, me);
13218
setState(stJoiningForces);
13219
enemy = _joinPlayer;
13221
setPhase(phMoveToLoc, NONE);
13223
timeGuardPos = 0; //reset countdown
13225
updateStateCoord(_x, _y);
13227
fillAttackers(numAttackersFromPriorty(false));
13229
msg("coming" , me, enemy); //allyInThreat
13232
//make sure group is going to the right place
13233
function void coordinateSendMovement(int _sendX, int _sendY, int _range,
13234
int _order, GROUP _coordinateGr)
13236
local DROID _droid;
13239
_bucket = initIterateGroupCmd(_coordinateGr,true,true,true);
13240
_droid = iterateGroupCmd(_coordinateGr,_bucket);
13241
while(_droid != NULLOBJECT)
13243
/* too far away and not going there */
13244
if(distBetweenTwoPoints(_sendX, _sendY, _droid.x, _droid.y) > _range)
13246
if(_droid.orderx > 0) //has move order
13248
/* busy and going to wrong palce */
13249
if(distBetweenTwoPoints(_sendX, _sendY, _droid.orderx, _droid.ordery) > _range) //don't touch if already on the way back
13251
orderDroidLoc(_droid, _order, _sendX, _sendY);
13254
else if((_droid.order == DORDER_NONE) or (_droid.order == DORDER_GUARD)) //idle //TODO: can be idle and have some other order
13256
orderDroidLoc(_droid, _order, _sendX, _sendY);
13260
_droid = iterateGroupCmd(_coordinateGr,_bucket);
13264
//check if units reached destination, if yes, add to a different group
13265
function bool checkReachedDestination(int _destX, int _destY, GROUP _toCheckGr,
13266
GROUP _toAddToGr, int _range)
13268
local DROID _droid;
13269
local bool _bNewReached;
13272
_bNewReached = false;
13274
_bucket = initIterateGroupCmd(_toCheckGr,true,true,false);
13275
_droid = iterateGroupCmd(_toCheckGr,_bucket);
13276
while(_droid != NULLOBJECT)
13278
//Check if reached destination
13279
if(distBetweenTwoPoints(_destX, _destY, _droid.x, _droid.y) <= _range)
13281
dbg("attacker reached", me);
13283
_bNewReached = true; //new unit has reached the destination point
13285
if(_toCheckGr == sendAttackGr){
13286
selectDroid(_droid, FALSE); //deselect since left sendAttackGr
13289
//add droid to the destination group
13290
if(_droid.droidType == DROID_COMMAND){
13291
cmdGr[ cmdToIndex(_droid) ] = _toAddToGr; //change commander group
13293
dbg("added commander " & cmdToIndex(_droid) & " to attackGr", me);
13295
groupAddDroid(_toAddToGr, _droid); //add to the new group
13299
_droid = iterateGroupCmd(_toCheckGr,_bucket);
13302
return _bNewReached;
13305
function void updateDrop()
13309
cancelState(); //have to cancel to unload units
13315
event coordinatePhases(inactive)
13317
local int _sendRange,_sendersOrder,_reachedDestinationRadius,_bucket;
13318
local bool _bStopped,_bReachedDestination;
13320
if(state == stNone)
13321
exit; //attackers idling
13323
/* main stuff begins here */
13324
if((enemy < 0) and !defendingOil())
13326
MsgBox(" " & me & " coordinatePhases() - no player set");
13330
/* Set radius of the destination point units can't go outside and order to give senders */
13331
_sendRange = (TILE * 6);
13332
_reachedDestinationRadius = REACHED_DEST_RANGE; //Units have reached destination when they are within this range from the destination
13333
_sendersOrder = DORDER_SCOUT;
13334
if(state == stHelpingAlly)
13336
_sendersOrder = DORDER_MOVE; //don't waste time on the way
13337
_sendRange = sendHelpRange; //give helpers move freedom to pursue attackers around ally's base
13338
_reachedDestinationRadius = sendHelpRange; //Don't need to come as close, start helping defend sooner
13340
else if(defendingOil())
13342
_sendersOrder = DORDER_MOVE;
13343
_reachedDestinationRadius = REACHED_DEF_OIL_RANGE;
13346
if((sendForceX <= 0) or (sendForceY <= 0))
13348
if(state == stHelpingAlly)
13349
msg("I can't see your base" , me, enemy); //allyInThreat
13351
dbg("coordinatePhases - (sendForceX <= 0) or (sendForceY <= 0)", me);
13357
if(state == stDrop)
13363
/* transport phase */
13364
if(state == stTransporting)
13370
if(defendingBase())
13371
exit; //defenders are sent to defend automatically
13373
/* make sure sendAttackGr droids are going to the destination */
13374
coordinateSendMovement(sendForceX, sendForceY, _sendRange, _sendersOrder, sendAttackGr);
13376
/* don't drift too far away from the defend location if defending oil or joining forces */
13377
if(phase == phGuardingPos)
13379
coordinateSendMovement(sendForceX, sendForceY, _sendRange, DORDER_SCOUT, attackGr);
13382
/* add to attackGr when new sendAttackGr droids reached the destination point */
13383
if(checkReachedDestination(sendForceX, sendForceY, sendAttackGr, attackGr, _reachedDestinationRadius))
13385
//New units have been added to the attackGr, assign any unassigned droids to commanders
13386
assignDroidsToBestCommandersFromGroup(attackGr, attackGr);
13389
//check if we have to switch from phMoveToLoc to the next phase, if at least one uniz has reached destination
13390
_bReachedDestination = ((groupSizeCmds(attackGr,true,false,true) > 0) and (phase == phMoveToLoc));
13392
/* start action when first unit reached the destination point */
13393
if((state == stTakingOil) or (state == stAttacking)
13394
or (state == stHelpingAlly) or defendingOil())
13396
if(_bReachedDestination)
13398
dbg("MANAGE UNITS: reached destination !!!!!", me);
13400
setPhase(phAttackingLoc, MINUTE * 10); //shouldn't take more than 10 mins
13403
/* start action when *most* of the units are there */
13404
else if(state == stJoiningForces)
13406
if(phase == phMoveToLoc)
13408
if(groupSizeCmds(attackGr,true,false,true) >= (groupSizeCmds(sendAttackGr,true,false,true) * 3)) //most of units arrived
13410
msg("ok, i'm there" , me, enemy);
13411
timeGuardPos = maxTimeGuardPos;
13413
setPhase(phGuardingPos, NONE);
13415
//exit; //must exit since vars are reset
13420
/* Check if have to switch back to phMoveToLoc if no attackers left */
13421
if(((phase == phAttackingLoc) or (phase == phGuardingPos)) and
13422
(groupSizeCmds(attackGr,true,false,true) == 0))
13424
dbg("no attackers, phase = phMoveToLoc !!!!!!!!", me);
13426
setPhase(phMoveToLoc, NONE);
13428
timeGuardPos = 0; //reset the oil guarding time
13432
/* Manage attack */
13433
if((state != stHelpingAlly) and ((phase == phAttackingLoc)
13434
or (phase == phGuardingPos))) //we are at the destination, stHelpingAlly is handled in manageHelpAlly()
13436
_bucket = initIterateGroupCmd(attackGr,true,true,true);
13437
droid = iterateGroupCmd(attackGr,_bucket);
13438
while(droid != NULLOBJECT)
13440
//find a target to attack
13441
if(droid.weapon == weaponBB){
13442
findBBAttackBaseTarget(droid);
13444
findAttackBaseTarget(droid, -1, -1, -1);
13447
//attack enemy target
13448
if(retObj != NULLOBJECT){
13449
orderDroidObj(droid, DORDER_ATTACK, retObj);
13452
//too far from attack location?
13453
//if( droidOrderIdle(droid) or !droidActionAttacking(droid) )
13454
if( droidOrderIdle(droid))
13457
if(objHasWeapon(droid)){
13458
range = objWeaponMaxRange(droid);
13459
}else{ //repairs etc
13460
range = (TILE * 8);
13463
// allow to travel further away if attacking or repairing
13464
if(droidActionAttacking(droid) or droidActionDroidRepair(droid)){
13465
range = range + (TILE * 12);
13468
if(distBetweenTwoPoints(droid.x, droid.y, sendForceX, sendForceY) > range)
13470
//make sure it's not far away because going around a big ramp: check destination
13471
if( (droid.orderx == 0) or
13472
(distBetweenTwoPoints(droid.orderx, droid.ordery, sendForceX, sendForceY) > range) ) //not heading to the right location
13474
dbg("too far from attack loc, send back", me);
13475
orderDroidLoc(droid, DORDER_SCOUT, sendForceX, sendForceY);
13480
droid = iterateGroupCmd(attackGr,_bucket);
13484
/* check if lost enemy base or ally we are helping disallied */
13485
if(state == stHelpingAlly) //will reveal territory if lost base, don't cancel attack here
13487
if(not knowBase[enemy]) //no visible structures left for this player
13489
//if(state == stHelpingAlly)
13491
msg("I don't see your base" , me, enemy); //allyInThreat
13494
dbg("coordinatePhases - not haveBase", me);
13499
//did player disally while we are helping him?
13500
if(not ally[enemy]) //no visible structures left for this player
13502
msg("backstabber!!!", me, enemy); //allyInThreat
13503
breakAlliance(me, enemy);
13504
cancelAllyDefense();
13508
else if(state == stTakingOil)
13510
//see if it's hopeless to go on
13511
if((groupSizeCmds(sendAttackGr,true,false,true) +
13512
groupSizeCmds(attackGr,true,false,true)) < minOilAttackers)
13514
dbg("TAKE OIL: little attackers left, cancel", me);
13516
taunt(enemy, TAUNT_FAILURE, 30);
13523
//see if we can stop guarding this oil resource already
13524
if(!_bStopped and (phase == phGuardingPos) and (timeGuardPos <= 0)) //guarding oil long enough
13526
dbg("TAKE OIL: waiting time is up!!!!!!!!!!!!!", me);
13528
taunt(enemy, TAUNT_SUCCESS, 20);
13535
/* something went wrong or we failed */
13536
if(!_bStopped and tTakeOil <= 0)
13538
dbg("TAKE OIL: takeoil timeout!!!!!!!!!!!!!", me);
13544
//check if we can cancel guarding oil since have defenses
13545
//if(numStructsByTypeInRange(me, me, REF_DEFENSE, sendForceX, sendForceY, (8 * 128)) >= 1)
13546
/* if(!_bStopped and numFriendlyWeapStructsInRange(me, sendForceX, sendForceY, (8 * 128), true) >= 1) //also include ally's defenses
13548
//if(numEnemyObjInRange(me, sendForceX, sendForceY, (8 * 128), FALSE) == 0)
13549
if(numEnemyWeapObjInRange(me, sendForceX, sendForceY, (8 * 128), false, true) == 0)
13551
dbg("TAKE OIL: oil is well-defended, rtb!!!!!!!!!!!!!", me);
13557
//see if it's hopeless to go on
13558
if(!_bStopped and (groupSizeCmds(attackGr,true,false,true) +
13559
groupSizeCmds(sendAttackGr,true,false,true)) <
13560
numEnemyWeapObjInRange(me, sendForceX, sendForceY, (8 * 128), false, true))
13562
dbg("TAKE OIL: they have more than us", me);
13564
taunt(enemy, TAUNT_FAILURE, 40);
13571
//see if we killed all defenses and can start guard oil countdown
13572
if(!_bStopped and (phase != phGuardingPos)) //not set yet
13574
//if(numEnemyObjInRange(me, sendForceX, sendForceY, (8 * 128), FALSE) == 0) //enemy derrick is destroyed and no enemy defenses left
13575
if(numEnemyWeapObjInRange(me, sendForceX, sendForceY, (8 * 128), false, true) == 0)
13577
if(groupSizeCmds(attackGr,true,false,true) > 0) //if we reached destination
13579
taunt(enemy, TAUNT_SUCCESS, 40);
13581
dbg("TAKE OIL: no enemies, started guarding", me);
13582
timeGuardPos = maxTimeGuardPos;
13584
setPhase(phGuardingPos, NONE);
13591
if(canStartTakingOil() and (THROW_DICE <= CHANCE_COUNTER_OIL)) // enough units?
13593
if(initializeStartTakingOil(sendForceX, sendForceY, MAX_COUNTER_OIL_DISTANCE))
13595
exit; // exit here if we started attacking enemy oil
13605
else if(state == stJoiningForces) //check if waited long enougn
13607
/* see if we can stop waiting at joining pos already */
13608
if((phase == phGuardingPos) and (timeGuardPos <= 0))
13610
dbg("JOIN FORCES: waiting time is up!!!!!!!!!!!!!", me);
13613
msg("I'm going back" , me, enemy);
13615
stopJoiningForces();
13619
else if(defendingOil())
13621
// sucess is handled in everySecEv()
13623
// see if it's hopeless to go on
13624
if((groupSizeCmds(sendAttackGr,true,false,true) +
13625
groupSizeCmds(attackGr,true,false,true)) < MIN_OIL_DEFENDERS)
13627
dbg("DEFENDING OIL: little attackers left, cancel", me);
13629
taunt(enemy, TAUNT_POSSESSION_LOSS, 50);
13631
stopDefendingOil();
13635
// see if we want to counter-oil
13636
if(_bStopped and (state == stNone)) // if idle
13638
if(canStartTakingOil() and (THROW_DICE <= CHANCE_COUNTER_OIL)) // enough units?
13640
if(initializeStartTakingOil(sendForceX, sendForceY, MAX_COUNTER_OIL_DISTANCE))
13642
exit; // exit here if we started attacking enemy oil
13647
//must exit here, since stopped defending oil
13654
/* check if we can send reinforcements, use more units if state == stHelpingAlly */
13655
if(canSendReinf(state == stHelpingAlly)) //got enough
13657
fillReinforcements(state == stHelpingAlly);
13661
function void saveExperience()
13663
if(not bLearn){return;}
13665
savePlayerAIExperience(me, FALSE); //silent save
13667
timeSaveExperience = maxTimeSaveExperience;
13669
dbg("Saved AI Experience (*)", me);
13672
/* Returns name of the passed group */
13673
function string groupToString(GROUP _group)
13675
local string _sGroup;
13677
_sGroup = "Unknown";
13679
if(_group == defendGr){
13680
_sGroup = "defendGr";
13681
}else if(_group == buildGr){
13682
_sGroup = "buildGr";
13683
}else if(_group == sendAttackGr){
13684
_sGroup = "sendAttackGr";
13685
}else if(_group == scoutGr){
13686
_sGroup = "scoutGr";
13687
}else if(_group == enemyScoutGr){
13688
_sGroup = "enemyScoutGr";
13689
}else if(_group == vtolGr){
13690
_sGroup = "vtolGr";
13691
}else if(_group == attackGr){
13692
_sGroup = "attackGr";
13693
}else if(_group == defendRepairGr){
13694
_sGroup = "defendRepairGr";
13699
function string droidToGroupName(DROID _droid)
13701
local GROUP _group;
13703
if(_droid.droidType == DROID_COMMAND){
13704
return groupToString( cmdGr[ cmdToIndex(_droid) ] );
13707
return groupToString( _droid.group );
13710
//---------------------------------------------------------
13711
//Don't trigger experience callbacks too frequently
13712
//---------------------------------------------------------
13713
event everySecEv(inactive)
13715
local float _newCurResUrgency;
13723
dbg("phase timeout", me);
13727
// if our oil derrick was attacked, remember how long the attack lasts already,
13728
// to be able to judge if the derrick is really under attack or whether it was just
13729
// an enemy unit passing by and shooting at the derrick
13730
/* if(tOilAttackBegin > 0){
13731
tOilAttackBegin++; // remember how long it has been attacked already
13734
// if derrick under siege wasn't attacked for certain time, assume it wasn't under siege
13735
if((tLastOilAttack > 0) and
13736
(GAME_TIME_IN_SECS > (tLastOilAttack + MAX_TIME_OIL_NOT_ATTACKED)))
13738
if(!defendingOil())
13740
resetOilDefendCoords();
13742
dbg("derrick siege threat timed out", me);
13744
else if(defendingOil())
13746
// make sure threat is really gone
13747
if(numFriendlyWeapStructsInRange(me, sendForceX, sendForceY, (8 * TILE), true) >= 1)
13749
if(numEnemyWeapObjInRange(me, sendForceX, sendForceY, (8 * TILE), false, true) == 0)
13751
taunt(enemy, TAUNT_SUCCESS, 70);
13753
stopDefendingOil();
13755
dbg("THREAT IS GONE - STOPPED DEFENDING OIL", me);
13763
if(watchWindowDebug == WATCH_DEBUG_CMDS)
13765
setDebugMenuEntry("min/max trucks: " & minTrucks & "/" & maxTrucks , 6);
13766
setDebugMenuEntry("oil trucks: " & maxBuildOilTrucks, 7);
13767
setDebugMenuEntry("base/oil def: " & maxBaseDefenseTrucks & "/" & maxOilDefenseTrucks, 8);
13768
setDebugMenuEntry("st/ph/enemy/al: " & state & "/" & phase & "/" & enemy & "/" & alert, 9);
13770
setDebugMenuEntry("defendGr: " & groupSizeCmds(defendGr,true,false,false) & "/" & groupSizeCmds(defendGr,true,false,true) &
13771
"/" & numDefenders & "- cmd:" & groupSizeCmds(defendGr,false,true,false), 0);
13772
if(cmds[0] == NULLOBJECT)
13774
setDebugMenuEntry("cmd0:" , 1);
13776
setDebugMenuEntry("cmd0: " & cmds[0].group.members & "/" & cmdDroidMaxGroup(cmds[0]) & " - " & getDroidRank(cmds[0]) & " - " & droidToGroupName(cmds[0]) , 1);
13778
if(cmds[1] == NULLOBJECT)
13780
setDebugMenuEntry("cmd1:" , 2);
13782
setDebugMenuEntry("cmd1: " & cmds[1].group.members & "/" & cmdDroidMaxGroup(cmds[1]) & " - " & getDroidRank(cmds[1]) & " - " & droidToGroupName(cmds[1]) , 2);
13784
if(cmds[2] == NULLOBJECT)
13786
setDebugMenuEntry("cmd2:" , 3);
13788
setDebugMenuEntry("cmd2: " & cmds[2].group.members & "/" & cmdDroidMaxGroup(cmds[2]) & " - " & getDroidRank(cmds[2]) & " - " & droidToGroupName(cmds[2]) , 3);
13790
if(cmds[3] == NULLOBJECT)
13792
setDebugMenuEntry("cmd3:" , 4);
13794
setDebugMenuEntry("cmd3: " & cmds[3].group.members & "/" & cmdDroidMaxGroup(cmds[3]) & " - " & getDroidRank(cmds[3]) & " - " & droidToGroupName(cmds[3]) , 4);
13796
if(cmds[4] == NULLOBJECT)
13798
setDebugMenuEntry("cmd4:" , 5);
13800
setDebugMenuEntry("cmd4: " & cmds[4].group.members & "/" & cmdDroidMaxGroup(cmds[4]) & " - " & getDroidRank(cmds[4]) & " - " & droidToGroupName(cmds[4]) , 5);
13803
//Display group of the selected droid
13804
setDebugMenuEntry("unit group:" , 6);
13805
InitEnumDroids(me, me);
13806
droid = EnumDroid();
13807
while(droid != NULLOBJECT)
13809
if(droid.selected){
13810
setDebugMenuEntry("unit group: " & droidToGroupName(droid), 6);
13811
droid = NULLOBJECT;
13813
droid = EnumDroid();
13818
/* Update research urgency */
13819
_newCurResUrgency = fCurResUrgency + (fNumDefaultResearch - (float)numBusyByType(resFac)); //fMinResearch = average, find out far we are from the average now, remember we need to make more later if lower than fMinResearch currently
13820
//can only be set manually outside of the bounds!
13821
if(_newCurResUrgency > fMaxResUrgency) //going outside of the highest boundry
13823
if(_newCurResUrgency > fCurResUrgency){ //moving up
13824
_newCurResUrgency = fmax(fCurResUrgency,fMaxResUrgency); //trim to the highest value or to fCurResUrgency, if it was set manually to a higher value than the high boundry
13827
else if(_newCurResUrgency < fMinResUrgency) //going outside of the lowest boundry
13829
if(_newCurResUrgency < fCurResUrgency){ //moving down
13830
_newCurResUrgency = fmin(fCurResUrgency,fMinResUrgency); //trim to the lowest value or to fCurResUrgency, if it was set manually to a lower value than the low boundry
13834
fCurResUrgency = _newCurResUrgency; //Update
13836
/* Update duration of current state */
13839
/* Update Reinforcement Countdown */
13841
reinfTime = reinfTime - 1;
13843
/* lasSat rechargement */
13844
if((lasSatState[me] == lsRecharging) or (lasSatState[me] == lsRequesterWaitingRecharging)) //only recharge if we built lasSat already and are not recharged already (would reset waiting state)
13846
tLasSat = tLasSat + 1; //continue recharging
13849
/* wait for allies' lassat to recharge */
13850
//if(lasSatState[me] == lsWaiting)
13851
if(tLasSatCountdown >= 0) //if we turned on the countdown for something (!= off)
13853
tLasSatCountdown = tLasSatCountdown - 1;
13856
/* requester has fired, now we fire with a little delay for more effectiveness, must be fired here, because every sec is important for the sync */
13858
if(lasSatState[me] == lsDelayedFiring)
13860
if(tLasSatCountdown <= 0)
13862
lasSatTarget = findLasSatTarget(lasSatEnemy);
13863
if(lasSatTarget != NULLOBJECT)
13865
fireLasSat(lasSatTarget);
13873
helpTime = helpTime - 1;
13875
if(timeGuardPos > 0)
13876
timeGuardPos = timeGuardPos - 1;
13878
if(requestHelpTime > 0)
13879
requestHelpTime = requestHelpTime - 1;
13881
if(collectTime > 0)
13882
collectTime = collectTime - 1;
13884
if(timeNotifyEnemyInBase > 0)
13885
timeNotifyEnemyInBase = timeNotifyEnemyInBase - 1;
13887
if(tWaitAlliesDrop > 0)
13888
tWaitAlliesDrop = tWaitAlliesDrop - 1;
13890
if(tWaitLoadDrop > 0)
13891
tWaitLoadDrop = tWaitLoadDrop - 1;
13894
tSyncDrop = tSyncDrop - 1;
13897
tTakeOil = tTakeOil - 1;
13899
if(timeSaveExperience > 0)
13901
timeSaveExperience = timeSaveExperience - 1;
13903
if(timeSaveExperience <= 0)
13909
if(notifyReadyAttackTime > 0)
13911
notifyReadyAttackTime = notifyReadyAttackTime - 1;
13913
if(notifyReadyAttackTime == 0) //remember countdown is finished
13915
bNotifiedReadyAttack = TRUE;
13916
dbg("bNotifiedReadyAttack == TRUE", me);
13920
//store exrepience countdown for every player
13922
while(_temp < multiPlayerMaxPlayers)
13924
if(storeOilDefTime[_temp] > 0)
13926
storeOilDefTime[_temp] = storeOilDefTime[_temp] - 1;
13929
if(storeBaseDefTime[_temp] > 0)
13931
storeBaseDefTime[_temp] = storeBaseDefTime[_temp] - 1;
13934
if(allyOfferTime[_temp] > 0)
13936
allyOfferTime[_temp] = allyOfferTime[_temp] - 1;
13939
if(tRequestStatus[_temp] > 0)
13941
tRequestStatus[_temp] = tRequestStatus[_temp] - 1;
13944
if(tWaitPlayerReply[_temp] > 0)
13946
tWaitPlayerReply[_temp] = tWaitPlayerReply[_temp] - 1;
13952
tLastResearch++; //will be reset by doResearch if research is not idle
13954
// notify allies if we are idle for certain amout of time
13955
// can't do that immediately when we become idle, since can switch
13956
// to some other state right after that - prevent flooding console
13957
// with state changes notifications
13958
if((state == stNone) and (GAME_TIME_IN_SECS > 10)) // skip startup
13960
if(tState == 6) // do only once per idle state
13967
function bool canFollowAttackRequest(int _attackRequester, bool _bHighPriorityTask)
13969
if(defendingBase() or (state == stAttacking) or
13970
(state == stDrop) or (state == stTransporting) or
13971
((state == stHelpingAlly) and (enemy != _attackRequester)))
13973
notifyStatus(_attackRequester);
13977
if(not haveTheoreticallyMinAttackers(_bHighPriorityTask))
13979
msg("let me get more units", me, _attackRequester);
13986
function bool isCurrentOrder(int _state, int _enemy)
13988
local int _dummy; //FIXME
13990
return ((_state == state) and (enemy == _enemy));
13993
/* Check if we are attacking some soecific (or any) enemy base */
13994
function bool attackingEnemyBase(int _enemy)
13996
return ((state == stAttacking) and (attackReason == ATTACK_BASE) and
13997
( (enemy == _enemy) or (_enemy == ANY) )); // match the enemy
14000
/* Returns true if we are attacking enemy arty location */
14001
function bool counteringArty()
14003
return ((state == stAttacking) and (attackReason == ATTACK_COUNTER_ARTY));
14006
function bool idling()
14008
return (state == stNone);
14011
function bool defendingBase()
14013
return (state == stDefendingBase);
14016
function bool helpingAlly()
14018
return (state == stHelpingAlly);
14021
function bool defendingOil()
14023
return (state == stDefendingOil);
14026
function bool canAlly(int _player)
14028
if(allianceExistsBetween(_player ,me))
14030
return(FALSE); //already allied
14033
/* check if attacked by this player */
14034
if(defendingBase())
14036
if(numPlayerWeapObjInRange(_player, me, baseX, baseY, baseRange + (5 * 128), false, true) > 5) //attacking us
14042
if((state != stNone) and (enemy == _player))
14047
/* check not allied to too many players already */
14048
if((numAllies(me) + 1) >= (multiPlayerMaxPlayers / 2))
14056
//decide if last beacon was placed long ago
14057
function bool beaconTimeout(int _player)
14059
if((tBeacon[_player] > 0) and (( tBeacon[_player] + tBeaconTimeout) < GAME_TIME_IN_SECS)) //not too long ago
14061
return TRUE; //this beacon is still 'fresh'
14067
function bool haveBeacon(int _player)
14069
if((tBeacon[_player] > 0) and (not beaconTimeout(_player)))
14071
return TRUE; //have beacon for this player
14077
function void makeAlliances()
14079
/* find closest player */
14080
temp = bestAlliancePlayer();
14083
temp = random(multiPlayerMaxPlayers);
14086
if(temp == me){return;}
14087
if(allianceExistsBetween(me, temp)){return;} //my ally
14088
if(allyOfferTime[temp] > 0){return;} //offered already
14091
/* don't offer alliance to a player we are attacking */
14092
if((state != stNone) and (enemy == temp))
14097
doOfferAlliance(temp);
14100
function void doOfferAlliance(int _alliancePlayer)
14102
allyOfferTime[_alliancePlayer] = maxAllyOfferTime;
14104
msg("ally?" , me, _alliancePlayer);
14107
function int bestAlliancePlayer()
14109
//return - closest enemy index
14115
while(_temp < multiPlayerMaxPlayers)
14117
if(knowBase[_temp] and (not dead[_temp]) and (not allianceExistsBetween(me, _temp)) and (_temp != me))
14119
if(allyOfferTime[_temp] <= 0)
14121
if(not((state != stNone) and (enemy == _temp))) //attacking him?
14123
intOK[_temp4] = _temp; //store this one
14124
_temp4 = _temp4 + 1; //how many available
14126
_temp2 = distBetweenTwoPoints(baseX, baseY, curBase[_temp][0], curBase[_temp][1]);
14127
if(_temp2 < _temp3)
14130
retInt = _temp; //remember closest
14139
if((_temp4 > 0) and (random(4) <= 1)) //found at least 1 and 50%
14141
retInt = intOK[random(_temp4)]; //choose one of the available
14145
return(retInt); //return closest or random available
14148
event allianceOffered(inactive)
14150
if(temp2 != me){exit;} //offered not to me
14152
//if(DEBUG_MSG and (not isHumanPlayer(temp))){exit;} //don't ally with AIs for now
14154
if(not canAlly(temp)) //shouldn't ally
14162
event droidSeen(inactive)
14164
//droid - that was seen
14167
if(droid == NULLOBJECT)
14172
if(not isVtol(droid))
14177
if(not hasVTOLs[droid.player])
14179
hasVTOLs[droid.player] = TRUE;
14181
dbg(getPlayerName(droid.player) & " got VTOLs", me);
14183
/* notify allies about enemy using VTOLs */
14184
if(not allianceExistsBetween(me, droid.player))
14186
notifyPlayerHasVTOLs(droid.player);
14191
event objectSeen(inactive)
14193
//obj - what was seen
14196
if((obj == NULLOBJECT) or (obj2 == NULLOBJECT))
14201
if((obj.player > 7) or (obj2.player > 7)) //skip scavengers
14206
/* ignore walls and defenses */
14207
if(obj.type == OBJ_STRUCTURE)
14209
_structure = objToStructure(obj);
14211
temp = getStructureType(_structure);
14212
if((_temp == 7) or (_temp == 8) or (_temp == 6) or (_temp == 6)) //wall, cornerwall, defense, rearm
14218
if(dead[obj.player]) //if we thought he was dead
14220
rememberPlayerIsAlive(obj.player);
14222
//dbg("saw player " & obj.player & "'s object at " & (obj.x / 128) & " - " & (obj.y / 128), me);
14223
notifyPlayerAlive(obj.player);
14227
function void rememberPlayerIsAlive(int _alivePlayer)
14229
if(gameTime < 200){return;} //engine bugs at startup
14231
dbg(getPlayerName(_alivePlayer) & " IS ALIVE!!!!!!!!!+++++++++++", me);
14233
dead[_alivePlayer] = FALSE;
14234
killedBase[_alivePlayer] = FALSE;
14237
function void doAlly(int _playerOffered)
14239
createAlliance(_playerOffered, me);
14241
ally[_playerOffered] = TRUE;
14242
allyOfferTime[_playerOffered] = 0; //reset, when disally, can immediately offer alliance again
14244
if((state != stNone) and (enemy == _playerOffered))
14246
stopState(); //stop if were attacking him
14249
/* Request help if in danger */
14250
if(state != stNone)
14252
notifyStatus(_playerOffered);
14256
function void buildAA()
14258
best = findBestAA();
14259
if(best == none){return;}
14261
range = MAX_BASE_PERIM_RANGE; //too many on spot range
14264
while(temp < multiPlayerMaxPlayers)
14266
if(!allianceExistsBetween(me, temp))
14268
if(knowBase[temp] and !dead[temp] and hasVTOLs[temp]) //found his base and saw him using VTOLs
14270
/* project enemy base to base perimeter */
14271
x = curBase[temp][0]; y = curBase[temp][1];
14272
circlePerimPoint(baseX, baseY, ref x, ref y, aaRange);
14274
/* make sure not too many AA defenses at that spot already */
14275
if(numAAinRange(me, me, x, y, range) < MAX_BASE_PERIM_AA_DEF)
14277
buildX = x; buildY = y;
14278
/* make sure we can build and won't be built too far away from orig loc */
14279
if(!pickStructLocation(AA[best], ref buildX, ref buildY, me))
14284
if(distBetweenTwoPoints(buildX, buildY, x, y) > range) //build loc moved too far away
14286
return; //original site was probably blocked, don't build too far away from orig site
14289
/* it worked, build AA */
14290
buildOnMap(AA[best], buildX, buildY, 2);
14298
function int findBestAA()
14300
//return - defense index
14302
/* find best defense */
14305
while(_temp < numAA)
14307
if(isStructureAvailable(AA[_temp],me))
14309
_temp2 = _temp; //Best defense
14317
event consoleEv(consoleTr)
14320
//turn on 'autogame'
14321
if(cstr == "autogame on" && (msgPlayer2 == me))
14323
if(debugModeEnabled() && myResponsibility(me))
14325
if(not bRunning) //make sure current machine is responsible for this AI and it's not already active
14327
console(getPlayerName(me) & " activated");
14333
//turn off 'autogames'
14334
if(cstr == "autogame off" && debugModeEnabled() && (msgPlayer2 == me))
14336
if(bRunning) //make sure this AI is active
14338
console(getPlayerName(me) & " deactivated");
14344
if(not DEBUG_MSG){exit;}
14345
if(!debugModeEnabled()){exit;}
14347
if(strcmp(cstr, "/baserange"))
14349
dbg("baseRange: " & (baseRange / 128), me);
14351
else if(strcmp(cstr, "/request help"))
14353
requestHelp(baseX, baseY);
14355
else if(strcmp(cstr, "/defendcoord"))
14357
dbg("x: " & (groupCMD_x(defendGr) / 128) & " y: " & (groupCMD_y(defendGr) / 128), me);
14359
else if(strcmp(cstr, "/state"))
14361
dbg("state: " & state, me);
14363
else if(strcmp(cstr, "/phase"))
14365
dbg("phase: " & phase, me);
14367
else if(strcmp(cstr, "/stop"))
14371
else if(strcmp(cstr, "/cancel"))
14375
else if(strcmp(cstr, "/numtrucks"))
14377
_temp2 = numBuildersInProduction(me);
14378
_temp = groupSizeCmds(buildGr,true,false,true);
14379
dbg("Trucks: " & _temp & "/" & _temp2, me);
14381
else if(strcmp(cstr, "/see enemy?"))
14384
dbg("seeBase[" & enemy & "] = " & canSeePlayerBase(enemy), me);
14387
dbg("no enemy", me);
14389
else if(strcmp(cstr, "/addallylassat"))
14394
if(allianceExistsBetween(_temp ,me) and me != _temp)
14396
x = curBase[_temp][0];
14397
y = curBase[_temp][0];
14398
if(pickStructLocation(lasSat, ref x, ref y, _temp))
14400
addStructure( lasSat, _temp, x, y);
14406
else if(strcmp(cstr, "/addlassat"))
14410
if(pickStructLocation(lasSat, ref x, ref y, me))
14412
addStructure(lasSat, me, x, y);
14413
lasSatState[me] = lsRecharging;
14416
else if(strcmp(cstr, "/numfacs"))
14418
temp = getNumStructures(fac,me);
14419
dbg("num facs: " & temp, me);
14421
else if(strcmp(cstr, "/numtransp"))
14423
dbg("numTransporters: " & numTransporters, me);
14425
else if(strcmp(cstr, "/transpstatus"))
14427
_temp = transporterCapacity(transporter[0]);
14428
dbg("action: " & transporter[0].action & ", order: " & transporter[0].order & ", capacity :" & _temp, me);
14431
else if(strcmp(cstr, "/numres"))
14433
_temp = numResearchLeft(me, resUnitTransporter);
14434
dbg("num res until transport: " & _temp, me);
14437
else if(strcmp(cstr, "/numrepprod"))
14439
_temp = totalRepairersInProduction();
14440
dbg("repair units in production: " & _temp, me);
14443
else if(strcmp(cstr, "/allystates"))
14446
dbg("0: " & allyState[0], me);
14447
dbg("1: " & allyState[1], me);
14448
dbg("2: " & allyState[2], me);
14450
dbg("0: " & allyPhase[0], me);
14451
dbg("1: " & allyPhase[1], me);
14452
dbg("2: " & allyPhase[2], me);
14454
dbg("0: " & allyEnemy[0], me);
14455
dbg("1: " & allyEnemy[1], me);
14456
dbg("2: " & allyEnemy[2], me);
14459
else if(strcmp(cstr, "/alert?"))
14463
dbg("yes, alert", me);
14467
dbg("no, no alert", me);
14470
else if(strcmp(cstr, "/takeoil"))
14472
dbg("numTakeOil: " & numTakeOil & ", countTakeOil: " & countTakeOil, me);
14474
else if(strcmp(cstr, "/sendForce"))
14476
dbg("sendForceX: " & sendForceX / 128 & ", sendForceY: " & sendForceY / 128, me);
14478
else if(strcmp(cstr, "/addpower"))
14480
addPower(3000, me);
14482
else if(strcmp(cstr, "/checkbase on"))
14484
bCheckBaseDebug = true;
14485
dbg("bCheckBaseDebug on", me);
14487
else if(strcmp(cstr, "/checkbase off"))
14489
bCheckBaseDebug = false;
14490
dbg("bCheckBaseDebug off", me);
14492
else if(strcmp(cstr, "/baseloc"))
14495
while(count < multiPlayerMaxPlayers)
14497
dbg(getPlayerName(count) & "'s base " & (curBase[count][0] / TILE) & "/" & (curBase[count][1] / TILE), me);
14501
else if(strcmp(cstr, "/temp"))
14506
//count2 = checkPlayerDead(count);
14507
dbg(getPlayerName(count) & " is dead = " & checkPlayerDead(count), me);
14511
else if(strcmp(cstr, "/temp2")) //4
14516
dbg("knowBase " & getPlayerName(count) & " is = " & knowBase[count], me);
14520
else if(strcmp(cstr, "/temp3")) //0
14525
dbg("seeBase " & getPlayerName(count) & " is = " & canSeePlayerBase(count), me);
14529
else if(strcmp(cstr, "/temp4")) //-7
14534
if(mapRevealedInRange(curBase[count][0],curBase[count][1], (2 * 128), me))
14536
dbg("base revealed for " & count, me);
14540
dbg("base not revealed for " & count, me);
14545
else if(strcmp(cstr, "/temp5"))
14550
//count2 = canSeePlayer(count); //can see any other objects?
14552
if(not canSeePlayer(count))
14554
dbg("can't see " & getPlayerName(count), me);
14558
dbg("can see " & getPlayerName(count), me);
14563
else if(strcmp(cstr, "/temp6")) //0
14568
dbg("dead " & count & " is = " & dead[count], me);
14572
else if(strcmp(cstr, "/temp7")) //0
14577
if(allianceExistsBetween(count ,me))
14579
MsgBox("dropBeacon for " & count);
14580
dropBeacon("help", count, me, baseX, baseY,0);
14586
else if(strcmp(cstr, "/fast"))
14595
minReinforcements = 7;
14601
dbg("FAST ATTACK MODE ON", me);
14603
else if(strcmp(cstr, "/range on"))
14605
//showRangeAtPos(baseX, baseY, baseRange + defendCorridor);
14609
showRangeAtPos(sendForceX, sendForceY, sendHelpRange);
14611
showRangeAtPos(sendForceX, sendForceY, REINF_ENEMY_COUNT_RANGE);
14615
else if(strcmp(cstr, "/save"))
14619
else if(strcmp(cstr, "/save"))
14623
else if(strcmp(cstr, "/range off"))
14625
showRangeAtPos(sendForceX, sendForceY, -1);
14627
else if(strcmp(cstr, "/msg on"))
14629
dbgMsgOn(me, TRUE);
14630
console("turned on debug messages");
14632
else if(strcmp(cstr, "/msg off"))
14634
console("turned off debug messages");
14635
dbgMsgOn(me, FALSE);
14639
/************************/
14641
/************************/
14645
if(strcmp(cstr, "/offer " & temp2))
14649
doOfferAlliance(temp2);
14653
dbg("can't ally myself", me);
14664
event beaconEv(inactive)
14666
local int _players;
14667
local string _processedString;
14671
MsgBox("beaconTr - msgPlayer >= 8");
14675
/* Get target players */
14676
_processedString = cstr;
14677
//_players = getTargetPlayers(ref _processedString);
14679
//dbg("beaconEv()!!!! = " & cstr & ", from " & msgPlayer, me);
14681
beaconX[msgPlayer] = x;
14682
beaconY[msgPlayer] = y;
14683
tBeacon[msgPlayer] = GAME_TIME_IN_SECS; //remember when got this msg, so can make it timeout
14685
processCommand(cstr, msgPlayer, TRUE);
14686
//dbg("beaconEv()!!!! END = " & cstr & ", from " & msgPlayer, me);
14689
event multiMsgEv(inactive)
14691
local int _players;
14692
local string _processedString;
14693
if(msgPlayer == me)
14696
/* Get target players */
14697
_processedString = cstr;
14698
// _players = getTargetPlayers(ref _processedString);
14700
dbg(" " & me & " multiMsgEv() = " & cstr & ", from " & msgPlayer, me);
14702
//dbg("multiMsgEv() = " & cstr & ", from " & msgPlayer, me);
14704
/* See if sender was referring to us */
14705
processCommand(cstr, msgPlayer, FALSE);
14708
//dbg("processDebugCommand() start = " & cstr & ", from " & msgPlayer, me);
14709
//process debug messages
14712
processDebugCommand(msgPlayer, cstr);
14714
//dbg("multiMsgEv() END = " & cstr & ", from " & msgPlayer, me);
14717
function void processDebugCommand(int _msgPlayer, STRING _cstr)
14719
if(strcmp(_cstr, "stop"))
14723
else if(strcmp(cstr, "see enemy?"))
14726
dbg("seeBase[" & enemy & "] = " & canSeePlayerBase(enemy), me);
14729
dbg("no enemy", me);
14731
else if(strcmp(_cstr, "status?"))
14733
if(alert){msg("alert = TRUE" , me, _msgPlayer);} //alert
14734
else{msg("alert = FALSE" , me, _msgPlayer);}
14736
if(lowMilitary){msg("lowMilitary = TRUE" , me, _msgPlayer);} //lowMilitary
14737
else{msg("lowMilitary = FALSE" , me, _msgPlayer);}
14739
msg("power = " & playerPower(me) , me, _msgPlayer); //power
14740
msg("state: " & state, me, _msgPlayer);
14741
msg("phase: " & phase, me, _msgPlayer);
14742
msg("numres: " & numBusyByType(resFac), me, _msgPlayer);
14744
else if(strcmp(cstr, "range on"))
14746
showRangeAtPos(baseX, baseY, baseRange + defendCorridor);
14748
else if(strcmp(cstr, "range off"))
14750
showRangeAtPos(baseX, baseY, -1);
14752
else if(strcmp(cstr, "msg on"))
14754
dbgMsgOn(me, TRUE);
14756
else if(strcmp(cstr, "msg off"))
14758
dbgMsgOn(me, FALSE);
14760
else if(strcmp(_cstr, "num res?"))
14762
msg("num res=" & numBusyByType(resFac), me, _msgPlayer);
14764
else if(strcmp(cstr, "fast"))
14770
minReinforcements = 7;
14776
dbg("FAST ATTACK MODE ON", me);
14778
else if(strcmp(cstr, "numres"))
14780
temp = numBusyByType(resFac);
14781
dbg("numres: " & temp, me);
14783
else if(strcmp(cstr, "/knowbase"))
14786
while(temp < multiPlayerMaxPlayers)
14790
console(temp & " - yes");
14794
console(temp & " - no");
14799
else if(strcmp(cstr, "/dead"))
14802
while(temp < multiPlayerMaxPlayers)
14806
console(temp & " - yes");
14810
console(temp & " - no");
14815
else if(strcmp(cstr, "/hasVTOLs"))
14818
while(temp < multiPlayerMaxPlayers)
14822
console(temp & " - yes");
14826
console(temp & " - no");
14833
//function void processCommand(int _msgPlayer, STRING _cstr, bool _bBlipMessage, string _processedString, int _targetPlayers)
14834
function void processCommand(string _message, int _sender, bool _bBlipMessage)
14836
local int _numMsgs,_curMsg,_addressedPlayers,_x,_y,_player;
14837
local string _msg,_processedString;
14839
//dbg("processCommand(" & _message & ", " & _sender & ")", me);
14841
if(dead[_sender] and (multiPlayerAlliancesType != ALLIANCES_TEAMS)){ //if we thought he was dead and teams are off
14842
rememberPlayerIsAlive(_sender);
14845
/* Extract semantic information */
14847
_numMsgs = processChatMsg(_message);
14849
debug(me & ") processCommand: '" & _message & "' from " & _sender);
14850
dbg("processCommand: '" & _message & "' from " & _sender, me);
14851
dbg("got " & _numMsgs & " commands", me);
14853
if(_message == "are you aiv?" or _message == "are you aivolution?")
14858
/* Process all messages */
14859
while(_curMsg < _numMsgs)
14861
if(chatCmdIsPlayerAddressed(_curMsg, me))
14863
dbg("i'm addressed", me);
14864
_msg = getChatCmdDescription(_curMsg);
14866
if(_msg == "ally me")
14868
if(alliancesLocked())
14873
if(allianceExistsBetween(_sender ,me) and (random(2) == 1))
14875
msg("already allied" , me, _sender);
14878
if(not canAlly(_sender)) //shouldn't ally
14880
if(random(2) == 1){msg("no" , me, _sender);}
14884
msg("ok" , me, _sender);
14889
/* ally mesages only */
14890
if(not allianceExistsBetween(me , _sender))
14895
allyState[_sender] = stNone;
14896
allyPhase[_sender] = phNone;
14897
allyEnemy[_sender] = none;
14899
/* tell him we are busy */
14900
if(not canFollowAttackRequest(_sender, true))
14905
/* tell him we are ready */
14906
msg("where" , me, _sender);
14908
if(_msg == "go center")
14910
/* tell him we are busy */
14911
if(not canFollowAttackRequest(_sender, true))
14914
/* cancel current state since not doing anything important */
14915
if(state != stNone)
14918
joinForces(_sender, mapWidth*64, mapHeight*64); //to center
14922
else if(_msg == "status?")
14924
if(state == stNone)
14930
notifyStatus(_sender);
14933
else if(_msg == "pumping units")
14935
allyState[_sender] = stNone;
14936
allyPhase[_sender] = phNone;
14937
allyEnemy[_sender] = none;
14939
else if(_msg == "stop")
14941
if((state != stNone) and (enemy == _sender))
14943
msg("ok" , me, _sender);
14947
else if(_msg == "got power?")
14949
notifyPower(_sender);
14951
//else if(strcmp(_msg, "cya")) //player has lost
14953
// if(allianceExistsBetween(me , _sender))
14955
// dead[_sender] = TRUE;
14957
// allyState[_sender] = stNone;
14958
// allyPhase[_sender] = phNone;
14959
// allyEnemy[_sender] = none;
14962
else if(_msg == "go!")
14964
/* tell him we are busy */
14965
if(not canFollowAttackRequest(_sender, true))
14968
/* cancel current state since not doing anything important */
14969
if(state != stNone)
14972
/* know location? */
14973
if(not haveBeacon(_sender))
14977
msg("I can't read your thoughts", me, _sender);
14979
msg("drop a beacon", me, _sender);
14983
joinForces(_sender, beaconX[_sender], beaconY[_sender]); //not to center
14987
else if(_msg == "help me")
14989
allyState[_sender] = stDefendingBase; //remember he's in trouble
14990
allyEnemy[_sender] = none;
14991
allyPhase[_sender] = phNone;
14993
if(_bBlipMessage) //processing message from blip
14995
curHelpX[_sender] = x;
14996
curHelpY[_sender] = y;
14999
/* got beacon msg and are already doing this command => just correct the coords */
15000
if(isCurrentOrder(stHelpingAlly, _sender))
15002
if(_bBlipMessage) //processing message from blip
15004
updateStateCoord(beaconX[_sender], beaconY[_sender]);
15005
helpTime = maxHelpTime; //reset help timeout timer
15009
msg("roger", me, _sender);
15013
else /* if a message, not a blip */
15015
helpTime = maxHelpTime; //reset help timeout timer
15016
msg("I am!", me, _sender);
15021
if(state == stHelpingAlly) /* busy with something else */
15023
//msg("defending player " & enemy & " already", me, _sender);
15024
notifyStatus(_sender);
15028
if(defendingBase())
15030
//msg("there're after me too, you better help me", me, _sender); //TODO: temporal solution
15031
//msg("there're after me too", me, _sender);
15035
temp = totalWeapUnits();
15036
if(temp < minAllyHelpers)
15038
msg("have nothing", me, _sender);
15042
if(curHelpX[_sender] <= 0)
15044
msg("give vision", me, _sender);
15048
if(state != stNone)
15050
pauseState(); //resume when done helping
15053
msg("coming, hold on", me, _sender);
15055
startHelpAlly(_sender, curHelpX[_sender], curHelpY[_sender]);
15057
else if(_msg == "i'm ok")
15059
allyState[_sender] = stNone;
15060
allyPhase[_sender] = phNone;
15061
allyEnemy[_sender] = none;
15063
if((state == stHelpingAlly) and (enemy == _sender))
15065
msg("roger", me, _sender);
15069
/* remind allies we are in trouble */
15070
if(defendingBase())
15071
requestHelp(baseX, baseY);
15073
else if(_msg == "give vision")
15075
giftRadar(me, _sender, FALSE);
15077
else if(_msg == "can't see him") //a reply after "go x"
15079
//if(state == stAttacking)
15081
// msg("go", me, _sender); //just follow my units
15087
giftRadar(me, _sender, FALSE);
15089
else if(_msg == "let's lassat someone")
15091
lasSatState[_sender] = lsWaitingReply;
15093
if(lasSatState[me] == lsReady)
15095
msg("ok", me, _sender);
15096
dbg("have a lassat requester********", me);
15097
lasSatState[me] = lsWaitingForRequester; //join the strike
15099
else if(lasSatState[me] == lsRecharging) //tell him to wait, if we are almost finished recharging
15101
if((tLasSatReady - tLasSat) < tLasSatWaitAlliesMax) //not much left
15103
lasSatState[me] = lsRequesterWaitingRecharging;
15104
msg("wait, lassat almost ready", me, _sender);
15108
else if(_msg == "wait, lassat almost ready")
15110
dbg("LASSAT: " & getPlayerName(_sender) & "has joined us********", me);
15111
lasSatState[_sender] = lsRequesterWaitingRecharging; //remember ally is almost done recharging
15114
else if(_msg == "lassat ready")
15116
dbg("LASSAT: " & getPlayerName(_sender) & " waits for us********", me);
15117
lasSatState[_sender] = lsWaitingForRequester; //remember ally is waiting for the requester to start lassat strike
15119
else if(_msg == "defending my oil")
15121
allyState[_sender] = stDefendingOil;
15122
allyPhase[_sender] = phMoveToLoc;
15123
allyEnemy[_sender] = none;
15127
/************************/
15129
/************************/
15135
if(_msg == "ally " & temp2 & "!")
15143
dbg("can't ally myself", me);
15152
/*************************/
15154
/*************************/
15156
//if(match(_processedString,"go <player>", ref _player))
15157
if((_msg == "attack player") and (getNumArgsInCmd(_curMsg) == 1))
15160
if(getChatCmdParam(ref _player, _curMsg, 0))
15162
dbg("*************go " & _player, me);
15164
if((_player == me) or (ally[_player]))
15166
notifyAllies(getPlayerName(_player) & "???", false);
15172
notifyAllies(getPlayerName(_player) & " is dead", false);
15176
/* got beacon msg and are already doing this command => just correct the coords */
15177
if(isCurrentOrder(stAttacking, _player))
15179
if(_bBlipMessage) /* processing beacon msg */
15181
updateStateCoord(beaconX[_sender], beaconY[_sender]);
15184
notifyAllies("roger", false);
15188
else /* if a normal msg, and we are already doind it, say so, since the destination can only be tweaked with a beacon */
15190
notifyAllies("I am", false);
15193
} /* we are doing something else already */
15194
else if(not canFollowAttackRequest(_sender, true))
15199
/* know location? */
15200
if(haveBeacon(_sender))
15202
_x = beaconX[_sender];
15203
_y = beaconY[_sender];
15205
else /* no beacon provided, use the current enemy location */
15207
if(killedBase[_player] and (not canSeePlayerBase(_player))) /* we have no idea where the enemy has rebuilt the base */
15209
notifyAllies(getPlayerName(_sender) & ", drop a beacon", false);
15212
else if(curBase[_player][0] > 0) /* remember or can directly see it */
15214
_x = curBase[_player][0];
15215
_y = curBase[_player][1];
15219
notifyAllies(getPlayerName(_sender) & ", drop a beacon", false);
15224
/* cancel current state since not doing anything important */
15225
if(state != stNone)
15230
if(killedBase[_player])
15232
notifyAllies(getPlayerName(_sender) & ", ok, but haven't we destroyed " & getPlayerName(_player) & "'s base already?", false);
15236
notifyAllies("ok" , false);
15239
allyState[_sender] = stAttacking;
15240
allyEnemy[_sender] = _player;
15241
allyPhase[_sender] = phMoveToLoc; //or phAttackingLoc
15243
offeredEnemy = _player; //remember the offer
15245
attackReason = ATTACK_BASE;
15246
startAttack(_player, _x, _y);
15247
notifyAllies("attacking " & getPlayerName(_player), TRUE);
15252
/*************************/
15254
/*************************/
15256
//if(match(_processedString,"going <player>", ref _player))
15257
if((_msg == "attacking player?") and (getNumArgsInCmd(_curMsg) == 1))
15260
if(getChatCmdParam(ref _player, _curMsg, 0))
15262
dbg("*************going " & _player, me);
15264
allyState[_sender] = stAttacking;
15265
allyEnemy[_sender] = _player;
15266
allyPhase[_sender] = phMoveToLoc; //or phAttackingLoc
15270
notifyAllies(getPlayerName(_sender) & ", you bastard!", false);
15271
breakAlliance(me, _sender);
15275
if(ally[_player]){return;} //just exit quietly
15279
notifyAllies("isn't " & getPlayerName(_player) & " dead already?", false);
15283
/* ignore if busy */
15284
if((state != stNone) and (enemy != _sender) and (phase != phGuardingPos)) //not idle and not dealing with this player somehow (defendingBase etc) or psGuardingPos (is low prior)
15286
return; //just exit
15289
/* also ignore if we are already attacking the SAME enemy, or "gonna take enemy derrick" msg is not gonna work properly */
15290
if(enemy == _player)
15295
if(not haveTheoreticallyMinAttackers(true))
15300
/* know location? */
15301
if(haveBeacon(_sender))
15303
_x = beaconX[_sender];
15304
_y = beaconY[_sender];
15306
else /* no beacon provided, use the current enemy location */
15308
if(killedBase[_player] and (not canSeePlayerBase(_player))) /* we have no idea where the enemy has rebuilt the base */
15310
notifyAllies(getPlayerName(_sender) & ", drop a beacon", false);
15313
else if(curBase[_player][0] > 0) /* remember or can directly see it */
15315
_x = curBase[_player][0];
15316
_y = curBase[_player][1];
15320
if(state != stNone) //stop if dealing with the one who messaged
15326
attackReason = ATTACK_BASE;
15327
startAttack(_player, _x, _y);
15328
notifyAllies("attacking " & getPlayerName(_player), TRUE);
15333
/*****************************/
15335
/*****************************/
15336
//if(match(_msg,"<player> got vtols", ref _player))
15337
if((_msg == "player has vtols") and (getNumArgsInCmd(_curMsg) == 1))
15340
if(getChatCmdParam(ref _player, _curMsg, 0))
15342
dbg("*************" & getPlayerName(_player) & " got vtols", me);
15346
if(hasVTOLs[_player])
15348
notifyAllies("I know", false);
15352
notifyAllies("ok", false);
15356
hasVTOLs[_player] = TRUE;
15361
/*************************/
15362
/* take enemy oil x */
15363
/*************************/
15365
//if(match(_processedString,"gonna get <player>'s derrick", ref _player))
15366
if((_msg == "getting player oil") and (getNumArgsInCmd(_curMsg) == 1))
15369
if(getChatCmdParam(ref _player, _curMsg, 0))
15371
dbg("*************gonna get " & getPlayerName(_player) & "'s derrick", me);
15373
allyState[_sender] = stTakingOil;
15374
allyEnemy[_sender] = _player;
15375
allyPhase[_sender] = phMoveToLoc; //or phAttackingLoc
15379
notifyAllies(getPlayerName(_sender) & ", you bastard!", false);
15380
breakAlliance(me, _sender);
15385
return; //just exit quietly
15387
/* ignore if already attacking this enemy somehow */
15388
if(enemy == _player)
15393
notifyAllies("isn't " & getPlayerName(_player) & " dead already?", false);
15397
/* ignore if busy */
15398
if((state != stNone) and (enemy != _sender) and (phase != phGuardingPos)) //not idle and not dealing with this player somehow (defendingBase etc) or psGuardingPos (is low prior)
15400
return; //just exit
15404
/* do we want to attack enemy's oil? */
15405
if(random(10) <= 6)
15407
/* do we have enough units to start start attacking enemy derrick alone? */
15408
if(haveTheoreticallyMinAttackers(true)) /* don't need too many for the derrick, hence "true" */
15410
/* find a derrick */
15411
structure = findEnemyDerrick(_player); /* find enemy derrick to attack */
15412
if(structure != NULLOBJECT)
15414
/* don't go on if we know where ally is attacking oil and this oil is too close to the derrick we have choosen to attack */
15415
if(not (haveBeacon(_sender) and distBetweenTwoPoints(beaconX[_sender], beaconY[_sender], structure.x, structure.y) < (25 * 128)))
15417
cancelState(); //stop if doing anything unimportant
15419
startTakingOil(structure);
15420
notifyTakeOil(structure.player, structure.x, structure.y);
15427
/* didn't start attacking derrick, decide if we want (and can) to attack the base directly */
15428
if(knowBase[_player] and haveTheoreticallyMinAttackers(false))
15430
cancelState(); /* stop if doing anything unimportant */
15431
startEnemyBaseAttack(_player);
15432
dropAllyBeacon("attacking " & getPlayerName(_player), curBase[_player][0], curBase[_player][1]);
15433
notifyAllies("attacking " & getPlayerName(_player), TRUE);
15440
/*************************/
15441
/* lassat player x */
15442
/*************************/
15444
//if(match(_processedString,"lassat <player>", ref _player))
15445
if((_msg == "lassat player") and (getNumArgsInCmd(_curMsg) == 1))
15448
if(getChatCmdParam(ref _player, _curMsg, 0))
15450
dbg("*******lassat " & _player, me);
15452
/* remember he just lassatted */
15453
lasSatState[_sender] = lsRecharging;
15454
lasSatEnemy = _player;
15456
/* if we were waiting for him to start the attack, start delayed attack */
15457
if(lasSatState[me] == lsWaitingForRequester)
15459
lasSatState[me] = lsDelayedFiring;
15460
tLasSatCountdown = 1 + (me * 9) + random(2); //every ally (except for requester) fires with delay of at least 1 sec to be more effective (to finish damaged structures) (lassat delay == 8-9 sec)
15469
// dbg("unknown message", me);
15474
dbg("i'm not addressed", me);
15479
//dbg("processCommand(" & _message & ", " & _sender & ") END------", me);
15482
event keyPressed(CALL_KEY_PRESSED, ref temp, ref temp2)
15484
//console("Key pressed: " & temp & ", meta key: " & temp2);
15487
if (temp != KEY_ESC)
15489
if(temp == KEY_SPACE) //space
15493
else if(temp == KEY_D and temp2 == KEY_LCTRL)
15495
dbg("Damaged selected object by 10%", me);
15496
InitEnumDroids(me, me);
15497
droid = EnumDroid();
15498
while(droid != NULLOBJECT)
15502
forceDamageObject(droid, 10);
15504
droid = EnumDroid();
15507
else if(temp == KEY_U and temp2 == KEY_LCTRL)
15509
if(baseX > 0 and baseY > 0)
15511
updatePlayerTileVis(me);
15512
if(checkVisibleTile(me, baseX / TILE, baseY / TILE))
15524
if(temp == KEY_P and (temp2 == KEY_RCTRL or temp2 == KEY_LCTRL))
15526
addPower(1000, me);
15527
console("add power");
15532
watchWindowDebug = modulo(watchWindowDebug + 1, 3);
15537
function void toggleDebugMenu()
15539
debugMenuUp = not debugMenuUp;
15540
debugMenu(debugMenuUp);
15543
/* Returns true if AI has all vital structures */
15544
function bool haveMinimalStructures()
15547
local STRUCTURE _structure;
15550
while(_index < numVitalStructs)
15552
if( (getNumStructures(minimalStruct[_index], me) + numStatBusy(minimalStruct[_index], FALSE))
15553
< numMinimalStruct[_index] )
15563
function void checkMinimalStructures()
15565
local int _index,_maxTrucks,_maxStructsAtATime,_numStructsAtATime;
15566
local bool _bStartedBuild;
15567
local STRUCTURE _structure;
15568
local FEATURE _oil;
15570
_maxStructsAtATime = 2;
15571
_numStructsAtATime = 0;
15574
while((_index < numVitalStructs) and (_numStructsAtATime < _maxStructsAtATime))
15576
if( (getNumStructures(minimalStruct[_index], me) +
15577
numStatBusy(minimalStruct[_index], false)) < numMinimalStruct[_index] )
15579
//see how many trucks are allowed to build this structure
15580
_maxTrucks = maxVitalBuilders[_index];
15581
if(_maxTrucks == -1){
15582
_maxTrucks = groupSizeCmds(buildGr,true,false,true); //use all trucks
15585
//if it's a derrick
15586
if(minimalStruct[_index] == derrick)
15588
_oil = findBestOilToBuildOn(baseX, baseY, -1);
15590
if(_oil != NULLOBJECT){
15591
dbg("Building minimal base - oil", me);
15593
bDummy = buildUsingClosestTruck(derrick, _oil.x, _oil.y, _maxTrucks); //Can skip "buildOnMap" for oil
15598
_bStartedBuild = buildInBase(minimalStruct[_index], _maxTrucks);
15600
if(_bStartedBuild){
15601
_numStructsAtATime++;
15603
dbg("Building minimal base " & _index, me);
15611
function bool droidActionAttacking(DROID _droid)
15613
if(_droid.order == DORDER_ATTACK){
15617
if(_droid.action == DACTION_ATTACK or
15618
_droid.action == DACTION_ROTATETOATTACK or
15619
_droid.action == DACTION_MOVETOATTACK){
15626
function bool droidOrderIdle(DROID _droid)
15628
if(_droid.order == DORDER_NONE){
15632
if(_droid.order == DORDER_GUARD){
15636
if(_droid.order == DORDER_RTB){
15643
function bool droidActionDroidRepair(DROID _repairer)
15645
if(_repairer.action == DACTION_DROIDREPAIR){
15649
if(_repairer.action == DACTION_MOVETODROIDREPAIR){
15656
function int numVisibleOilResInRange(int _x, int _y, int _range)
15659
local FEATURE _oil;
15661
initGetFeature(oilRes,me,me);
15662
_oil = getFeature(me);
15663
while(_oil != NULLOBJECT)
15665
if((_range <= 0) or (distBetweenTwoPoints(_x, _y, _oil.x, _oil.y) < _range))
15669
_oil = getFeature(me);
15675
function int numDerricksInRange(int _targetPlayer, int _x, int _y, int _range)
15677
local int _numDerricks;
15678
local STRUCTURE _derrick;
15682
initEnumStruct(false,derrick,_targetPlayer,me);
15683
_derrick = enumStruct();
15684
while(_derrick != NULLOBJECT)
15686
if((_range <= 0) or
15687
(distBetweenTwoPoints(_x, _y, _derrick.x, _derrick.y) < _range))
15691
_derrick = enumStruct();
15694
return _numDerricks;
15697
/* Returns total number (occupied and non-occupied) of oil resources that can be seen by a player */
15698
function int numTotalOilInRange(int _x, int _y, int _range)
15700
return numVisibleOilResInRange(_x, _y, _range) +
15701
numDerricksInRange(me, _x, _y, _range);
15704
function BASEOBJ closerObject(BASEOBJ _obj1, BASEOBJ _obj2, int _x, int _y)
15706
if(_obj1 == NULLOBJECT and _obj2 == NULLOBJECT){
15707
return _obj1; //NULLOBJECT
15710
if(_obj1 == NULLOBJECT){
15714
if(_obj2 == NULLOBJECT){
15718
if(distBetweenTwoPoints(_obj1.x, _obj1.y, _x, _y)
15719
< distBetweenTwoPoints(_obj2.x, _obj2.y, _x, _y))
15727
// decide if we have to defend oil derrick
15728
function void dealWithOilAttacked(int _oilx, int _oily)
15730
local BASEOBJ _oilLocation;
15732
if(isInMyBase(_oilx, _oily)){
15736
// remember when oil derrick under attack was attacked last time
15737
if(tOilAttackBegin > 0) // noticed some oil derrick being under attack
15739
// check if same derrick was attacked again
15740
_oilLocation = closerObject(closestDerrick(_oilx, _oily),
15741
closestOilResource(_oilx, _oily), _oilx, _oily);
15743
if(_oilLocation != NULLOBJECT)
15745
if(distBetweenTwoPoints(lastOilAttackedX, lastOilAttackedY,
15746
_oilLocation.x, _oilLocation.y) <= RANGE_ALL_OIL_DEFENSES)
15748
// remember last time derrick under siege was attacked
15749
tLastOilAttack = GAME_TIME_IN_SECS;
15754
// if it's a beginning of the attack, remember coordinates and when derrick was attacked
15755
if(tOilAttackBegin <= 0)
15757
// find derrick in danger
15758
_oilLocation = closerObject(closestDerrick(_oilx, _oily),
15759
closestOilResource(_oilx, _oily), _oilx, _oily);
15761
// make sure found derrick is not too far away
15762
if(_oilLocation != NULLOBJECT)
15764
if(distBetweenTwoPoints(_oilx, _oily, _oilLocation.x,
15765
_oilLocation.y) <= RANGE_ALL_OIL_DEFENSES)
15767
tOilAttackBegin = GAME_TIME_IN_SECS;
15768
tLastOilAttack = GAME_TIME_IN_SECS;
15770
lastOilAttackedX = _oilLocation.x;
15771
lastOilAttackedY = _oilLocation.y;
15776
// check if we have to defend attacked oil
15777
if((tOilAttackBegin > 0) and // it wasn't just a random bullet, the derrick is really under siege
15778
(GAME_TIME_IN_SECS > (tOilAttackBegin + MIN_TIME_OIL_ATTACKED_DELAY)))
15780
if(canStartDefendingOil())
15782
if(checkOilThreat(lastOilAttackedX, lastOilAttackedY))
15784
// start defending oil
15785
initializeStartDefeindingOil(lastOilAttackedX, lastOilAttackedY);
15791
function bool canStartDefendingOil()
15793
//if(!defendingOil() and !helpingAlly() and !defendingBase()) // not busy
15794
if(state == stNone) // not busy
15796
if(numAvailableAttackers() >= MIN_OIL_DEFENDERS)
15805
function bool checkOilThreat(int _oilx, int _oily)
15807
local int _enemyForce,_allyForce,_range,_tankShootRange;
15809
_range = CHECK_OIL_THREAT_RANGE;
15810
_tankShootRange = (TILE * 7); //doesn't make sense to change state if we can reach it anyway
15812
// make sure derrick is not in the base or within base defend range
15813
if(distBetweenTwoPoints(_oilx, _oily, baseX, baseY) >
15814
(baseRange + defendCorridor + _tankShootRange)) //not near my base
15816
if(!isNearEnemyBase(_oilx, _oily))
15818
_enemyForce = enemyWeapObjCostInRange(me, _oily,
15819
_oily, _range, false, true);
15821
_allyForce = friendlyWeapObjCostInRange(me, _oilx,
15822
_oily, _range, false, true);
15824
// make sure enemy force is stronger
15825
if((_enemyForce - _allyForce) > 0)
15835
function bool canStartTakingOil()
15837
//if(!defendingOil() and !helpingAlly() and !defendingBase()) // not busy
15838
if(numAvailableAttackers() >= numOilAttackers){
15842
// if(state != stNone){ // busy
15849
function bool initializeStartTakingOil(int _oilx, int _oily, int _maxRange)
15851
local STRUCTURE _enemyDerrick;
15853
// cancel state if busy and not doing anything important
15854
if(state != stNone){
15858
_enemyDerrick = findBestEnemyDerrick(none, numAvailableAttackers(),
15859
sendForceX, sendForceY, _maxRange);
15861
if(_enemyDerrick == NULLOBJECT)
15866
startTakingOil(_enemyDerrick);
15871
// make necessary calculations to be able to start defending oil derrick
15872
function void initializeStartDefeindingOil(int _oilx, int _oily)
15874
local int _maxDefendingOilTime;
15876
_maxDefendingOilTime = distBetweenTwoPoints(_oilx, _oily,
15877
baseX, baseY) / TILE + MIN_DEF_OIL_TIME;
15879
dbg("OIL IS THREATENED AT " & (_oilx / TILE) & "/" &
15880
(_oily / TILE) & " (" & _maxDefendingOilTime & " secs)", me);
15882
// cancel state if busy and not doing anything important
15883
if(state != stNone){
15887
startDefendingOil(_oilx, _oily, _maxDefendingOilTime);
15890
function void startDefendingOil(int _derrickX, int _derrickY, int _maxTime)
15892
dbg("DEFENDING OIL!!!!!!!!!!!!!!!!!!!!!!!!!!", me);
15896
updateStateCoord(_derrickX, _derrickY);
15898
// circlePerimPoint(_derrickX, _derrickY, ref sendForceX, ref sendForceY, (TILE * 4));
15900
if((sendForceX <= 0) or (sendForceY <= 0))
15902
MsgBox("startDefendingOil() - sendForceX <= 0");
15906
setState(stDefendingOil);
15908
setPhase(phMoveToLoc, NONE);
15910
maxStateTime = _maxTime;
15912
// Set minimum number of defenders to leave in the base
15913
updateNumDefenders();
15915
dbg("defending oil at " & _derrickX & "/" & _derrickY & " !!!!!!!!!!!!!!!!!!!!!!!!", me);
15917
/* Assign attackers and commanders to groups */
15918
prepareAttackers(false);
15922
dropAllyBeacon("defending my oil", sendForceX, sendForceY);
15925
/* Returns how many friendly units will be left after some period of time, given starting forces and forces effectivenesses */
15926
function float secondLanchasterLaw(float _fAllyStartForce, float _fEnemyStartForce,
15927
int _time, //time in seconds that has to pass
15928
float _allyEffectiveness,
15929
float _enemyEffectiveness)
15931
local float _sqrtDivEffect, //square root from (ally effectiveness / enemy effectiveness)
15932
_sqrtMultTimeEffect; //time multiplied with square root from (ally effectiveness * enemy effectiveness)
15934
// number of force won't change if enemy can't attack or if there are no enemies
15935
if(_fEnemyStartForce == 0.0 or _enemyEffectiveness == 0.0){
15936
return _fAllyStartForce;
15939
_sqrtDivEffect = sqrt(_allyEffectiveness / _enemyEffectiveness);
15940
_sqrtMultTimeEffect = sqrt(_allyEffectiveness * _enemyEffectiveness) * (float)_time;
15942
return 0.5 * (( _fAllyStartForce - _sqrtDivEffect * _fEnemyStartForce) * exp(_sqrtMultTimeEffect) +
15943
(_fAllyStartForce + _sqrtDivEffect * _fEnemyStartForce) * exp(-_sqrtMultTimeEffect));
15946
function bool LanchasterVictory(float _fStartForceA, float _fStartForceB,
15947
float _fKillRateA, float _fKillRateB)
15949
//ASSERT(!(_fStartForceB > 0 and _fKillRateB <= 0.0), "_fKillRateB can't be 0", me);
15951
// avoid division by zero
15952
/* if(_fStartForceB <= 0 or _fKillRateB <= 0.0){
15956
// check if force A is going to win
15957
if( ((float)_fStartForceA / (float)_fStartForceB) > sqrt(_fKillRateA / _fKillRateB)){
15961
//in case one of the sides has 0 units both kill rates will be 0.0
15962
if(_fKillRateA == 0.0 and _fKillRateB == 0.0)
15964
if(_fStartForceA > 0.0 and _fStartForceB <= 0.0){
15966
}else if(_fStartForceA <= 0.0 and _fStartForceB > 0.0){
15971
if( (sqrt(_fKillRateA) * _fStartForceA) >= (sqrt(_fKillRateB) * _fStartForceB) ){
15978
/* How much time does it take for side A to win? */
15979
function int LanchasterTimeToWin(float _fStartForceA, float _fStartForceB,
15980
float _fKillRateA, float _fKillRateB)
15982
local float _fTimeToWin,_fKillFactor,_devisor;
15984
if(_fStartForceA <= 0.0 or _fStartForceB <= 0.0 or _fKillRateB == 0.0){
15988
_fKillFactor = (_fStartForceB / _fStartForceA) *
15989
sqrt(_fKillRateA / _fKillRateB);
15991
// avoid division by 0
15992
if( (1.0 - _fKillFactor) == 0.0){
15996
// store the result so we can catch division by 0
15997
_devisor = (2.0 * sqrt(_fKillRateA * _fKillRateB)) *
15998
log ( (1.0 + _fKillFactor) / (1.0 - _fKillFactor) );
16000
// avoid division by 0
16001
if(_devisor == 0.0){
16005
_fTimeToWin = 1.0 / _devisor;
16007
return (int)_fTimeToWin;
16010
function float weaponDamagePerSec(int _player, WEAPON _weap)
16012
local float _fFirePowerPerSec,_fFireRatePerSec,_fShortRangeDamagePerSec,
16013
_fLongRangeDamagePerSec,_fReloadTimeInSecs,_fFirePauseInSecs;
16015
local int _upgradedShortHit,_upgradedLongHit,_upgradedDamage,
16016
_upgradedFirePause;
16018
local int _tempShortHit;
16020
_tempShortHit = weaponShortHitUpgrade(_player, _weap);
16022
// get upgradable weapon values
16023
_upgradedShortHit = _weap.shortHit + (_weap.shortHit * _tempShortHit) / 100;
16024
_upgradedLongHit = _weap.longHit + (_weap.longHit * weaponLongHitUpgrade(_player, _weap)) / 100;
16025
_upgradedDamage = _weap.damage + (_weap.damage * weaponDamageUpgrade(_player, _weap)) / 100;
16026
_upgradedFirePause = _weap.firePause + (_weap.firePause * weaponFirePauseUpgrade(_player, _weap)) / 100;
16029
//debug("weap damage " & _weap.firePause & "," & _weap.reloadTime & "," & _weap.numRounds &
16030
// "," & _weap.damage & "," & _weap.shortHit & "," & _weap.longHit);
16031
//debug("weap damage2 " & _upgradedShortHit & "," & _upgradedLongHit & "," & _upgradedDamage &
16032
// "," & _upgradedFirePause);
16033
//debug("weap damage3 " & weaponDamageUpgrade(_player, _weap) & "," & weaponShortHitUpgrade(_player, _weap) & "," & weaponLongHitUpgrade(_player, _weap) &
16034
// "," & weaponFirePauseUpgrade(_player, _weap));
16037
// avoid division by 0
16038
_fFirePauseInSecs = (float)_upgradedFirePause / 1000.0;
16039
if(_fFirePauseInSecs == 0.0){
16040
_fFirePauseInSecs = 0.001;
16043
if(_weap.numRounds > 0){
16045
// avoid division by 0
16046
if(_weap.reloadTime == 0){
16047
_fReloadTimeInSecs = 0.001;
16049
_fReloadTimeInSecs = (float)_weap.reloadTime / 1000.0;
16052
_fFireRatePerSec = 1.0 / ((_fReloadTimeInSecs + (_fFirePauseInSecs * (float)(_weap.numRounds - 1))) / (float)_weap.numRounds);
16054
_fFireRatePerSec = 1.0 / _fFirePauseInSecs;
16058
_fShortRangeDamagePerSec = _fFireRatePerSec * ((float)_upgradedDamage / 100.0 * (float)_upgradedShortHit);
16059
_fLongRangeDamagePerSec = _fFireRatePerSec * ((float)_upgradedDamage / 100.0 * (float)_upgradedLongHit);
16061
_fFirePowerPerSec = (_fShortRangeDamagePerSec + _fLongRangeDamagePerSec) / 2.0;
16063
return _fFirePowerPerSec;
16066
// firepower of a droid (including upgrades)
16067
function float objBaseDamagePerSec(BASEOBJ _obj)
16069
// Make sure droid has a weapon
16070
if(_obj.weapon == NULLSTAT){
16074
return weaponDamagePerSec(_obj.player, _obj.weapon);
16077
function float enemyFirepowerInRange(int _x, int _y, int _range)
16080
local float _fFirePower;
16084
while(_enemy < MAX_PLAYERS)
16086
if(_enemy != me and !allianceExistsBetween(_enemy, me))
16088
_fFirePower = _fFirePower + playerFirepowerInRange(_enemy, _x, _y, _range);
16093
return _fFirePower;
16096
function float friendlyFirepowerInRange(int _x, int _y, int _range)
16098
local int _allyOrMe;
16099
local float _fFirePower;
16103
while(_allyOrMe < MAX_PLAYERS)
16105
if(_allyOrMe == me or allianceExistsBetween(_allyOrMe, me))
16107
_fFirePower = _fFirePower + playerFirepowerInRange(_allyOrMe, _x, _y, _range);
16112
return _fFirePower;
16115
function float playerFirepowerInRange(int _player, int _x, int _y, int _range)
16117
local float _fFirePower;
16118
local DROID _droid;
16119
local STRUCTURE _structure;
16123
InitEnumDroids(_player,me);
16124
_droid = EnumDroid();
16125
while(_droid != NULLOBJECT)
16127
if(!isVtol(_droid))
16129
if(objHasWeapon(_droid))
16131
if(distBetweenTwoPoints(_x, _y, _droid.x, _droid.y) < _range)
16133
_fFirePower = _fFirePower + objBaseDamagePerSec(_droid);
16137
_droid = EnumDroid();
16140
//iterate through all strucrures
16141
initEnumStruct(TRUE,derrick,_player,me);
16142
_structure = enumStruct();
16143
while(_structure != NULLOBJECT)
16145
if(objHasWeapon(_structure))
16147
if(structureComplete(_structure))
16149
if(distBetweenTwoPoints(_x, _y, _structure.x, _structure.y) < _range)
16151
_fFirePower = _fFirePower + objBaseDamagePerSec(_structure);
16155
_structure = enumStruct();
16158
return _fFirePower;
16161
function float groupFirepower(GROUP _group)
16164
local float _fFirePower;
16165
local DROID _droid;
16169
_bucket = initIterateGroupCmd(_group,true,true,true);
16170
_droid = iterateGroupCmd(_group, _bucket);
16171
while(_droid != NULLOBJECT)
16173
_fFirePower = _fFirePower + objBaseDamagePerSec(_droid);
16174
_droid = iterateGroupCmd(_group, _bucket);
16177
return _fFirePower;
16180
function float groupHP(GROUP _group)
16183
local float _fDroidHP;
16184
local DROID _droid;
16188
_bucket = initIterateGroupCmd(_group,true,true,true);
16189
_droid = iterateGroupCmd(_group, _bucket);
16190
while(_droid != NULLOBJECT)
16192
_fDroidHP = _fDroidHP + (float)_droid.hitPoints;
16193
_droid = iterateGroupCmd(_group, _bucket);
16200
function int totalEnemyWeapObjHPInRange(int _x, int _y, int _range, bool _bVtols)
16202
local int _enemy,_enemyHP;
16206
while(_enemy < MAX_PLAYERS)
16208
if(_enemy != me and !allianceExistsBetween(_enemy, me))
16210
_enemyHP = _enemyHP + totalPlayerWeapObjHPInRange(_enemy, _x, _y, _range, _bVtols);
16218
function int totalFriendlyWeapObjHPInRange(int _x, int _y, int _range, bool _bVtols)
16220
local int _allyOrMe,_friendlyHP;
16224
while(_allyOrMe < MAX_PLAYERS)
16226
if(_allyOrMe == me or allianceExistsBetween(_allyOrMe, me))
16228
_friendlyHP = _friendlyHP + totalPlayerWeapObjHPInRange(_allyOrMe, _x, _y, _range, _bVtols);
16233
return _friendlyHP;
16237
function int totalPlayerWeapObjHPInRange(int _player, int _x, int _y,
16238
int _range, bool _bVtols)
16241
local DROID _droid;
16242
local STRUCTURE _structure;
16246
InitEnumDroids(_player,me);
16247
_droid = EnumDroid();
16248
while(_droid != NULLOBJECT)
16250
if(!isVtol(_droid) or _bVtols)
16252
if(objHasWeapon(_droid))
16254
if(distBetweenTwoPoints(_x, _y, _droid.x, _droid.y) < _range)
16256
_hp = _hp + _droid.hitPoints;
16260
_droid = EnumDroid();
16263
//iterate through all strucrures
16264
initEnumStruct(TRUE,derrick,_player,me);
16265
_structure = enumStruct();
16266
while(_structure != NULLOBJECT)
16268
if(objHasWeapon(_structure))
16270
if(structureComplete(_structure))
16272
if(distBetweenTwoPoints(_x, _y, _structure.x, _structure.y) < _range)
16274
_hp = _hp + _structure.hitPoints;
16278
_structure = enumStruct();
16284
function bool isTankTemplate(TEMPLATE _tmpl)
16286
local int _tmplIndex,_techIndex;
16289
while(_techIndex < numBranches)
16292
while(_tmplIndex < numTemplates[_techIndex])
16294
if(_tmpl == tmpl[_techIndex][_tmplIndex])
16307
function void resetOilDefendCoords()
16309
tOilAttackBegin = none; // when enemy started attacking oil derrick
16310
tLastOilAttack = none;
16311
lastOilAttackedX = none; // position of the attacked oil derrick
16312
lastOilAttackedY = none;
16315
event evUpdateMapRevealFactor(inactive)
16317
updateMapRevealFactor();
16320
function void updateMapRevealFactor()
16322
local int _x,_y,_numUnrevealedTiles,_totalTiles,_step;
16324
_numUnrevealedTiles = 0;
16329
while(_x < (mapWidth - 1))
16332
while(_y < (mapHeight - 1))
16334
if(!mapTileVisible(me, _x,_y))
16336
_numUnrevealedTiles++;
16343
_totalTiles = mapWidth * mapHeight;
16345
fMapRevealFactor = MAP_REVEAL_FAC_UBOUND -
16346
(float)(_totalTiles - max(0, _numUnrevealedTiles * _step)) /
16347
(float)_totalTiles;
16350
function DROID closestEnemyDroidByType(int _x, int _y, int _range, int _type)
16352
local DROID _droid,_closestDroid;
16353
local int _closestDist,_tempDist,_enemy;
16355
_closestDist = 99999;
16356
_closestDroid = NULLOBJECT;
16359
while(_enemy < MAX_PLAYERS)
16361
if(!allianceExistsBetween(_enemy, me) and _enemy != me)
16363
InitEnumDroids(_enemy, me);
16364
_droid = EnumDroid();
16365
while(_droid != NULLOBJECT)
16367
if(_type < 0 or _droid.droidType == _type)
16369
_tempDist = distBetweenTwoPoints(_droid.x, _droid.y, _x, _y);
16370
if(_range < 0 or _tempDist < _range)
16372
if(_tempDist < _closestDist)
16374
_closestDist = _tempDist;
16375
_closestDroid = _droid;
16379
_droid = EnumDroid();
16386
return _closestDroid;
16389
/* Thank someone */
16390
function string strGratitude()
16396
}else if(dice < 7){
16399
return "thank you";
16405
function void setPhase(int _phase, int _timeout)
16411
function bool canSeePlayerBase(int _player)
16413
return seeBase[_player];
16416
function bool canSeeLoc(int _x, int _y)
16418
updatePlayerTileVis(me);
16419
return checkVisibleTile(me, _x / TILE, _y / TILE);
16422
function bool enemyTargetInRange(int _enemy, int _x, int _y, int _range)
16424
local bool _bHaveTarget;
16426
_bHaveTarget = structInRangeVis(me, _enemy, _x, _y, _range);
16430
_bHaveTarget = droidInRangeVis(me, _enemy, _x, _y, _range);
16433
return _bHaveTarget;
16436
function BASEOBJ findEnemyTargetInRange(int _enemy, int _x, int _y, int _range, bool _bStructures, bool _bDroids)
16438
local BASEOBJ _target;
16443
_target = getClosestEnemyStructByType(_x, _y, _range, REF_FACTORY, _enemy);
16445
if(_target == NULLOBJECT)
16447
_target = getClosestEnemyStructByType(_x, _y, _range, REF_CYBORG_FACTORY, _enemy);
16450
if(_target == NULLOBJECT)
16452
_target = getClosestEnemyStructByType(_x, _y, _range, REF_HQ, _enemy);
16455
if(_target == NULLOBJECT)
16457
_target = getClosestEnemyStructByType(_x, _y, _range, REF_POWER_GEN, _enemy);
16461
if(_target == NULLOBJECT)
16463
_target = getClosestEnemyStructByType(_x, _y, _range, NONE, _enemy);
16468
if(_bDroids and _target == NULLOBJECT)
16470
_target = getClosestEnemyDroidByType(_x, _y, _range, NONE, true, _enemy);
16476
function PROPULSION getBestTankPropulsion()
16480
_index = numTankPropulsions - 1;
16483
if(isComponentAvailable(me, tankPropulsion[_index]))
16485
dbg("best prop index is " & _index, me);
16486
return tankPropulsion[_index];
16491
dbg("no prop ", me);
16495
function BODY getBestTankBody(int _factoryCapacity)
16499
_index = numTankBodies - 1;
16502
if(isComponentAvailable(me, tankBody[_index]))
16504
// make sure can be built by factory
16505
if(getBodySize(tankBody[_index]) <= _factoryCapacity)
16507
dbg("best body index is " & _index, me);
16508
return tankBody[_index];
16514
dbg("no body for size " & _factoryCapacity & " (" & getBodySize(tankBody[0]) & ")", me);
16518
function WEAPON getBestTankATWeapon()
16520
local int _index,_bestIndex,_bestDamage,_damage;
16521
local WEAPON _bestWeapon;
16523
_bestDamage = NONE;
16527
while(_index < numTankATWeapons)
16529
if(isComponentAvailable(me, tankATWeapon[_index]))
16531
_damage = (int)weaponDamagePerSec(me, tankATWeapon[_index]);
16532
dbg("damage of " & _index & " is " & _damage, me);
16533
if((_damage > _bestDamage) || (_bestIndex == NONE))
16535
dbg("_bestIndex = " & _index , me);
16536
_bestIndex = _index;
16537
_bestWeapon = tankATWeapon[_index];
16538
_bestDamage =_damage;
16544
dbg("best weapon index is " & _bestIndex, me);
16546
return _bestWeapon; // can be NULLSTAT
16549
function TEMPLATE getBestTankATTemplate(int _factoryCapacity)
16551
local TEMPLATE _newTemplate;
16552
local BODY _bestBody;
16553
local PROPULSION _bestPropulsion;
16554
local WEAPON _bestWeapon;
16556
_bestBody = getBestTankBody(_factoryCapacity);
16557
_bestPropulsion = getBestTankPropulsion();
16558
_bestWeapon = getBestTankATWeapon();
16560
if(_bestBody != NULLSTAT and
16561
_bestPropulsion != NULLSTAT and
16562
_bestWeapon != NULLSTAT)
16564
_newTemplate = assembleWeaponTemplate(me, _bestBody, _bestPropulsion, _bestWeapon);
16567
return _newTemplate; // can be NULLTEMPLATE