~ubuntu-branches/ubuntu/lucid/warzone2100/lucid

« back to all changes in this revision

Viewing changes to data/mods/multiplay/aivolution/multiplay/skirmish/player7.slo

  • Committer: Bazaar Package Importer
  • Author(s): Christoph Egger, Paul Wise, Christoph Egger
  • Date: 2009-06-29 17:12:52 UTC
  • mfrom: (1.1.11 upstream) (2.1.7 squeeze)
  • Revision ID: james.westby@ubuntu.com-20090629171252-5ddnlfg3zfchrega
Tags: 2.2.1+dfsg1-1
[ Paul Wise ]
* New upstream release (Closes: #534962)
* Adjust the flex build-depends to take account of the conflict
  with all the versions of flex 2.5.34 (LP: #372872)
* Make the -music Recommends more strict, 2.1 music doesn't work
  with 2.2.
* Upstream moved the downloads to sourceforge, update the watch file
* Bump Standards-Version, no changes needed
* Drop use of dh_desktop since it no longer does anything
* Recommend the new warzone2100-video package, version 2.2 or similar
* Mention the warzone2100 crash reports in the -dbg package description

[ Christoph Egger ]
* Replace CC-2.0 graphic from cybersphinx, create a new tarball
* Add myself to uploaders

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* General stuff */
 
2
#define MAX_PLAYERS                                             8
 
3
#define TILE                                                    128
 
4
#define MAX_UNITS                                               110
 
5
 
 
6
/* Should be used with GAME_TIME_IN_SECS, not with gameTime */
 
7
#define SECOND                                                  1
 
8
#define MINUTE                                                  (SECOND * 60)
 
9
 
 
10
/* How many seconds it takes to cross a tile */
 
11
#define TILE_TRAVEL_TIME                                1
 
12
 
 
13
/* Defines for debug watch window */
 
14
#define WATCH_DEBUG_REINF                               0
 
15
#define WATCH_DEBUG_RESEARCH                    1
 
16
#define WATCH_DEBUG_CMDS                                2
 
17
 
 
18
/* 10 secs are equivalent to 1 droid */
 
19
#define SECONDS_PER_DROID                               10
 
20
 
 
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)
 
24
 
 
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)
 
28
 
 
29
/* Max game time when we build scouts, stop afterwards */
 
30
#define SCOUT_BUILD_TIME                                (MINUTE * 8)
 
31
 
 
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)
 
35
 
 
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
 
40
 
 
41
/* min number of reinforcements to use when helping ally */
 
42
#define MIN_HELPING_ALLY_REINF                  5
 
43
 
 
44
#define MIN_COUNTERATTACKERS                    6
 
45
#define MIN_OIL_DEFENDERS                               8
 
46
 
 
47
/* Commanders stuff */
 
48
#define MAX_COMMANDERS                                  10
 
49
#define CMD_INIT_CAPACITY                               6
 
50
#define MAX_CMD_ASSIGN_DIST                             (TILE * 25)
 
51
 
 
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)
 
55
 
 
56
#define MAX_DEFEND_REPAIRERS                    7
 
57
 
 
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)
 
60
 
 
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)
 
63
 
 
64
/* How many defenders are rapired by a single repair unit */
 
65
#define NUM_DEFENDERS_PER_REPAIRER              4
 
66
 
 
67
/* Choose randomly from this number of available templates */
 
68
#define MAX_CHOICE_DROIDS                               3
 
69
#define MAX_CHOICE_LIGHT_CYB                    2
 
70
 
 
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))
 
73
 
 
74
/* How useless a base defense is compared to a normal unit */
 
75
#define STR_UNIT_DEFENSE_FACTOR                 4
 
76
 
 
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
 
81
 
 
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
 
84
 
 
85
/* Max number of group iteration thet can take place at the same time */
 
86
#define MAX_GROUP_ITERATE_BUCKET                5
 
87
 
 
88
/* How many trucks to use when upgrading certain structures */
 
89
#define MAX_POWGEN_UPGRADE_TRUCKS               2
 
90
#define MAX_FACTORY_UPGRADE_TRUCKS              3
 
91
 
 
92
                        /* Research stuff */
 
93
 
 
94
/* Min research facilities to use when researching */
 
95
#define F_MIN_ACTIVE_RES_FAC                    (2.5)
 
96
 
 
97
#define GAME_TIME_IN_SECS                               (gameTime / 10)
 
98
 
 
99
/* in secs */
 
100
#define LEGO_PHASE_LEN                                  (MINUTE * 5)
 
101
#define STARTUP_PHASE_LEN                               (SECOND * 4)
 
102
 
 
103
#define MIN_DEF_OIL_TIME                                (MINUTE * 4)
 
104
 
 
105
// hardcoded amyway
 
106
#define MAX_BUILDERS                                    15
 
107
 
 
108
#define CHECK_OIL_THREAT_RANGE                  (TILE * 12)
 
109
 
 
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))
 
113
 
 
114
#define THROW_DICE                                              random(100)
 
115
 
 
116
/* Reinforcements: What range to use when counting enemies for threat assessing */
 
117
#define REINF_ENEMY_COUNT_RANGE                 (TILE * 12)
 
118
 
 
119
                                /* Oil building */
 
120
 
 
121
// max range to look for further oil when finished building an oil derrick
 
122
#define NEXT_OIL_RANGE                                  (TILE * 11)
 
123
 
 
124
                                /* Oil defense */
 
125
 
 
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)
 
129
 
 
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)
 
134
 
 
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
 
138
 
 
139
// range of oil defenses for a single stored oil defense location
 
140
#define OIL_DEFENSES_RANGE                              (TILE * 5)
 
141
 
 
142
// try to cover all oil defenses with this range
 
143
#define RANGE_ALL_OIL_DEFENSES                  (OIL_DEFENSES_RANGE + DEFENSE_DIST_FROM_OIL)
 
144
 
 
145
//max number of trucks that can build defenses for a single oi lderrick
 
146
#define MAX_TRUCKS_PER_OIL_DEFENSE              1
 
147
 
 
148
// Whether to build defenses for derricks located in the base
 
149
#define DEFEND_BASE_DERRICKS                    false
 
150
 
 
151
                                /* Base defense */
 
152
 
 
153
// range of base defenses
 
154
#define BASE_DEFENSES_RANGE                             (TILE * 5)
 
155
 
 
156
//max number of recalled base defend locations to build defenses at
 
157
#define MAX_BASE_DEFENSE_LOCATIONS              5
 
158
 
 
159
#define MIN_BASE_RECALL_PRIORITY                1
 
160
 
 
161
#define MAX_BASE_DEFEND_LOCS                    7
 
162
 
 
163
#define MAX_BASE_DEFENSES_PER_LOC               7
 
164
#define MIN_BASE_DEFENSES_PER_LOC               5
 
165
 
 
166
#define NUM_BASE_DEF_LOC_TRUCKS                 1
 
167
 
 
168
// trucks to use for the same location when base is in danger
 
169
#define MAX_BASE_DEF_LOC_TRUCKS                 3
 
170
 
 
171
 
 
172
#define REACHED_DEST_RANGE                              (TILE * 17)
 
173
#define REACHED_DEF_OIL_RANGE                   (TILE * 10)
 
174
 
 
175
/* Weights for choose an enemy */
 
176
#define W_LOST_UNITS            0.6
 
177
//Weight per tile
 
178
#define W_BASE_DISTANCE         0.4
 
179
#define AVERAGE_UNIT_COST       250
 
180
 
 
181
//2 units for 50 tiles
 
182
#define TILE_TRAVEL_COST        10.0
 
183
 
 
184
                                /* Scouts */
 
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
 
188
 
 
189
/* Number of oil scouts */
 
190
#define MIN_OIL_SCOUTS                                  0
 
191
#define MAX_OIL_SCOUTS                                  5
 
192
 
 
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
 
195
 */
 
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
 
200
 
 
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
 
209
 
 
210
#define NONE                                                    (-1)
 
211
#define ALL                                                             (-2)
 
212
#define ANY                                                             (-3)
 
213
 
 
214
// reason why we attacked someone
 
215
#define ATTACK_BASE                                             1
 
216
#define ATTACK_COUNTER_ARTY                             2
 
217
 
 
218
 
 
219
 
 
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,
 
225
                                                numTankBodies;
 
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;
 
236
 
 
237
public  RESEARCHSTAT    research[3][60],resBB,resCmd;
 
238
public  BODY                    viperBody;
 
239
public  WEAPON                  weaponBB;
 
240
public  BRAIN                   cmdTurret;
 
241
 
 
242
//-----------------------
 
243
// private vars
 
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],
 
268
                                bToEnemyScoutGr;
 
269
 
 
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;
 
285
 
 
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;
 
307
 
 
308
 
 
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,
 
313
                                                lasSatTarget;
 
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;
 
321
 
 
322
private int                             maxAttackCyborgs,attackReason;
 
323
private bool                    bBuildCyborgs;
 
324
private int                             tPhase;
 
325
private bool                    bCheckBaseDebug;
 
326
 
 
327
private STRUCTURESTAT   ghostStat[120];
 
328
 
 
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;
 
368
event   doScout;
 
369
event   droidBuilt;
 
370
event   structBuilt;
 
371
event   structDestroyed;
 
372
event   structureAttacked;
 
373
event   droidAttacked;
 
374
event   objectAttacked;
 
375
event   everySecEv;
 
376
event   consoleEv;
 
377
event   multiMsgEv;
 
378
event   beaconEv;
 
379
event   droidTakeOverEv;
 
380
event   transLanded;
 
381
event   defendBase;
 
382
event   doResearchEv;
 
383
event   defendOil;
 
384
event   buildNormalOilDefenses;
 
385
event   scoutForEnemy;
 
386
event   coordinatePhases;
 
387
event   manageCMDRepairsEv;
 
388
event   repairDefendDroids;
 
389
event   diffMod;
 
390
event   allianceOffered;
 
391
event   droidSeen;
 
392
event   objectSeen;
 
393
event   checkLost;
 
394
event   buildStructureModel;
 
395
event   startNewResearch;
 
396
event   startAllResearch;
 
397
event   evUpdateMapRevealFactor;
 
398
event   delayedMainInitialize;
 
399
 
 
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();
 
409
 
 
410
 
 
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();
 
431
 
 
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();
 
452
 
 
453
function void   startEnemyScout();
 
454
function void   getNextScoutCoord(int _lastX, int _lastY);
 
455
function void   closerTruck();
 
456
 
 
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);
 
465
 
 
466
//Functions
 
467
 
 
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);
 
501
 
 
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();
 
512
 
 
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();
 
520
 
 
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);
 
531
 
 
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);
 
555
 
 
556
function void   fillHelpers();
 
557
 
 
558
function int    findBestAA();
 
559
function int    findBestDefense();
 
560
 
 
561
function void   setCollectingLoc();
 
562
function void   startCollectingPhase();         //gather together
 
563
function void   startCollecting();              //gather together
 
564
 
 
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);
 
568
 
 
569
function void   updateTransport();
 
570
function void   updateDropPhase();
 
571
 
 
572
function void   startMovePhase();
 
573
function void   startTransportState(GROUP _groupToTransport, int _destinationX, int _destinationY);
 
574
 
 
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();
 
585
 
 
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();
 
596
 
 
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();
 
605
 
 
606
function void   pauseState();
 
607
function void   resumeState();
 
608
function void   erasePausedState();
 
609
function void   resetSendForceCoords();
 
610
 
 
611
function void   loadSavedState();
 
612
function void   saveCurrentState();
 
613
function void   eraseLoadSavedState();
 
614
 
 
615
function bool   canStopCollecting();    //finished gathering or time is up
 
616
function bool   finishedCollecting();   //finished gathering
 
617
 
 
618
function void   doAlly(int _playerOffered);
 
619
 
 
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);
 
627
 
 
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();
 
646
 
 
647
function void   refreshAllyRadar();
 
648
function void   rememberPlayerIsAlive(int _alivePlayer);
 
649
 
 
650
function int    bestAlliancePlayer();
 
651
function void   makeAlliances();
 
652
function bool   canAlly(int _player);
 
653
function void   doOfferAlliance(int _alliancePlayer);
 
654
 
 
655
function void   findAttackBaseTarget(DROID _looker, int _x, int _y, int _radius);
 
656
function void   findBBAttackBaseTarget(DROID _looker);
 
657
 
 
658
function void   storeBaseDefLocEv();
 
659
function void   storeOilDefLocEv();
 
660
 
 
661
function void   deselectAllDroids();
 
662
function void   goRTB();
 
663
function void   saveExperience();
 
664
 
 
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();
 
710
 
 
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);
 
733
 
 
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);
 
739
 
 
740
function void   setTechBranch();
 
741
 
 
742
function string groupToString(GROUP _group);
 
743
function string droidToGroupName(DROID _droid);
 
744
 
 
745
function void   goToPerim(int _centerX, int _centerY, int _fromX, int _fromY, int _perimRange, int _order, DROID _droid);
 
746
 
 
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);
 
782
 
 
783
function string strGratitude();
 
784
 
 
785
function TEMPLATE getBestTankATTemplate(int _factoryCapacity);
 
786
 
 
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);
 
792
 
 
793
function PROPULSION getBestTankPropulsion();
 
794
function BODY getBestTankBody(int _factoryCapacity);
 
795
function WEAPON getBestTankATWeapon();
 
796
 
 
797
//=====================================================================
 
798
//      Events
 
799
//=====================================================================
 
800
//event powerup(CALL_GAMEINIT)
 
801
event powerup(wait, 5)
 
802
{
 
803
        local bool bMyRespons,bNotLost;
 
804
 
 
805
        DEBUG_ALL = false;
 
806
 
 
807
        DEBUG_MSG = DEBUG_ALL;          //isHumanPlayer(player);
 
808
                                                                /*%!    ID="DEBUG_MSG",
 
809
                                                                MainDesc="DEBUG messages",
 
810
                                                                type="asn",             //Assign
 
811
                                                                tmpl="YesNo"    */
 
812
        DEBUG_OBSERVE = DEBUG_ALL;      /*%!    ID="DEBUG_OBSERVE",
 
813
                                                                MainDesc="DEBUG observe mode",
 
814
                                                                type="asn",             //Assign
 
815
                                                                tmpl="YesNo"    */
 
816
        DEBUG_POWER = FALSE;            /*%!    ID="DEBUG_POWER",
 
817
                                                                MainDesc="DEBUG power",
 
818
                                                                type="asn",             //Assign
 
819
                                                                tmpl="YesNo"    */
 
820
 
 
821
        DEBUG_COMMANDS = DEBUG_ALL;             /*%!    ID="DEBUG_COMMANDS",
 
822
                                                                MainDesc="DEBUG commands",
 
823
                                                                type="asn",             //Assign
 
824
                                                                tmpl="YesNo"    */
 
825
 
 
826
        modifierOn = TRUE;
 
827
 
 
828
        bLearn = TRUE;          //Use experience?
 
829
        sVer = "1.4";
 
830
 
 
831
        bRunning = FALSE;       //remember this AI is inactive
 
832
 
 
833
        me = player;
 
834
 
 
835
        myName = getPlayerColourName(me) & "-Aiv";
 
836
 
 
837
        dbgMsgOn(me, DEBUG_MSG);
 
838
 
 
839
 
 
840
        /* Check if this AI is inactive */
 
841
        groupAddArea(tempGr, player, 0, 0, (mapWidth*128), (mapHeight*128));
 
842
        structure = getStructure(fac, me);
 
843
 
 
844
        bNotLost = TRUE;
 
845
        if((tempGr.members == 0) and (structure == NULLOBJECT))
 
846
        {
 
847
                bNotLost = FALSE;
 
848
        }
 
849
 
 
850
        //find out if this player is controlled by AI
 
851
        bMyRespons = FALSE;
 
852
        if(myResponsibility(me) and ((me != selectedPlayer) or DEBUG_OBSERVE))
 
853
        {
 
854
                if(bNotLost){   //alive?
 
855
                        bMyRespons = TRUE;
 
856
                }else{
 
857
                        dbg("deactivated", me);
 
858
                }
 
859
        }
 
860
        else
 
861
        {
 
862
                dbg("not my responsibility", me);
 
863
        }
 
864
 
 
865
        //do common one-time initialization only if this player is loaded
 
866
        if(bNotLost){
 
867
                oneTimeInitialize(bMyRespons);
 
868
        }
 
869
 
 
870
        //only load if AI is active
 
871
        if(bMyRespons)
 
872
        {
 
873
                setEventTrigger(delayedMainInitialize, everySecTr);
 
874
        }
 
875
}
 
876
 
 
877
event delayedMainInitialize(inactive)
 
878
{
 
879
        if(GAME_TIME_IN_SECS >= me)
 
880
        {
 
881
                mainInitialize();
 
882
                setEventTrigger(delayedMainInitialize, inactive);
 
883
        }
 
884
}
 
885
 
 
886
/* Initialization for both AI and human player, to be performed once only */
 
887
function void oneTimeInitialize(bool bAIControlled)
 
888
{
 
889
        local int loadExperienceStatus;
 
890
 
 
891
        /* Decide what debug info to output to the watch window */
 
892
        watchWindowDebug = WATCH_DEBUG_REINF;
 
893
        
 
894
        attackReason = NONE;
 
895
 
 
896
        bigMap = false;
 
897
        if((mapWidth * mapHeight) > (125 * 125))                // > 125*125
 
898
        {
 
899
                bigMap = true;
 
900
        }
 
901
 
 
902
        fixGroups();
 
903
 
 
904
        //assign all dorids to an approriate group
 
905
        unassignedDroids(defendGr, buildGr);
 
906
 
 
907
        // remember base location
 
908
        storeBase();
 
909
 
 
910
        if(bLearn and bAIControlled)
 
911
        {
 
912
                loadExperienceStatus = loadPlayerAIExperience(me);
 
913
 
 
914
                if(DEBUG_MSG)
 
915
                {
 
916
                        if(loadExperienceStatus == 0)           //loaded successfully
 
917
                        {
 
918
                                dbg("Experience loaded successfully for player " & me, me);
 
919
                        }
 
920
                        else if(loadExperienceStatus < 0)
 
921
                        {
 
922
                                dbg("No saved experience found for player " & me, me);
 
923
                        }
 
924
                        else // any error
 
925
                        {
 
926
                                dbg("Error while loading experience for player " & me, me);
 
927
                        }
 
928
                }
 
929
        }
 
930
 
 
931
        /* Initialize ghost structures data */
 
932
        maxGhosts = 120;
 
933
        count = 0;
 
934
        while(count < maxGhosts)
 
935
        {
 
936
                ghostStat[count] = NULLSTRUCTURESTAT;
 
937
                ghostx[count] = -1;
 
938
                ghosty[count] = -1;
 
939
                ghostDead[count] = TRUE;
 
940
                count  = count + 1 ;
 
941
        }
 
942
 
 
943
        groupIterateBucket = (-1);
 
944
 
 
945
        maxBaseEnemies = 22;
 
946
        storeTime = 120;        //in seconds, how long to wait until next store if the same function void can be triggered
 
947
 
 
948
        reinfTime = 0;          //last time we send reinforcements
 
949
        maxReinfTime = 420;     // > 6 min
 
950
 
 
951
        helpTime = 0;           //last time we send reinforcements
 
952
        maxHelpTime = 400;      // > 6 min
 
953
 
 
954
        timeGuardPos = 0;
 
955
        maxTimeGuardPos = 180;  //attackers wait at current pos
 
956
 
 
957
        tTakeOil = 0;
 
958
        tMaxTakeOil = 400;
 
959
 
 
960
        requestHelpTime = 0;
 
961
        maxRequestHelpTime = 180;       //3 min
 
962
 
 
963
        collectTime = 0;
 
964
        maxCollectTime = 150;
 
965
 
 
966
        timeNotifyEnemyInBase = 0;
 
967
        maxTimeNotifyEnemyInBase = 300; //5 mins
 
968
 
 
969
        maxTimeSaveExperience = 120;    //2 mins
 
970
        timeSaveExperience = maxTimeSaveExperience;     //skip first time
 
971
 
 
972
        maxAllyOfferTime = 500;         //>7 min
 
973
 
 
974
        tWaitAlliesDrop = 0;
 
975
        tMaxWaitAlliesDrop = 420;       //7 mins
 
976
 
 
977
        tSyncDrop = 0;
 
978
        tMaxSyncDrop = 300;             //in secs
 
979
 
 
980
        tWaitLoadDrop = 0;
 
981
        tMaxWaitLoadDrop = 150;         //in secs
 
982
 
 
983
        tMaxRequestStatus = 550;        //randomized after every execution of requestStatus()
 
984
 
 
985
        tMaxWaitPlayerReply = 30;       //in secs
 
986
 
 
987
        tLastBaseDefense = 0;   //when started to build a base defense last time
 
988
 
 
989
        dropStartTime = none;
 
990
 
 
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
 
993
 
 
994
        maxTakeOil = 6;         //max take oil reids we can make
 
995
        countTakeOil = 0;
 
996
        numTakeOil = random(maxTakeOil);
 
997
 
 
998
        // For the oil defense routine
 
999
        resetOilDefendCoords();
 
1000
 
 
1001
        maxDefendRepairers = MAX_DEFEND_REPAIRERS;
 
1002
 
 
1003
        defWeight = 18;         //defense weight for distance calculation
 
1004
        weightDistFactor = 250; //factor for derrick weight calculation (divided by distance)
 
1005
 
 
1006
        notifyReadyAttackTime = 0;
 
1007
        maxNotifyReadyAttackTime = 8 + random(12);      //should be different for each AI
 
1008
        bNotifiedReadyAttack = FALSE;
 
1009
 
 
1010
        maxTransporters = 9;
 
1011
 
 
1012
 
 
1013
        count = 0;
 
1014
        while(count < MAX_PLAYERS)
 
1015
        {
 
1016
                storeOilDefTime[count] = 0;
 
1017
                storeBaseDefTime[count] = 0;
 
1018
                allyOfferTime[count] = 0;
 
1019
                lostDroids[count] = 0;
 
1020
                lostStructs[count] = 0;
 
1021
 
 
1022
                count++;
 
1023
        }
 
1024
 
 
1025
        /* Decide how many trucks we need */
 
1026
        updateMaxTrucks();
 
1027
 
 
1028
        /* Total Unit limit */
 
1029
        unitLimit = MAX_UNITS; //getUnitLimit(me);
 
1030
 
 
1031
        /* Set research limits */
 
1032
        maxResearch = getStructureLimit(resFac, me);    //use all we can
 
1033
        fMinResearch = F_MIN_ACTIVE_RES_FAC;
 
1034
 
 
1035
        if(maxResearch <= 0){
 
1036
                dbg("*************maxResearch = 0 *************", me);
 
1037
        }
 
1038
 
 
1039
        //fNumDefaultResearch = fMinResearch;
 
1040
        fNumDefaultResearch = fMinResearch;
 
1041
        fMinResearch = 2.5;
 
1042
 
 
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
 
1050
 
 
1051
        structNoLiveHealth = 9; //When to demolish structure if it's low on hitpoints, in %
 
1052
 
 
1053
        offeredEnemy = none;    //last player an ally offered us to attack
 
1054
 
 
1055
        counterEnemy = none;            //enemy that currently attacked us (used for counter attacks)
 
1056
 
 
1057
        noPower = 70;
 
1058
        lowPower = 200;
 
1059
        highPower = 900;
 
1060
        muchoPower = 2600;
 
1061
        alert = FALSE;          //Emergency
 
1062
        lowMilitary = FALSE;
 
1063
        minFacs = 3;
 
1064
        minResFacs = 2;
 
1065
 
 
1066
        baseSq = 0;                     //base square
 
1067
        baseRange = 0;
 
1068
        aaRange = 0;                    //prim where to build base aa
 
1069
 
 
1070
        oilDefensesRange = OIL_DEFENSES_RANGE;
 
1071
 
 
1072
        // Initialize scout variables
 
1073
        updateMaxScouts();
 
1074
 
 
1075
        maxOilDef = MAX_OIL_DEFENSES_PER_LOC;           /*%!    ID="maxOilDef",
 
1076
                                                MainDesc="max oil defenses",
 
1077
                                                type="asn",             //Assign
 
1078
                                                val="5",
 
1079
                                                ArgDesc="5 (Default)",
 
1080
                                                val="0",
 
1081
                                                ArgDesc="0",
 
1082
                                                val="3",
 
1083
                                                ArgDesc="3",
 
1084
                                                val="7",
 
1085
                                                ArgDesc="7",
 
1086
                                                val="10",
 
1087
                                                ArgDesc="10"    */
 
1088
 
 
1089
        numOilDef = maxOilDef;
 
1090
        minOilDef = MIN_OIL_DEFENSES_PER_LOC;   /*%!    ID="minOilDef",
 
1091
                                                MainDesc="min oil defenses",
 
1092
                                                type="asn",             //Assign
 
1093
                                                val="3",
 
1094
                                                ArgDesc="3 (Default)",
 
1095
                                                val="0",
 
1096
                                                ArgDesc="0",
 
1097
                                                val="5",
 
1098
                                                ArgDesc="5",
 
1099
                                                val="7",
 
1100
                                                ArgDesc="7",
 
1101
                                                val="10",
 
1102
                                                ArgDesc="10"    */
 
1103
 
 
1104
 
 
1105
        minOilRecallPrior = MIN_OIL_RECALL_PRIORITY;            //ignore derricks with lower defend priority
 
1106
 
 
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;
 
1110
 
 
1111
        /* Base defenses */
 
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;
 
1117
 
 
1118
        scoutX = 0;
 
1119
        scoutY = 0;
 
1120
 
 
1121
        phNone                          = 0;
 
1122
        phCollecting            = 1;
 
1123
        phMoveToLoc                     = 2;
 
1124
        phAttackingLoc          = 3;
 
1125
        phSearchingForBase      = 4;
 
1126
        phGuardingPos           = 5;
 
1127
        phLostBase                      = 6;
 
1128
        phRTB                           = 7;
 
1129
        phGettingTech           = 8;
 
1130
        phGettingUnits          = 9;
 
1131
        phWaitAllies            = 10;
 
1132
        phLoadingTransport      = 11;
 
1133
        phSync                          = 12;   //Synchronizing with allies
 
1134
        phSendDrop                      = 13;
 
1135
        phTransportDone         = 14;   //signal for drop phase that transport phase is done successfully
 
1136
 
 
1137
 
 
1138
        stNone                  = 0;
 
1139
        stAttacking             = 1;
 
1140
        stDefendingBase = 2;
 
1141
        stDefendingOil  = 3;
 
1142
        stHelpingAlly   = 4;
 
1143
        stJoiningForces = 5;
 
1144
        stTakingOil             = 6;
 
1145
        stCollecting    = 7;
 
1146
        stDrop                  = 8;
 
1147
        stTransporting  = 9;
 
1148
 
 
1149
 
 
1150
        threatRange = (TILE * 10);
 
1151
 
 
1152
        tBeaconTimeout = 30;    //in secs
 
1153
 
 
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
 
1157
 
 
1158
        initialDefensesFinished = false;        //if finished building anti-rush defenses
 
1159
 
 
1160
        bFirstTimeDefenders = TRUE;
 
1161
 
 
1162
        tech = none;
 
1163
 
 
1164
        lsNone = 0;
 
1165
        lsRecharging = 1;
 
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
 
1173
        lsFiring = 9;
 
1174
 
 
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
 
1180
 
 
1181
        //initialize enemy and ally information
 
1182
        count = 0;
 
1183
        while(count < 8)        //multiPlayerMaxPlayers)
 
1184
        {
 
1185
                /* las sat */
 
1186
                lasSatState[count] = lsNone;    //finished charging etc
 
1187
 
 
1188
                base[count][0] = none;          //x
 
1189
                base[count][1] = none;          //y
 
1190
 
 
1191
                curBase[count][0] = none;               //x
 
1192
                curBase[count][1] = none;               //y
 
1193
 
 
1194
                hasVTOLs[count] = FALSE;
 
1195
 
 
1196
                knowBase[count]= FALSE;
 
1197
                seeBase[count] = FALSE;
 
1198
 
 
1199
                ally[count] = FALSE;
 
1200
                dead[count] = (not playerLoaded(count));        //FALSE;
 
1201
 
 
1202
                if(dead[count])
 
1203
                {
 
1204
                        dbg(getPlayerName(count) & " (" & count & ") is not loaded", me);
 
1205
                }
 
1206
 
 
1207
                killedBase[count] = FALSE;
 
1208
 
 
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)
 
1212
 
 
1213
                tRequestStatus[count] = tMaxRequestStatus + random(700);
 
1214
                tWaitPlayerReply[count] = 0;
 
1215
 
 
1216
                allyState[count] = stNone;
 
1217
                allyPhase[count] = phNone;
 
1218
                allyEnemy[count] = none;
 
1219
 
 
1220
                curHelpX[count] = -1;
 
1221
                curHelpY[count] = -1;
 
1222
 
 
1223
                //init beacon stuff
 
1224
                beaconX[count] = -1;
 
1225
                beaconY[count] = -1;
 
1226
                tBeacon[count] = -1;    //time of the last beacon msg
 
1227
 
 
1228
                //recall players base location
 
1229
                if(bLearn)
 
1230
                {
 
1231
                        if(recallPlayerBaseLoc(me, count, ref x, ref y))        //if this location stored
 
1232
                        {
 
1233
                                if(x <= 0 or y <= 0)
 
1234
                                {
 
1235
                                        MsgBox("x or y <= 0");
 
1236
                                }
 
1237
                                base[count][0] = x;             //x
 
1238
                                base[count][1] = y;             //y
 
1239
 
 
1240
                                curBase[count][0] = x;          //x
 
1241
                                curBase[count][1] = y;          //y
 
1242
 
 
1243
                                curHelpX[count] = curBase[count][0];    //where to go help
 
1244
                                curHelpY[count] = curBase[count][1];
 
1245
 
 
1246
                                knowBase[count] = TRUE;
 
1247
 
 
1248
                                dbg("recalled base location for " & getPlayerName(count), me);
 
1249
                        }
 
1250
                }
 
1251
 
 
1252
                count = count + 1;
 
1253
        }
 
1254
 
 
1255
        base[me][0] = baseX;
 
1256
        base[me][1] = baseY;
 
1257
 
 
1258
        minAllyHelpers = 5;
 
1259
 
 
1260
        numOilAttackers = 5;    //num units required before can start taking oil
 
1261
        minOilAttackers = 3;    //min units required before can start taking oil
 
1262
 
 
1263
        minDefenders = MIN_DEFENDERS;   //min defenders to leave in base
 
1264
 
 
1265
        //attack stuff
 
1266
        numDefenders = 0;       //set in updateNumDefenders() now
 
1267
 
 
1268
        defendCorridor = (5 * 128);     //range which defenders can stay in (baseRange)
 
1269
 
 
1270
        minAttackers = 5;
 
1271
        maxAttackers = 90;      //(unitLimit - maxTrucks - numDefenders) * 3 / 4;
 
1272
        numAttackers = 13 + random(12) + minAttackers;
 
1273
 
 
1274
        attackersIncrease = 4;          // by how many units to increase number of attackers vs a certain player when attack fails
 
1275
 
 
1276
        // set initial number of attackers to use vs. all players
 
1277
        count = 0;
 
1278
        while(count < MAX_PLAYERS)
 
1279
        {
 
1280
                numPlayerAttackers[count] = numAttackers;
 
1281
                count++;
 
1282
        }
 
1283
 
 
1284
        minReinforcements =  5; //13 + random(8);
 
1285
 
 
1286
        //drop stuff
 
1287
        maxDroppers = 40;
 
1288
        if(random(2) == 0)
 
1289
        {
 
1290
                maxDroppers = maxDroppers + 10;
 
1291
        }
 
1292
        medDroppers = max(maxDroppers / 2, minDroppers);
 
1293
        minDroppers = 10;                                       //1 transporter
 
1294
 
 
1295
        maxAllyDroppers = 3 + random(2);                //no more than x players
 
1296
 
 
1297
        //Bunker Buster
 
1298
        minBB = 1;
 
1299
        maxBB = 8;
 
1300
        numBB = maxBB;
 
1301
 
 
1302
        haveBB = FALSE;
 
1303
 
 
1304
        attackedCount = 0;              // how many times was attacked
 
1305
 
 
1306
        //Commanders belong to the defend group on start up
 
1307
        count = 0;
 
1308
        while(count < MAX_COMMANDERS)
 
1309
        {
 
1310
                cmds[count] = NULLOBJECT;
 
1311
                cmdGr[count] = defendGr;
 
1312
                count++;
 
1313
        }
 
1314
 
 
1315
        //adapt for big maps
 
1316
        if(bigMap)
 
1317
        {
 
1318
                minReinforcements = minReinforcements + random(2) + 3;
 
1319
        }
 
1320
        
 
1321
        maxAttackCyborgs = 40;
 
1322
}
 
1323
 
 
1324
function void mainInitialize()
 
1325
{
 
1326
        bRunning = TRUE;        //remember this AI is active
 
1327
 
 
1328
        /* only change name if not human */
 
1329
        if(not isHumanPlayer(me))
 
1330
        {
 
1331
                setPlayerName(me, myName);
 
1332
        }
 
1333
        
 
1334
        reInitialize();         //assign variables
 
1335
        showVersion();
 
1336
        startEnemyScout();
 
1337
        
 
1338
        mainEconomySelftest();
 
1339
        mainMilitarySelftest();
 
1340
 
 
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);
 
1347
 
 
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);
 
1356
 
 
1357
 
 
1358
 
 
1359
        setEventTrigger(objectAttacked, objectAttackedTr);
 
1360
        setEventTrigger(coordinatePhases, coordinatePhasesTr);
 
1361
 
 
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);
 
1376
}
 
1377
 
 
1378
//---------------------------------------------------------
 
1379
//      Initializations
 
1380
//---------------------------------------------------------
 
1381
function void reInitialize()
 
1382
{
 
1383
        //if(IGNORE_MESSAGES)
 
1384
        //{
 
1385
        //      console("multiplayer mode on for Aivolution " & me & " (cooperation off)");
 
1386
        //}
 
1387
 
 
1388
        dbg("ACTIVE!!!", me);
 
1389
        
 
1390
        tPhase = 0;
 
1391
 
 
1392
        unassignedDroids(defendGr, buildGr);            //assign all dorids to an approriate group
 
1393
 
 
1394
        cstr = "empty";
 
1395
        baseDefendObj = NULLOBJECT;
 
1396
 
 
1397
        none = (-1);
 
1398
        off = (-1);
 
1399
 
 
1400
        debugMenuUp = FALSE;
 
1401
 
 
1402
        setPhase(phNone, NONE);
 
1403
 
 
1404
        setState(stNone);
 
1405
        lastState = stNone;
 
1406
 
 
1407
        vsetState(stNone);              //vtol state
 
1408
        lastvState = stNone;
 
1409
 
 
1410
        /* las sat stuff */
 
1411
        lasSatEnemy = none;
 
1412
 
 
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];
 
1417
 
 
1418
        enemy = none;
 
1419
        lastEnemy = none;
 
1420
 
 
1421
        noBaseTargets = TRUE;           //didn't find any targets yet
 
1422
 
 
1423
        resetSendForceCoords();         //where to send the sendAttackGr units
 
1424
 
 
1425
        transportX = none;
 
1426
        transportY = none;
 
1427
 
 
1428
        defendX = none;
 
1429
        defendY = none;
 
1430
 
 
1431
        collectX = none;                //where to gather forces
 
1432
        collectY = none;
 
1433
 
 
1434
        //help ally stuff
 
1435
        allyInThreat = none;            //what ally is in danger now?
 
1436
        sendHelpRange = 18 * TILE;      //range units should stay inside when helping ally in his base
 
1437
 
 
1438
        //dbg(" " & me & ")  Num attackers: " & numAttackers);
 
1439
}
 
1440
 
 
1441
//if we have no trucks and no facs, deactivate events
 
1442
event checkLost(inactive)
 
1443
{
 
1444
        /* any base structures left? */
 
1445
        temp = 0;
 
1446
        while(temp < numBaseStructs)
 
1447
        {
 
1448
                tempStruct = getStructureVis(baseStructs[temp], me, me);
 
1449
                if(tempStruct != NULLOBJECT)
 
1450
                {
 
1451
                        exit;           //yes, have a base structure
 
1452
                }
 
1453
                temp = temp + 1;
 
1454
        }
 
1455
 
 
1456
        // FIXME: might consider reactivating
 
1457
        //if((getDroidCount(me) == 0) and
 
1458
        //      not (multiPlayerGameType == SKIRMISH and multiPlayerAlliancesType == ALLIANCES_TEAMS))
 
1459
 
 
1460
        if(getDroidCount(me) == 0)
 
1461
        {
 
1462
                taunt(NONE, TAUNT_GAME_LOSS, 60);
 
1463
                shutDown();
 
1464
        }
 
1465
}
 
1466
 
 
1467
/*
 
1468
 * Deactivete this AI
 
1469
  */
 
1470
function void shutDown()
 
1471
{
 
1472
        bRunning = FALSE;       //remember this AI is inactive
 
1473
 
 
1474
        notifyPlayerDead(me);
 
1475
 
 
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);
 
1490
 
 
1491
 
 
1492
        setEventTrigger(objectAttacked, inactive);
 
1493
        setEventTrigger(coordinatePhases, inactive);
 
1494
 
 
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);
 
1508
 
 
1509
        dbg("DEACTIVATED SCRIPT!!!!!!!!!!!!!!!!!!", me);
 
1510
}
 
1511
 
 
1512
//---------------------------------------------------------
 
1513
//      Deal with basic stuff
 
1514
//---------------------------------------------------------
 
1515
event mainEconomySelftest(inactive)
 
1516
{
 
1517
        baseDetails();
 
1518
        updateBeacons();
 
1519
 
 
1520
        doEconomyMisc();        /* should be done before any other economy tasks */
 
1521
        doEconomy();
 
1522
}
 
1523
 
 
1524
event mainMilitarySelftest(inactive)
 
1525
{
 
1526
        doMilitaryMisc();       /* should be done before any other military tasks */
 
1527
        doMilitary();
 
1528
}
 
1529
 
 
1530
//---------------------------------------------------------
 
1531
//      Deal with basic military stuff
 
1532
//---------------------------------------------------------
 
1533
function void doMilitary()
 
1534
{
 
1535
        updateMaxScouts();
 
1536
 
 
1537
        /* build anti-rush defenses */
 
1538
        if(!initialDefensesFinished)
 
1539
        {
 
1540
                //dbg("buildInitialDefenses() - doMilitary()", me);
 
1541
                buildInitialDefenses(FALSE);
 
1542
        }
 
1543
 
 
1544
        if(!initialDefensesFinished and (gameTime >= 9000))     //max 15 mins
 
1545
        {
 
1546
                stopInitialDefenses();  //enough
 
1547
        }
 
1548
 
 
1549
        /* manage helping ally process */
 
1550
        if(state == stHelpingAlly)              //did we choose to defend him?
 
1551
        {
 
1552
                /* if checkAllyThreat detected that no enemies left and were helping ally, retreat back to base */
 
1553
                //if(defendingAlly)
 
1554
                //{
 
1555
 
 
1556
                if(helpTime > 0)        //help didn't timeout yet
 
1557
                {
 
1558
                        manageHelpAlly();
 
1559
                }
 
1560
                else
 
1561
                {
 
1562
                        dbg("DEFEND ALLY: time out, rtb!!!!!!!!!!!!!!!!!", me);
 
1563
                        notifyAllies(getPlayerName(enemy) & ", retreating for now, call me if you need me again" , false);      //allyInThreat
 
1564
                        stopAllyDefense();
 
1565
                }
 
1566
        }
 
1567
        else if(defendingOil())
 
1568
        {
 
1569
                if(tState >= maxStateTime)
 
1570
                {
 
1571
                        stopDefendingOil();
 
1572
                }
 
1573
        }
 
1574
 
 
1575
        /* build units */
 
1576
        if((tech == techAir) or (playerPower(me) > muchoPower))
 
1577
        {
 
1578
                buildVTOLs();
 
1579
        }
 
1580
 
 
1581
        if((tech == techTanks) or (playerPower(me) > muchoPower))
 
1582
        {
 
1583
                // if(canBuildTanks())
 
1584
                // {
 
1585
                        buildTanks();
 
1586
                // }
 
1587
        }
 
1588
 
 
1589
 
 
1590
        /* Build base defenses */
 
1591
        if( ((GAME_TIME_IN_SECS - tLastBaseDefense) >  (SECOND * 30)) or defendingBase())       //wait at least 30 secs
 
1592
        {
 
1593
                // if(not((playerPower(me) <= lowPower) and defendingBase()))           //build defenses only if not low on power and not defendingBase
 
1594
                // {
 
1595
                        buildBaseDefenses();
 
1596
                // }
 
1597
        }
 
1598
 
 
1599
        /* build AA defenses */
 
1600
/*      if((!alert and !defendingBase()) or (playerPower(me) > highPower))
 
1601
        {
 
1602
                buildAA();
 
1603
        } */
 
1604
 
 
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
 
1607
        {
 
1608
                gatewayDefenses();
 
1609
        }
 
1610
 
 
1611
        /* check if tired attacking an enemy and want to try to drop him instead */
 
1612
        if(attackingEnemyBase(enemy))
 
1613
        {
 
1614
                if((tempReinfCount[enemy] >= maxReinfCount) and (groupSizeCmds(attackGr,true,false,true) <= 1))         //if we attacked too many times and current attack failed too
 
1615
                {
 
1616
                        result2 = random(3);
 
1617
 
 
1618
                        /* do drop */
 
1619
/*
 
1620
                        if(result2 == 1)
 
1621
                        {
 
1622
                                result = numResearchLeft(me, resUnitTransporter);
 
1623
                                if(result <= 3)         //won't take too long
 
1624
                                {
 
1625
                                        dbg("ATTACKED ENEMY TOO MANY TIMES: drop instead!!!", me);
 
1626
 
 
1627
                                        result = enemy;
 
1628
 
 
1629
                                        pauseState();
 
1630
 
 
1631
                                        enemy = result;         //same enemy
 
1632
                                        requestPrepareDrop();
 
1633
                                        startDropPhase();
 
1634
                                }
 
1635
                        }
 
1636
*/
 
1637
                        /* wipe out some derricks */
 
1638
                        if(result2 == 0)
 
1639
                        {
 
1640
                                // make sure we have enough units
 
1641
                                if(canStartTakingOil())
 
1642
                                {
 
1643
                                        structure = findEnemyDerrick(enemy);
 
1644
 
 
1645
                                        if(structure != NULLOBJECT)
 
1646
                                        {
 
1647
                                                dbg("ATTACKED ENEMY TOO MANY TIMES: wipeout oil instead!!!", me);
 
1648
                                                pauseState();           //resume when done hunting enemy derricks
 
1649
 
 
1650
                                                startTakingOil(structure);
 
1651
                                                notifyTakeOil(structure.player, structure.x, structure.y);
 
1652
                                        }
 
1653
                                }
 
1654
                        }
 
1655
                }
 
1656
        }
 
1657
 
 
1658
        /* see if we want to drop someone ... just out of fun */
 
1659
//todo: fix
 
1660
/*
 
1661
        if((state == stNone) and (random(10) > 6))
 
1662
        {
 
1663
                if((notifyReadyAttackTime <= 0) and (bNotifiedReadyAttack == FALSE))    //make sure not about to start attack
 
1664
                {
 
1665
                        //result = enoughDroppers();
 
1666
                        if(enoughDroppers())
 
1667
                        {
 
1668
                                result = numResearchLeft(me, resUnitTransporter);
 
1669
                                if(result <= 6)         //won't take too long
 
1670
                                {
 
1671
                                        result = chooseEnemyToDrop();
 
1672
                                        if(result != none)              //found any enemy targets?
 
1673
                                        {
 
1674
                                                enemy = result;
 
1675
                                                requestPrepareDrop();
 
1676
                                                startDropPhase();
 
1677
                                        }
 
1678
                                }
 
1679
                        }
 
1680
                }
 
1681
        }
 
1682
*/
 
1683
 
 
1684
        /* build transporters if gonna drop */
 
1685
/*
 
1686
        if((state == stDrop) and researchFinished(resUnitTransporter, me))      //gonna drop and got unit transporter tech
 
1687
        {
 
1688
                //temp = enoughTransporters();
 
1689
                if((not alert) and (not enoughTransporters()))
 
1690
                {
 
1691
                        buildTransporters();
 
1692
                }
 
1693
        }
 
1694
*/
 
1695
        /* see if we want to blow up some enemy derricks */
 
1696
        if(countTakeOil < numTakeOil)   //don't do too often
 
1697
        {
 
1698
                if((state == stNone) and (notifyReadyAttackTime <= 0) and (bNotifiedReadyAttack == FALSE))      //not busy and not about to start attack
 
1699
                {
 
1700
                        result = numAvailableAttackers();
 
1701
                        if((random(10) < 7) and (result >= numOilAttackers))
 
1702
                        {
 
1703
                                structure = findEnemyDerrick(none);     //any player
 
1704
                                //structure = retStruct;
 
1705
 
 
1706
                                if(structure != NULLOBJECT)
 
1707
                                {
 
1708
                                        startTakingOil(structure);
 
1709
                                        notifyTakeOil(structure.player, structure.x, structure.y);
 
1710
                                }
 
1711
                        }
 
1712
                }
 
1713
        }
 
1714
 
 
1715
 
 
1716
        /* start land attack */
 
1717
        if(state == stNone)
 
1718
        {
 
1719
                //result = canTheoreticallyStartAttack();       //enough units in total
 
1720
/*              if(canTheoreticallyStartAttack())                                       //we can start
 
1721
                { */
 
1722
                        if(noBaseTargets)       //if couldn't find any enemy main bases
 
1723
                        {
 
1724
                                findAlternateTarget();  //find any other visible target
 
1725
                        }
 
1726
 
 
1727
                        if(not noBaseTargets)   //notify only if can actually start attacking someone
 
1728
                        {
 
1729
                                if(bNotifiedReadyAttack or (not playerInAlliance(me)))  //already notified or no allies
 
1730
                                {
 
1731
                                        result = chooseEnemy(); //should be able to find enemy if (not noBaseTargets)
 
1732
                                        if(result != none)              //found any enemy targets?
 
1733
                                        {
 
1734
                                                if(canStartAttack(result))
 
1735
                                                {
 
1736
                                                        //enemy = result;
 
1737
                                                        startEnemyBaseAttack(result);
 
1738
                                                        requestStartAttack(result, curBase[result][0], curBase[result][1]);
 
1739
                                                }
 
1740
                                        }
 
1741
                                        else
 
1742
                                        {
 
1743
                                                dbg("ATTACK: failed to find an enemy", me);
 
1744
                                        }
 
1745
                                }
 
1746
                                else if(notifyReadyAttackTime <= 0)     //haven't started countdown already
 
1747
                                {
 
1748
                                        if(haveTheoreticallyMinAttackers(false))
 
1749
                                        {
 
1750
                                                notifyReadyAttack();            //notify allies and wait for orders
 
1751
                                        }
 
1752
                                }
 
1753
                        }
 
1754
                /* } */
 
1755
        }
 
1756
 
 
1757
        /* Continue military actions if we are attacking */
 
1758
        if(state == stAttacking)
 
1759
        {
 
1760
                doAttack();
 
1761
                checkStopAttack();
 
1762
        }
 
1763
 
 
1764
        /* remind allies we are in trouble */
 
1765
        if(defendingBase())
 
1766
        {
 
1767
                if(canRequestHelp())
 
1768
                {
 
1769
                        requestHelp(baseX, baseY);      //do once in a while
 
1770
                }
 
1771
        }
 
1772
 
 
1773
        /* use lasSat */
 
1774
        updateLasSat();
 
1775
}
 
1776
 
 
1777
function void doMilitaryMisc()
 
1778
{
 
1779
        militarySelftest();             //misc stuff
 
1780
 
 
1781
        /* set tech branch */
 
1782
        if((tech == none) and (gameTime > 100))
 
1783
        {
 
1784
                setTechBranch();        // decide what we will research
 
1785
        }
 
1786
 
 
1787
        /* create alliances */
 
1788
        if(not alliancesLocked() and (gameTime > 100))
 
1789
        {
 
1790
                if(numAllies(me) < (multiPlayerMaxPlayers / 2)) //not allied to too many players already
 
1791
                {
 
1792
                        if(random(5) == 1)
 
1793
                        {
 
1794
                                makeAlliances();
 
1795
                        }
 
1796
                }
 
1797
        }
 
1798
 
 
1799
        /* Make sure we are not under heavy attack */
 
1800
        if(gameTime > 1800)             //3 mins, in case bases are close to each other
 
1801
        {
 
1802
                checkBaseThreat();      //set or cancel base threat alert
 
1803
        }
 
1804
 
 
1805
 
 
1806
        /* find enemies and allies and their bases (targets) */
 
1807
        updateMilitaryStatus();
 
1808
 
 
1809
        /* if we haven't heard anything from our allies for a long time, ask what they are doing */
 
1810
        checkRequestStatus();
 
1811
 
 
1812
        /* Update minimum number of defender units to use */
 
1813
        updateNumDefenders();
 
1814
}
 
1815
 
 
1816
//---------------------------------------------------------
 
1817
//      Deal with basic economy stuff
 
1818
//---------------------------------------------------------
 
1819
function void doEconomyMisc()
 
1820
{
 
1821
        updateMaxTrucks();
 
1822
}
 
1823
 
 
1824
/* Returns true if it's the beginning of the game */
 
1825
function bool legoPhase()
 
1826
{
 
1827
        if(GAME_TIME_IN_SECS <= LEGO_PHASE_LEN){
 
1828
                return true;
 
1829
        }
 
1830
 
 
1831
        return false;
 
1832
}
 
1833
 
 
1834
/* Returns true the game has just started */
 
1835
function bool startupPhase()
 
1836
{
 
1837
        if(GAME_TIME_IN_SECS <= STARTUP_PHASE_LEN){
 
1838
                return true;
 
1839
        }
 
1840
 
 
1841
        return false;
 
1842
}
 
1843
 
 
1844
function bool haveMinTrucks()
 
1845
{
 
1846
        if(groupSizeCmds(buildGr,true,false,true) >= minTrucks){
 
1847
                return true;
 
1848
        }
 
1849
 
 
1850
        return false;
 
1851
}
 
1852
 
 
1853
// have trucks + num building
 
1854
function bool gettingMinTrucks()
 
1855
{
 
1856
        if((groupSizeCmds(buildGr,true,false,true) +
 
1857
                numBuildersInProduction(me)) >= minTrucks)
 
1858
        {
 
1859
                return true;
 
1860
        }
 
1861
 
 
1862
        return false;
 
1863
}
 
1864
 
 
1865
function void buildMoreOil()
 
1866
{
 
1867
        local   int                     _maxRange;
 
1868
        local   DROID           _truck;
 
1869
        local   FEATURE         _oil;
 
1870
 
 
1871
        _maxRange = TILE * 50;
 
1872
 
 
1873
        if(numStatBusy(derrick, true) < maxBuildOilTrucks)
 
1874
        {
 
1875
                _oil = findBestOilToBuildOn(-1, -1, -1);        //just find the best oil on the map
 
1876
                if(_oil != NULLOBJECT)
 
1877
                {
 
1878
                        _truck = closestIdleTruck(_oil.x, _oil.y);
 
1879
 
 
1880
                        if(_truck != NULLOBJECT)
 
1881
                        {
 
1882
                                orderDroidStatsLoc(_truck, DORDER_BUILD, derrick, _oil.x, _oil.y);
 
1883
                        }
 
1884
                }
 
1885
        }
 
1886
}
 
1887
 
 
1888
function void doEconomy()
 
1889
{
 
1890
        local   int             _numBuilders;
 
1891
        local   bool    _bBaseHasHighPriority;
 
1892
 
 
1893
        economySelftest();
 
1894
 
 
1895
        /* build AA defenses */
 
1896
        if(!defendingBase() or (playerPower(me) > muchoPower))
 
1897
        {
 
1898
                buildAA();
 
1899
        }
 
1900
 
 
1901
        //dbg(" " & me & ")  doEconomy");
 
1902
        if(DEBUG_POWER and (playerPower(me) <= lowPower)){
 
1903
                addPower(highPower - 300, me);
 
1904
        }
 
1905
 
 
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())
 
1908
        {
 
1909
                buildMoreOil();
 
1910
 
 
1911
                if(startupPhase()){
 
1912
                        dbg(numVisibleOilResInRange(-1,-1,-1) & " oil resources are visible", me);
 
1913
                }
 
1914
        }
 
1915
 
 
1916
        closerTruck();
 
1917
 
 
1918
        //dbg(" " & me & ")  buildTrucks");
 
1919
 
 
1920
        if(needTrucks()){
 
1921
                // dbg("NEED TRUCKS", me);
 
1922
 
 
1923
                buildTrucks();
 
1924
        }
 
1925
        // else
 
1926
        // {
 
1927
                // dbg("DON'T NEED TRUCKS", me);
 
1928
        // }
 
1929
                //dbg(" " & me & ")  checkPowerGen");
 
1930
 
 
1931
        //Make sure we have all vital base structures (factory, power getm etc)
 
1932
        if(!haveMinimalStructures()){
 
1933
                checkMinimalStructures();
 
1934
        }
 
1935
 
 
1936
        checkPowerGen();
 
1937
 
 
1938
        //dbg(" " & me & ")  repair");
 
1939
 
 
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
 
1943
        {
 
1944
                repairStructures();
 
1945
                finishStructures();
 
1946
        }
 
1947
 
 
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()) )
 
1951
        {
 
1952
                upgradeFac();
 
1953
        }
 
1954
 
 
1955
        // upgrade power generators
 
1956
        upgradePow();
 
1957
 
 
1958
        if(state == stDrop)             //give it a higher priority if going to drop
 
1959
        {
 
1960
                upgradeVtolFac();
 
1961
        }
 
1962
 
 
1963
        //dbg(" " & me & ")  buildOil");
 
1964
 
 
1965
        /* Build derricks */
 
1966
        if(not structureLimitReached(derrick, me))      //don't try if can't
 
1967
        {
 
1968
                buildOil( defendingBase() );    //don't go away from base if in danger and low on trucks
 
1969
        }
 
1970
 
 
1971
        /* Build factories and research facilities */
 
1972
        buildBaseStructs();
 
1973
 
 
1974
        if(!_bBaseHasHighPriority and (haveMinTrucks() or !needTrucks()) )
 
1975
        {
 
1976
                repairStructures();
 
1977
                finishStructures();
 
1978
        }
 
1979
 
 
1980
        if(!alert and (state != stDrop)){
 
1981
                upgradeVtolFac();
 
1982
        }
 
1983
 
 
1984
        if(not alert){
 
1985
                upgradeResFac();
 
1986
        }
 
1987
                //dbg(" " & me & ")  END doEconomy()");
 
1988
}
 
1989
 
 
1990
function void economySelftest()
 
1991
{
 
1992
        if(gameTime < 30)
 
1993
                exit;   //wait until power is initialized
 
1994
 
 
1995
        bResult = alert;                //remember last state
 
1996
 
 
1997
        /* if base is in danger ignore anything else */
 
1998
        if((playerPower(me) <= highPower) and (groupSizeCmds(defendGr,true,false,true) < numDefenders))
 
1999
        {
 
2000
                if(gameTime > 4200)
 
2001
                {
 
2002
                        if(not bResult){dbg("economy - not enough defenders       (!!!!!)", me);}
 
2003
 
 
2004
                        alert = TRUE;
 
2005
                        lowMilitary = TRUE;
 
2006
                }
 
2007
        }
 
2008
 
 
2009
        /* restet lowMilitary */
 
2010
        if(lowMilitary)
 
2011
        {
 
2012
                if(groupSizeCmds(defendGr,true,false,true) >= numDefenders)
 
2013
                {
 
2014
                        lowMilitary = FALSE;            //reset here
 
2015
                        alert = FALSE;
 
2016
                        dbg("lowMilitary back to normal (!!!!!)", me);
 
2017
                }
 
2018
        }
 
2019
 
 
2020
        if(lowMilitary)
 
2021
                exit;           //don't reset alert until lowMilitary is back to normal
 
2022
 
 
2023
        /* set numOilDef */
 
2024
        if(playerPower(me) >= lowPower)
 
2025
        {
 
2026
                numOilDef = maxOilDef;
 
2027
                numBaseDef = maxBaseDef;
 
2028
        }
 
2029
        else if(playerPower(me) <= noPower)             //no power
 
2030
        {
 
2031
                numOilDef = minOilDef;
 
2032
                numBaseDef = minBaseDef;
 
2033
        }
 
2034
 
 
2035
        /* set alert and lowMilitary */
 
2036
        if(playerPower(me) >= lowPower)                 //high power, back to normal
 
2037
        {
 
2038
                alert = FALSE;
 
2039
        }
 
2040
        else if(playerPower(me) <= noPower)             //no power
 
2041
        {
 
2042
                if(!haveMinTrucks() and needTrucks())
 
2043
                {
 
2044
                        alert = TRUE;
 
2045
                        if(not bResult){dbg("economy low on trucks       (!!!!!)", me);}
 
2046
                }
 
2047
 
 
2048
                if(not alert)
 
2049
                {
 
2050
                        if((getNumStructures(fac,me) < minFacs) or (getNumStructures(powGen,me) == 0))
 
2051
                        {
 
2052
                                alert = TRUE;
 
2053
                                if(not bResult){dbg("economy low on vital structures       (!!!!!)", me);}
 
2054
                        }
 
2055
                }
 
2056
 
 
2057
                //if(not alert)
 
2058
                //{
 
2059
                        if((gameTime > 4200) and (groupSizeCmds(defendGr,true,false,true) < numDefenders))
 
2060
                        {
 
2061
                                alert = TRUE;
 
2062
                                lowMilitary = TRUE;
 
2063
                                if(not bResult){dbg("economy - not enough defenders       (!!!!!)", me);}
 
2064
                        }
 
2065
                //}
 
2066
        }
 
2067
 
 
2068
        if(bResult and (not alert))
 
2069
        {
 
2070
                dbg("Economy back to normal         !!!!!!", me);
 
2071
        }
 
2072
}
 
2073
 
 
2074
function void updateMaxTrucks()
 
2075
{
 
2076
        local   int             _numHaveTrucks;
 
2077
 
 
2078
        minTrucks = 6;                          //Critical number
 
2079
 
 
2080
        maxTrucks = 8;
 
2081
 
 
2082
        // we need more at startup
 
2083
        if(legoPhase()){
 
2084
                maxTrucks = maxTrucks + 4;
 
2085
        }
 
2086
 
 
2087
        // we need more trucks if there's a lot of defences to build
 
2088
        if(getBaseDefendLocCount() > 0){
 
2089
                maxTrucks++;
 
2090
        }
 
2091
 
 
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;
 
2095
 
 
2096
        if(bigMap)
 
2097
        {
 
2098
                maxTrucks = maxTrucks + 3;
 
2099
                minTrucks = minTrucks + 1;
 
2100
        }
 
2101
 
 
2102
        _numHaveTrucks = groupSizeCmds(buildGr,true,false,true);
 
2103
 
 
2104
        // decide how many trucks are allowed to be building derricks at a time (used to be 7)
 
2105
        maxBuildOilTrucks = (_numHaveTrucks + 1) / 2;
 
2106
 
 
2107
        // max trucks building defenses at a time
 
2108
        if(!haveMinTrucks()){
 
2109
                maxBaseDefenseTrucks = 1;
 
2110
                maxOilDefenseTrucks = max(1,_numHaveTrucks / 3);
 
2111
        }else{
 
2112
                maxBaseDefenseTrucks = max(2, _numHaveTrucks / 4);
 
2113
                maxOilDefenseTrucks = max(1, (int)((float)_numHaveTrucks / 1.9));
 
2114
        }
 
2115
 
 
2116
        if(bigMap)
 
2117
        {
 
2118
                if(haveMinTrucks()){
 
2119
                        maxOilDefenseTrucks++;
 
2120
                }
 
2121
        }
 
2122
 
 
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;
 
2127
        }
 
2128
}
 
2129
 
 
2130
function void showVersion()
 
2131
{
 
2132
        dbg("Aivolution AI active for player " & me & " (version " & sVer & ")", me);   //show to the local player
 
2133
}
 
2134
 
 
2135
function void storeBase()
 
2136
{
 
2137
        local   STRUCTURE       _structure;
 
2138
        local   DROID           _truck;
 
2139
        local   bool            _bHaveBaseStructs;
 
2140
        local   int                     _index,_baseX,_baseY,_numBaseStructs,_bucket;
 
2141
 
 
2142
 
 
2143
        _bHaveBaseStructs = FALSE;
 
2144
 
 
2145
        //Go through all structures
 
2146
        _index = 0;
 
2147
        _numBaseStructs = 0;
 
2148
        _baseX = 0;
 
2149
        _baseY = 0;
 
2150
        while(_index < numBaseStructs)
 
2151
        {
 
2152
                initEnumStruct(FALSE,baseStructs[_index],me,me);
 
2153
                _structure = enumStruct();
 
2154
                while(_structure != NULLOBJECT)
 
2155
                {
 
2156
                        _baseX = _baseX + _structure.x / TILE;
 
2157
                        _baseY = _baseY + _structure.y / TILE;
 
2158
 
 
2159
                        _numBaseStructs++;
 
2160
                        _structure = enumStruct();
 
2161
                }
 
2162
                _index++;
 
2163
        }
 
2164
 
 
2165
        if(_numBaseStructs > 0)
 
2166
        {
 
2167
                baseX = (_baseX / _numBaseStructs) * TILE;
 
2168
                baseY = (_baseY / _numBaseStructs) * TILE;
 
2169
        }
 
2170
        else
 
2171
        {
 
2172
                _bucket = initIterateGroupCmd(buildGr,true,false,true);         // find idle droids in build group.
 
2173
                _truck = iterateGroupCmd(buildGr, _bucket);
 
2174
 
 
2175
                if(_truck != NULLOBJECT){
 
2176
                        baseX = _truck.x;
 
2177
                        baseY = _truck.y;
 
2178
                }else{
 
2179
                        baseX = (TILE * mapWidth) / 2;
 
2180
                        baseY = (TILE * mapHeight) / 2;
 
2181
 
 
2182
                        console("Couldn't find base location for " & getPlayerName(me));
 
2183
                }
 
2184
        }
 
2185
}
 
2186
 
 
2187
function void fixGroups()
 
2188
{
 
2189
        InitEnumDroids(me,me);
 
2190
        tempDroid = EnumDroid();
 
2191
        while(tempDroid != NULLOBJECT)
 
2192
        {
 
2193
                droidLeaveGroup(tempDroid);
 
2194
                tempDroid = EnumDroid();
 
2195
        }
 
2196
}
 
2197
 
 
2198
event diffMod(diffModTr)
 
2199
{
 
2200
        if(not isHumanPlayer(me) and modifierOn)
 
2201
        {
 
2202
                skDifficultyModifier(me);
 
2203
        }
 
2204
}
 
2205
 
 
2206
function void goRTB()
 
2207
{
 
2208
        local int _x, _y,_index;
 
2209
 
 
2210
        dbg("Going back to base", me);
 
2211
 
 
2212
        ASSERT(sendForceX != none and sendForceY != none, "goRTB: sendForceX < 0", me);
 
2213
 
 
2214
        groupAddGroupCmd(sendAttackGr, attackGr);
 
2215
 
 
2216
        // send to the base perimeter
 
2217
        if(sendForceX != baseX and sendForceY != baseY)         // can be equal if were send to defend the base
 
2218
        {
 
2219
                _x = sendForceX;
 
2220
                _y = sendForceY;
 
2221
        }
 
2222
        else
 
2223
        {
 
2224
                // send to last defend location
 
2225
                if(defendX != NONE and defendY != NONE)
 
2226
                {
 
2227
                        _x = defendX;
 
2228
                        _y = defendY;
 
2229
                }
 
2230
        }
 
2231
 
 
2232
        circlePerimPoint(baseX, baseY, ref _x, ref _y, baseRange);      //move locations to the derrick perimeter
 
2233
 
 
2234
        // find a place with enough space
 
2235
        pickStructLocation(powGen, ref _x, ref _y, me);
 
2236
 
 
2237
        //Order droids and commanders
 
2238
        orderGroupLocCmd(sendAttackGr, DORDER_MOVE, _x, _y);
 
2239
 
 
2240
        //Move all droids and commanders to defend group
 
2241
        groupAddGroupCmd(defendGr, sendAttackGr);
 
2242
}
 
2243
 
 
2244
event buildStructureModel(inactive)
 
2245
{
 
2246
        local   STRUCTURE               _structure;
 
2247
        local   int                             i,j;
 
2248
 
 
2249
        i = 0;
 
2250
 
 
2251
        initEnumStruct(TRUE,wall,me,me);
 
2252
        _structure = enumStruct();
 
2253
        while((_structure != NULLOBJECT) and (i < maxGhosts))
 
2254
        {
 
2255
                /* Remember initial walls and defenses */
 
2256
                if((_structure.stat == wall) or (_structure.stattype == REF_DEFENSE))
 
2257
                {
 
2258
                        ghostStat[i] = _structure.stat;
 
2259
                        ghostx[i] = _structure.x;
 
2260
                        ghosty[i] = _structure.y;
 
2261
                        ghostDead[i] = FALSE;
 
2262
                        i = i + 1;
 
2263
                }
 
2264
 
 
2265
                _structure = enumStruct();
 
2266
        }
 
2267
 
 
2268
        dbg("Model saved (" & i  & ")", me);
 
2269
}
 
2270
 
 
2271
function void updateBeacons()
 
2272
{
 
2273
        count = 0;
 
2274
        while(count < 8)
 
2275
        {
 
2276
                if(beaconTimeout(count))        //last beacon timed out
 
2277
                {
 
2278
                        dbg("beacon timeout for " & count, me);
 
2279
 
 
2280
                        tBeacon[count] = -1;
 
2281
 
 
2282
                        beaconX[count] = -1;
 
2283
                        beaconY[count] = -1;
 
2284
 
 
2285
                        curHelpX[count] = curBase[count][0];    //restore base and help location
 
2286
                        curHelpY[count] = curBase[count][1];
 
2287
                }
 
2288
                count = count + 1;
 
2289
        }
 
2290
}
 
2291
 
 
2292
//---------------------------------------------------------
 
2293
//      Base size
 
2294
//---------------------------------------------------------
 
2295
function void baseDetails()
 
2296
{
 
2297
        maxy = 0; maxx = 0;
 
2298
        miny = (mapHeight*128); minx = (mapWidth*128);
 
2299
 
 
2300
        baseRange = 1;  //avoid possible div by 0
 
2301
        aaRange = 1;
 
2302
 
 
2303
        count = 0;
 
2304
        while(count < numBaseStructs)
 
2305
        {
 
2306
                initEnumStruct(FALSE,baseStructs[count],me,me);
 
2307
                structure = enumStruct();
 
2308
                while(structure != NULLOBJECT)
 
2309
                {
 
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;}
 
2314
 
 
2315
                        result = distBetweenTwoPoints(baseX, baseY, structure.x, structure.y);
 
2316
                        if(result > baseRange){baseRange = result;}
 
2317
 
 
2318
                        structure = enumStruct();
 
2319
                }
 
2320
                count = count + 1;
 
2321
        }
 
2322
 
 
2323
        result = 7 * 128;
 
2324
 
 
2325
        minx = minx - result; maxx = maxx + result;
 
2326
        miny = miny - result; maxy = maxy + result;
 
2327
 
 
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;}
 
2332
 
 
2333
        aaRange = baseRange + 128;              //between the base and baseRange
 
2334
 
 
2335
        baseRange = baseRange + (5 * 128);
 
2336
 
 
2337
 
 
2338
        //baseSq = ((maxx - minx) / 128) * ((maxy - miny) / 128);
 
2339
}
 
2340
 
 
2341
//---------------------------------------------------------
 
2342
//      Prepare scouting routines
 
2343
//---------------------------------------------------------
 
2344
function void startEnemyScout()
 
2345
{
 
2346
        bEnemyScoutHor  = TRUE;
 
2347
 
 
2348
        //only one of these is actually used, depending on bEnemyScoutHor
 
2349
        bEnemyScoutToBottom = TRUE;
 
2350
        bEnemyScoutToRight = TRUE;
 
2351
 
 
2352
        getClosestCorner(baseX, baseY);                 //find corner we are closest to
 
2353
        x = retInt;
 
2354
        y = retInt2;
 
2355
 
 
2356
        if(not mapRevealedInRange(x,y,enemyScoutRange,me))
 
2357
        {
 
2358
                //make this the first place scouts will visit
 
2359
                enemyScoutX = x;
 
2360
                enemyScoutY = y;
 
2361
                //dbg("can visit corner", me);
 
2362
        }
 
2363
        else
 
2364
        {
 
2365
                dbg("can't visit corner", me);
 
2366
        }
 
2367
 
 
2368
        setEventTrigger(scoutForEnemy, scoutForEnemyTr);
 
2369
}
 
2370
 
 
2371
function bool finishDefenses(DROID _truck, int _repairx, int _repairy, int _maxRange)
 
2372
{
 
2373
        local   int                     _def;
 
2374
        local   STRUCTURE       _defense;
 
2375
        local   bool            _bOK;
 
2376
 
 
2377
        _def = numDef - 1;
 
2378
        while(!_bOK and (_def >= 0))
 
2379
        {
 
2380
                initEnumStruct(FALSE,def[_def],me,me);
 
2381
                _defense = enumStruct();
 
2382
                while(!_bOK and (_defense != NULLOBJECT))
 
2383
                {
 
2384
                        if(!structureComplete(_defense))
 
2385
                        {
 
2386
                                if(distBetweenTwoPoints(_repairx, _repairy, _defense.x, _defense.y) < _maxRange)
 
2387
                                {
 
2388
                                        if(!buildingSiteBlocked(_truck, _maxRange, _defense.x, _defense.y, true))
 
2389
                                        {
 
2390
                                                orderDroidStatsLoc(_truck, DORDER_BUILD, def[_def], _defense.x, _defense.y);
 
2391
                                                dbg("finishing defense at " & (_defense.x / TILE) & "-" & (_defense.y / TILE), me);
 
2392
                                                return true;
 
2393
                                        }
 
2394
                                }
 
2395
                        }
 
2396
                        _defense = enumStruct();
 
2397
                }
 
2398
 
 
2399
                _def--;
 
2400
        }
 
2401
 
 
2402
        return false;
 
2403
}
 
2404
 
 
2405
function void finishStructures()
 
2406
{
 
2407
        initIterateGroupB(buildGr, me);
 
2408
        droid = iterateGroupB(buildGr, me);
 
2409
        while(droid != NULLOBJECT)
 
2410
        {
 
2411
                if((droid.order == DORDER_NONE) or (droid.order == DORDER_RTB))
 
2412
                {
 
2413
                        //Check all base structures first
 
2414
                        //-------------------------------------
 
2415
                        result = 99999;
 
2416
                        structure2 = NULLOBJECT;
 
2417
 
 
2418
                        count = 0;
 
2419
                        while(count < numBaseStructs)
 
2420
                        {
 
2421
                                initEnumStruct(FALSE,baseStructs[count],me,me);
 
2422
                                structure = enumStruct();
 
2423
                                while(structure != NULLOBJECT)
 
2424
                                {
 
2425
                                        if(not structureComplete(structure))
 
2426
                                        {
 
2427
                                                //Find closest one
 
2428
                                                result3 = distBetweenTwoPoints(baseX, baseY, structure.x, structure.y);
 
2429
                                                if(result3 < result)
 
2430
                                                {
 
2431
                                                        //Make sure no one's building already
 
2432
                                                        //result2 = buildingSiteBlocked(NULLOBJECT, 128, structure.x, structure.y);
 
2433
                                                        //if(result2 == 0)
 
2434
                                                        if(not buildingSiteBlocked(NULLOBJECT, 128, structure.x, structure.y, false))
 
2435
                                                        {
 
2436
                                                                structure2 = structure;
 
2437
                                                                result = result3;
 
2438
                                                        }
 
2439
                                                }
 
2440
                                        }
 
2441
                                        structure = enumStruct();
 
2442
                                }
 
2443
                                count = count + 1;
 
2444
                        }
 
2445
 
 
2446
                        //Check all
 
2447
                        //------------------------------
 
2448
                        if(structure2 == NULLOBJECT)
 
2449
                        {
 
2450
                                initEnumStruct(TRUE,fac,me,me); //all
 
2451
                                structure = enumStruct();
 
2452
                                while(structure != NULLOBJECT)
 
2453
                                {
 
2454
                                        if(not structureComplete(structure))
 
2455
                                        {
 
2456
                                                //Find closest one
 
2457
                                                result3 = distBetweenTwoPoints(baseX, baseY, structure.x, structure.y);
 
2458
                                                if(result3 < result)
 
2459
                                                {
 
2460
                                                        //Make sure no one's building already
 
2461
                                                        //result2 = buildingSiteBlocked(NULLOBJECT, 128, structure.x, structure.y);
 
2462
                                                        //if(result2 == 0)
 
2463
                                                        if(not buildingSiteBlocked(NULLOBJECT, 128, structure.x, structure.y, false))
 
2464
                                                        {
 
2465
                                                                //check for threat, since can be far from the base
 
2466
                                                                if(not threatInRange(me, structure.x, structure.y, threatRange, FALSE))
 
2467
                                                                {
 
2468
                                                                        structure2 = structure;
 
2469
                                                                        result = result3;
 
2470
                                                                }
 
2471
                                                        }
 
2472
                                                }
 
2473
                                        }
 
2474
                                        structure = enumStruct();
 
2475
                                }
 
2476
                        }
 
2477
 
 
2478
                        //Build it
 
2479
                        if(structure2 != NULLOBJECT)
 
2480
                        {
 
2481
                                bDummy = buildUsingClosestTruck(structure2.stat, structure2.x, structure2.y, 1);
 
2482
                        }
 
2483
 
 
2484
 
 
2485
                }
 
2486
                droid = iterateGroupB(buildGr, me);
 
2487
        }
 
2488
}
 
2489
 
 
2490
function bool canSendReinf(bool _forHelping)
 
2491
{
 
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,
 
2506
                                        _fTotalAllyUnits;
 
2507
        local   bool    _bWin,_bWinWithSentReinf;
 
2508
 
 
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
 
2512
        {
 
2513
                _numAvailable = groupSizeCmds(defendGr,true,false,true) -
 
2514
                                        min(minDefenders, numDefenders);        //leave only minimal number of derenders
 
2515
        }
 
2516
 
 
2517
        _numAvailable = max(0,_numAvailable);
 
2518
 
 
2519
        // if(_numAvailable > 0)
 
2520
        // {
 
2521
                _fightRange = REINF_ENEMY_COUNT_RANGE;
 
2522
 
 
2523
                // range when sendAttackGr units get added to attackGr
 
2524
                if(helpingAlly()){
 
2525
                        _sendRange = sendHelpRange;
 
2526
                }else if(defendingOil()){
 
2527
                        _sendRange = REACHED_DEF_OIL_RANGE;
 
2528
                }else{
 
2529
                        _sendRange = REACHED_DEST_RANGE;
 
2530
                }
 
2531
 
 
2532
                // Calculate travel distance of the reinforcements
 
2533
                _travelDist = ( max(0, distBetweenTwoPoints(sendForceX, sendForceY, baseX, baseY) -
 
2534
                                                baseRange - defendCorridor)) / TILE;
 
2535
 
 
2536
                // Calculate travel time of the reinforcements
 
2537
                _travelTime = TILE_TRAVEL_TIME * _travelDist;
 
2538
 
 
2539
                _numReinfOnTheWay = groupSizeCmds(sendAttackGr,true,false,true);
 
2540
 
 
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)
 
2545
                {
 
2546
                        _sentReinfTravDist = distBetweenTwoPoints(sendForceX, sendForceY, groupCMD_x(sendAttackGr), groupCMD_y(sendAttackGr)) / TILE;
 
2547
                        if(_sentReinfTravDist > _sendRange)             //make sure won't count sendAttackGr members twice
 
2548
                        {
 
2549
                                _sentReinfTravelTime = TILE_TRAVEL_TIME * _sentReinfTravDist;
 
2550
                        }
 
2551
                }
 
2552
 
 
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);
 
2556
 
 
2557
                // Calculate enemy and friendly strengths
 
2558
                _fNumAttackersLeft = (float)_numAllies;
 
2559
                _fNumEnemiesLeft = (float)_numEnemies;
 
2560
 
 
2561
                // if(_numEnemies > 0 and _numAllies > 0)
 
2562
                // {
 
2563
                        // Calculate total hp of the weapon objects
 
2564
                        if(_numAllies > 0){
 
2565
                                _friendlyHP = totalFriendlyWeapObjHPInRange(sendForceX, sendForceY, _fightRange, false);
 
2566
                        }
 
2567
 
 
2568
                        if(_numEnemies > 0){
 
2569
                                _enemyHP = totalEnemyWeapObjHPInRange(sendForceX, sendForceY, _fightRange, false);
 
2570
                        }
 
2571
 
 
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;
 
2577
                        }
 
2578
 
 
2579
                        _fEnemyAvUnitStrength = 0.0;
 
2580
                        if(_enemyHP > 0 and _numEnemies > 0){
 
2581
                                _fEnemyAvUnitStrength = (float)_enemyHP / (float)_numEnemies;
 
2582
                        }
 
2583
 
 
2584
                        // _fEnemyAvUnitFirepower = _enemyPower / _numEnemies;
 
2585
                        // _fFriendlyAvUnitFirepower = _friendlyPower / _numAllies;
 
2586
 
 
2587
                        _fFriendlyFirepower = friendlyFirepowerInRange(sendForceX, sendForceY, _fightRange);
 
2588
                        if(_numAllies > 0){
 
2589
                                _fFriendlyAvUnitFirepower = _fFriendlyFirepower / (float)_numAllies;    //can't use group here because of possible ally units
 
2590
                        }
 
2591
 
 
2592
                        _fEnemyFirepower = enemyFirepowerInRange(sendForceX, sendForceY, _fightRange);
 
2593
                        if(_numEnemies > 0){
 
2594
                                _fEnemyAvUnitFirepower = _fEnemyFirepower / (float)_numEnemies;
 
2595
                        }
 
2596
 
 
2597
                        // Calculate how fast units kill each other (one unit vs one enemy unit)
 
2598
                        if(_fEnemyAvUnitStrength > 0.0){
 
2599
                                _allyKillRate = _fFriendlyAvUnitFirepower / _fEnemyAvUnitStrength;
 
2600
                        }
 
2601
 
 
2602
                        if(_fFriendlyAvUnitStrength > 0.0){
 
2603
                                _enemyKillRate = _fEnemyAvUnitFirepower / _fFriendlyAvUnitStrength;
 
2604
                        }
 
2605
 
 
2606
                        // Calculate predicted number of attackers left in the attackGr when reinforcements will arrive
 
2607
                        _fNumAttackersLeft = (float)_numAllies;
 
2608
                        _fNumEnemiesLeft = (float)_numEnemies;
 
2609
 
 
2610
                        _fNumAttackersLeft = secondLanchasterLaw((float)_numAllies,(float)_numEnemies,_travelTime,_allyKillRate,_enemyKillRate);
 
2611
                        _fNumEnemiesLeft = secondLanchasterLaw((float)_numEnemies,(float)_numAllies,_travelTime,_enemyKillRate,_allyKillRate);
 
2612
 
 
2613
                        _bWin = LanchasterVictory((float)_numAllies, (float)_numEnemies, _allyKillRate, _enemyKillRate);
 
2614
 
 
2615
                        // calculate how much time it will take for us to win
 
2616
                        if(_bWin){
 
2617
                                _timeToWin = LanchasterTimeToWin((float)_numAllies, (float)_numEnemies, _allyKillRate, _enemyKillRate);
 
2618
 
 
2619
                                // if(_timeToWin < _travelTime)
 
2620
                                // {
 
2621
                                        _fNumAttackersLeft = secondLanchasterLaw((float)_numAllies,(float)_numEnemies,_timeToWin,_allyKillRate,_enemyKillRate);
 
2622
                                        _fNumEnemiesLeft = 0.0;
 
2623
                                // }
 
2624
                        }else{
 
2625
                                _timeToLose = LanchasterTimeToWin((float)_numEnemies, (float)_numAllies, _enemyKillRate, _allyKillRate);
 
2626
 
 
2627
                                // if(_timeToWin < _travelTime)
 
2628
                                // {
 
2629
                                        _fNumAttackersLeft = 0.0;
 
2630
                                        _fNumEnemiesLeft = secondLanchasterLaw((float)_numEnemies,(float)_numAllies,_timeToLose,_enemyKillRate,_allyKillRate);
 
2631
                                // }
 
2632
                        }
 
2633
 
 
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);
 
2636
 
 
2637
                        // if we are going to lose see if reinforcements that are already on the way (!) will make it in time
 
2638
                        _bWinWithSentReinf = true;
 
2639
 
 
2640
                        // Reinforcements vs Enemy
 
2641
                        //------------------------------------------
 
2642
                        _fReinfAvUnitStrength = 0.0;
 
2643
                        _fReinfAvFirepower = 0.0;
 
2644
                        _fReinfAvKillRate = 0.0;
 
2645
                        if(_numReinfOnTheWay > 0)
 
2646
                        {
 
2647
                                _fReinfAvUnitStrength = groupHP(sendAttackGr) / (float)_numReinfOnTheWay;
 
2648
                                _fReinfAvFirepower = groupFirepower(sendAttackGr) / (float)_numReinfOnTheWay;
 
2649
 
 
2650
                                // kill rate our reinforcements vs the original enemy force
 
2651
                                if(_fEnemyAvUnitStrength > 0.0){
 
2652
                                        _fReinfAvKillRate = _fReinfAvFirepower / _fEnemyAvUnitStrength;
 
2653
                                }
 
2654
 
 
2655
                                // kill rate of the riginal enemy force vs our reinforcements
 
2656
                                if(_fReinfAvUnitStrength > 0.0){
 
2657
                                        _fReinfEnAvKillRate = _fEnemyAvUnitFirepower / _fReinfAvUnitStrength;
 
2658
                                }
 
2659
                        }
 
2660
 
 
2661
 
 
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
 
2664
                        {
 
2665
                                // check if reinf will be there before we lose
 
2666
                                if(_sentReinfTravelTime < _timeToLose)
 
2667
                                {
 
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);
 
2671
 
 
2672
                                        // Original attackForce + old reinforcements
 
2673
                                        _fTotalAllyUnits = (float)_numReinfOnTheWay + _fNumReinfAttackersLeft;
 
2674
 
 
2675
                                        // kill rate of original attackers and reinforcements
 
2676
                                        _fAllyCompoundKillRate = (( (float)_numReinfOnTheWay * _fReinfAvKillRate +
 
2677
                                                                                _fNumReinfAttackersLeft * _allyKillRate)) / _fTotalAllyUnits;
 
2678
 
 
2679
                                        // kill rate of original enemy force against original ally force and reinforcements
 
2680
                                        _fEnemyCompoundKillRate = _fEnemyAvUnitFirepower /
 
2681
                                                                        (( (float)_numReinfOnTheWay * _fReinfAvUnitStrength +
 
2682
                                                                                _fNumReinfAttackersLeft * _fFriendlyAvUnitStrength) / _fTotalAllyUnits);
 
2683
 
 
2684
 
 
2685
                                        // try again
 
2686
                                        _bWinWithSentReinf = LanchasterVictory(_fTotalAllyUnits, _fNumReinfEnemiesLeft,
 
2687
                                                                                                                _fAllyCompoundKillRate, _fEnemyCompoundKillRate);
 
2688
 
 
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);
 
2693
                                        }else{
 
2694
                                                // calc how many reinf will be left
 
2695
                                                _reinfWinTime =  LanchasterTimeToWin(_fTotalAllyUnits, _fNumReinfEnemiesLeft, _fAllyCompoundKillRate, _fEnemyCompoundKillRate);
 
2696
                                                _fNumReinfLeft = secondLanchasterLaw(_fTotalAllyUnits, _fNumReinfEnemiesLeft, _reinfWinTime, _fAllyCompoundKillRate, _fEnemyCompoundKillRate);
 
2697
                                        }
 
2698
                                }
 
2699
                                else    // sent reinf will arrive after attackers are killed
 
2700
                                {
 
2701
                                        // calc how many enemies will be left
 
2702
                                        _fNumReinfEnemiesLeft = secondLanchasterLaw((float)_numEnemies,(float)_numAllies,_timeToLose,_enemyKillRate,_allyKillRate);
 
2703
                                        _fNumReinfAttackersLeft = 0.0;
 
2704
 
 
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);
 
2707
 
 
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);
 
2712
                                        }else{
 
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);
 
2716
                                        }
 
2717
                                }
 
2718
                        }
 
2719
 
 
2720
                // }
 
2721
 
 
2722
                // The longer the travel distance, the more units must be sent, 1 additional unit per 10 secs
 
2723
                _minTravelingUnits = _travelTime / SECONDS_PER_DROID;
 
2724
 
 
2725
                // how many enemy reinforcements must arrive - we need additional firepower to counter them
 
2726
                _predictedEnemyReinf = 1;
 
2727
 
 
2728
                // we should only send more units if we are going to lose
 
2729
                if(_bWin){
 
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);
 
2736
                }
 
2737
 
 
2738
                //_minSendUnits = _predictedEnemyReinf + max(0, (int)_fNumEnemiesLeft - (int)_fNumAttackersLeft);
 
2739
 
 
2740
                // Take old reinforcements into account
 
2741
                // TODO: need a better way to model this
 
2742
                // if(_numReinfOnTheWay > 0)
 
2743
                // {
 
2744
                        // _minSendUnits = _minSendUnits - (int)_fNumEffectiveReinf;
 
2745
                // }
 
2746
 
 
2747
                // Make sure there is a min number of reinforcements available
 
2748
                // if(_minSendUnits < _minTravelingUnits)
 
2749
                // {
 
2750
                        // _minSendUnits = _minTravelingUnits;
 
2751
                // }
 
2752
        // }
 
2753
 
 
2754
        if(watchWindowDebug == WATCH_DEBUG_REINF)
 
2755
        {
 
2756
                setDebugMenuEntry("time/min trav:" & _travelTime & "/" & _minTravelingUnits, 0);
 
2757
                setDebugMenuEntry("# (left): " & _numAllies & "(" & _fNumAttackersLeft &  ")/" & _numEnemies & "(" & _fNumEnemiesLeft & ")", 1);
 
2758
 
 
2759
                setDebugMenuEntry("hp:" & (int)_fFriendlyAvUnitStrength & " (" & _friendlyHP &
 
2760
                                                ") / " & (int)_fEnemyAvUnitStrength & " (" & _enemyHP & ")" , 2);
 
2761
 
 
2762
                setDebugMenuEntry("dam:" & _fFriendlyAvUnitFirepower & " (" &
 
2763
                                                (int)_fFriendlyFirepower & ") / " & _fEnemyAvUnitFirepower &
 
2764
                                                " (" & (int)_fEnemyFirepower & ")" , 3);
 
2765
 
 
2766
                setDebugMenuEntry("kill rate: " & _allyKillRate & " / " & _enemyKillRate , 4);
 
2767
 
 
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);
 
2771
 
 
2772
                if(_bWin){
 
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);
 
2780
                        }else{
 
2781
                                setDebugMenuEntry("reinf win-:" & ((float)_timeToLose / (float)MINUTE) & "+" & ((float)_reinfWinTime / (float)MINUTE), 8);
 
2782
                                setDebugMenuEntry("reinf left:" & _fNumReinfLeft & "(" & _fNumReinfEnemiesLeft & ")", 9);
 
2783
                        }
 
2784
                }else{
 
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);
 
2788
                        }else{
 
2789
                                setDebugMenuEntry("no chance-:" & ((float)_timeToLose / (float)MINUTE) & "+" & ((float)_reinfLoseTime / (float)MINUTE), 8);
 
2790
                        }
 
2791
                        setDebugMenuEntry("en left: " & _fNumReinfEnemiesLeft, 9);
 
2792
                }
 
2793
 
 
2794
 
 
2795
        }
 
2796
 
 
2797
 
 
2798
        // make sure there will be any attackers left when reinforcements will arrive
 
2799
/*      if(_fNumAttackersLeft <= 0.0)
 
2800
        {
 
2801
                return false;
 
2802
        } */
 
2803
 
 
2804
        if(_numAvailable < _minSendUnits)
 
2805
        {
 
2806
                return false;
 
2807
        }
 
2808
 
 
2809
        return true;
 
2810
 
 
2811
/*      _numAvailable = groupSizeCmds(defendGr,true,false,true) - numDefenders; //use less units
 
2812
        if(_forHelping) //use more units if helping
 
2813
        {
 
2814
                _numAvailable = groupSizeCmds(defendGr,true,false,true) -
 
2815
                                        min(minDefenders, numDefenders);        //leave only minimal number of derenders
 
2816
        }
 
2817
 
 
2818
        _minSendUnits = minReinforcements;
 
2819
        if(_forHelping)
 
2820
        {
 
2821
                // if we wait for more units ally can get killed
 
2822
                _minSendUnits = min(MIN_HELPING_ALLY_REINF, minReinforcements);
 
2823
        }
 
2824
 
 
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
 
2828
        {
 
2829
                return TRUE;
 
2830
        }
 
2831
 
 
2832
        return FALSE; */
 
2833
}
 
2834
 
 
2835
//----------------------------------------------------------
 
2836
//                      stop state
 
2837
//----------------------------------------------------------
 
2838
function void stopState()
 
2839
{
 
2840
        if(state == stAttacking)
 
2841
        {
 
2842
                stopAttack();
 
2843
        }
 
2844
        else if(defendingBase())
 
2845
        {
 
2846
                stopDefendingBase();
 
2847
        }
 
2848
        else if(defendingOil())
 
2849
        {
 
2850
                stopDefendingOil();
 
2851
        }
 
2852
        else if(helpingAlly())
 
2853
        {
 
2854
                stopAllyDefense();
 
2855
        }
 
2856
        else if(state == stJoiningForces)
 
2857
        {
 
2858
                stopJoiningForces();
 
2859
        }
 
2860
        else if(state == stTakingOil)
 
2861
        {
 
2862
                stopTakingOil();
 
2863
        }
 
2864
        else if(state == stCollecting)
 
2865
        {
 
2866
                stopCollecting();
 
2867
        }
 
2868
        else if(state == stTransporting)
 
2869
        {
 
2870
                stopTransportState();
 
2871
        }
 
2872
        else if(state == stDrop)
 
2873
        {
 
2874
                stopDropState();
 
2875
        }
 
2876
        else if(state != stNone)
 
2877
        {
 
2878
                MsgBox("stopState() - unknown state");
 
2879
        }
 
2880
}
 
2881
 
 
2882
function void cancelState()
 
2883
{
 
2884
        if(state == stAttacking)
 
2885
        {
 
2886
                cancelAttack();
 
2887
        }
 
2888
        else if(state == stDefendingBase)
 
2889
        {
 
2890
                cancelDefendingBase();
 
2891
        }
 
2892
        else if(defendingOil())
 
2893
        {
 
2894
                cancelDefendingOil();
 
2895
        }
 
2896
        else if(state == stHelpingAlly)
 
2897
        {
 
2898
                cancelAllyDefense();
 
2899
        }
 
2900
        else if(state == stJoiningForces)
 
2901
        {
 
2902
                cancelJoiningForces();
 
2903
        }
 
2904
        else if(state == stTakingOil)
 
2905
        {
 
2906
                cancelTakingOil();
 
2907
        }
 
2908
        else if(state == stCollecting)
 
2909
        {
 
2910
                cancelCollecting();
 
2911
        }
 
2912
        else if(state == stTransporting)
 
2913
        {
 
2914
                cancelTransportState();
 
2915
        }
 
2916
        else if(state == stDrop)
 
2917
        {
 
2918
                cancelDropState();
 
2919
        }
 
2920
        else if(state != stNone)
 
2921
        {
 
2922
                MsgBox("cancelState() - unknown state");
 
2923
        }
 
2924
}
 
2925
 
 
2926
function void endState()
 
2927
{
 
2928
        if(state == stAttacking)
 
2929
        {
 
2930
                endAttack();
 
2931
        }
 
2932
        else if(state == stDefendingBase)
 
2933
        {
 
2934
                endDefendingBase();
 
2935
        }
 
2936
        else if(defendingOil())
 
2937
        {
 
2938
                endDefendingOil();
 
2939
        }
 
2940
        else if(state == stHelpingAlly)
 
2941
        {
 
2942
                endAllyDefense();
 
2943
        }
 
2944
        else if(state == stJoiningForces)
 
2945
        {
 
2946
                endJoiningForces();
 
2947
        }
 
2948
        else if(state == stTakingOil)
 
2949
        {
 
2950
                endTakingOil();
 
2951
        }
 
2952
        else if(state == stTransporting)
 
2953
        {
 
2954
                endTransportState();
 
2955
        }
 
2956
        else if(state == stDrop)
 
2957
        {
 
2958
                endDropState();
 
2959
        }
 
2960
        else if(state != stNone)
 
2961
        {
 
2962
                MsgBox("endState() - unknown state");
 
2963
        }
 
2964
}
 
2965
 
 
2966
 
 
2967
function void pauseState()
 
2968
{
 
2969
        if(state == stNone){exit;}
 
2970
 
 
2971
        /* only stAttacking is paused, otherwise just stop doing what we were doing */
 
2972
        if(state != stAttacking)
 
2973
        {
 
2974
                cancelState();
 
2975
                exit;
 
2976
        }               //only stAttacking for now
 
2977
 
 
2978
        dbg("PAUSING CURRENT STATE!!!!!!!!!!!!!!!!!!", me);
 
2979
 
 
2980
        /* cancelState() will reset enemy and stat, so remember now */
 
2981
        lastStateTemp = state;
 
2982
        lastEnemyTemp = enemy;
 
2983
 
 
2984
        cancelState();
 
2985
 
 
2986
        lastState = lastStateTemp;
 
2987
        lastEnemy = lastEnemyTemp;
 
2988
}
 
2989
 
 
2990
function void resumeState()
 
2991
{
 
2992
        if(lastState == stAttacking)
 
2993
        {
 
2994
                if((not allianceExistsBetween(lastEnemy ,me)) and knowBase[lastEnemy])
 
2995
                {
 
2996
                        dbg("Resuming attack: at enemy: " & lastEnemy, me);
 
2997
 
 
2998
                        groupAddGroupCmd(defendGr, attackGr);
 
2999
                        groupAddGroupCmd(defendGr, sendAttackGr);
 
3000
 
 
3001
                        setState(lastState);
 
3002
 
 
3003
                        //HACK: resume with curBase[], actually must remember last attack x and y
 
3004
                        if(knowBase[lastEnemy])
 
3005
                        {
 
3006
                                startEnemyBaseAttack(lastEnemy);
 
3007
                                requestStartAttack(lastEnemy, curBase[lastEnemy][0], curBase[lastEnemy][1]);
 
3008
                        }
 
3009
                }
 
3010
        }
 
3011
 
 
3012
        /* clear vars */
 
3013
        erasePausedState();
 
3014
}
 
3015
 
 
3016
function void erasePausedState()
 
3017
{
 
3018
        lastState = stNone;
 
3019
        lastEnemy = none;
 
3020
}
 
3021
 
 
3022
function int findAllyInTrouble()
 
3023
{
 
3024
        _temp = 0;
 
3025
        _temp2 = 99999;
 
3026
        _temp4 = none;  //ally in trouble
 
3027
        while(_temp < multiPlayerMaxPlayers)
 
3028
        {
 
3029
                if(ally[_temp] and (not dead[_temp]) and (allyState[_temp] == stDefendingBase))
 
3030
                {
 
3031
                        //if(knowBase[_temp])
 
3032
                        if(curHelpX[_temp] > 0) //have help location
 
3033
                        {
 
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
 
3037
                                {
 
3038
                                        _temp4 = _temp;
 
3039
                                        _temp2 = _temp3;
 
3040
                                }
 
3041
                        }
 
3042
                }
 
3043
                _temp = _temp + 1;
 
3044
        }
 
3045
 
 
3046
        return(_temp4);
 
3047
}
 
3048
 
 
3049
//----------------------------------------------------------
 
3050
//                      stop defendingBase
 
3051
//----------------------------------------------------------
 
3052
function void stopDefendingBase()
 
3053
{
 
3054
        local   bool    _busy;
 
3055
 
 
3056
        _busy = FALSE;
 
3057
 
 
3058
        endDefendingBase();
 
3059
 
 
3060
        dbg("DEFEND: stopped", me);
 
3061
 
 
3062
        /* If we were doing something before defending, resume it */
 
3063
        if(lastState != stNone)
 
3064
        {
 
3065
                _busy = TRUE;
 
3066
                resumeState();
 
3067
        }
 
3068
 
 
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
 
3071
        {
 
3072
                temp = totalWeapUnits();
 
3073
                if(temp > minAllyHelpers)
 
3074
                {
 
3075
                        temp = findAllyInTrouble();             //see if any of our allies is in trouble
 
3076
                        if(temp != none)
 
3077
                        {
 
3078
                                notifyAllies(getPlayerName(temp) & ", coming now, hold on", false);
 
3079
 
 
3080
                                _busy = TRUE;
 
3081
 
 
3082
                                startHelpAlly(temp,curHelpX[temp],curHelpY[temp]);
 
3083
                        }
 
3084
                }
 
3085
        }
 
3086
 
 
3087
        /* Return to base if idle */
 
3088
        if(not _busy)
 
3089
        {
 
3090
                goRTB();
 
3091
                resetSendForceCoords();
 
3092
        }
 
3093
 
 
3094
        /* play cool
 
3095
        if(random(2) == 0)
 
3096
        {
 
3097
                if(random(2) == 0){notifyAllies("they suck", TRUE);}
 
3098
                else{notifyAllies("bwuhaha", TRUE);}
 
3099
        }*/
 
3100
 
 
3101
        /* Check ally status */
 
3102
        checkRequestStatus();
 
3103
}
 
3104
 
 
3105
function void cancelDefendingBase()
 
3106
{
 
3107
        erasePausedState();             //don't resume since cancelled
 
3108
 
 
3109
        endDefendingBase();
 
3110
 
 
3111
        goRTB();
 
3112
 
 
3113
        resetSendForceCoords();
 
3114
 
 
3115
        dbg("DEFEND: cancelled defendingBase", me);
 
3116
}
 
3117
 
 
3118
function void endDefendingBase()
 
3119
{
 
3120
        deselectAllDroids();
 
3121
 
 
3122
        setState(stNone);
 
3123
 
 
3124
        setPhase(phNone,NONE);
 
3125
 
 
3126
        enemy = none;
 
3127
        counterEnemy = none;
 
3128
 
 
3129
        requestHelpTime = 0;
 
3130
 
 
3131
        /* reset notification stuff */
 
3132
        bNotifiedReadyAttack = FALSE;
 
3133
        notifyReadyAttackTime = 0;
 
3134
}
 
3135
 
 
3136
 
 
3137
//----------------------------------------------------------
 
3138
//                      stop taking oil
 
3139
//----------------------------------------------------------
 
3140
function void stopTakingOil()
 
3141
{
 
3142
        dbg("TAKE OIL: stopped", me);
 
3143
 
 
3144
        endTakingOil();
 
3145
 
 
3146
        /* If we were doing something before helping ally, resume it */
 
3147
        if(lastState != stNone)
 
3148
        {
 
3149
                resumeState();
 
3150
        }
 
3151
        else
 
3152
        {
 
3153
                goRTB();
 
3154
                resetSendForceCoords();
 
3155
                checkRequestStatus();
 
3156
        }
 
3157
}
 
3158
 
 
3159
function void cancelTakingOil()
 
3160
{
 
3161
        erasePausedState();             //don't resume since cancelled
 
3162
 
 
3163
        endTakingOil();
 
3164
 
 
3165
        goRTB();
 
3166
 
 
3167
        resetSendForceCoords();
 
3168
 
 
3169
        dbg("TAKE OIL: cancelled", me);
 
3170
}
 
3171
 
 
3172
function void endTakingOil()
 
3173
{
 
3174
        deselectAllDroids();
 
3175
 
 
3176
        setState(stNone);
 
3177
 
 
3178
        setPhase(phNone, NONE);
 
3179
 
 
3180
        enemy = none;
 
3181
 
 
3182
        timeGuardPos = 0;
 
3183
        tTakeOil = 0;
 
3184
 
 
3185
        /* reset notification stuff */
 
3186
        bNotifiedReadyAttack = FALSE;
 
3187
        notifyReadyAttackTime = 0;
 
3188
}
 
3189
 
 
3190
//----------------------------------------------------------
 
3191
//                      stop defending oil
 
3192
//----------------------------------------------------------
 
3193
function void stopDefendingOil()
 
3194
{
 
3195
        dbg("DEFENDING OIL: stopped", me);
 
3196
 
 
3197
        endDefendingOil();
 
3198
 
 
3199
        /* If we were doing something before helping ally, resume it */
 
3200
        if(lastState != stNone)
 
3201
        {
 
3202
                resumeState();
 
3203
        }
 
3204
        else
 
3205
        {
 
3206
                goRTB();
 
3207
                resetSendForceCoords();
 
3208
                checkRequestStatus();
 
3209
        }
 
3210
}
 
3211
 
 
3212
function void endDefendingOil()
 
3213
{
 
3214
        deselectAllDroids();
 
3215
 
 
3216
        setState(stNone);
 
3217
 
 
3218
        setPhase(phNone, NONE);
 
3219
 
 
3220
        enemy = none;
 
3221
 
 
3222
        // reset coordinates of the attacked derrick
 
3223
        resetOilDefendCoords();
 
3224
}
 
3225
 
 
3226
function void cancelDefendingOil()
 
3227
{
 
3228
        erasePausedState();             //don't resume since cancelled
 
3229
 
 
3230
        endDefendingOil();
 
3231
 
 
3232
        goRTB();
 
3233
 
 
3234
        resetSendForceCoords();
 
3235
 
 
3236
        dbg("DEFENDING OIL: cancelled", me);
 
3237
}
 
3238
 
 
3239
//----------------------------------------------------------
 
3240
//                      stop joining forces
 
3241
//----------------------------------------------------------
 
3242
function void stopJoiningForces()
 
3243
{
 
3244
        dbg("JOINING FORCES: stopped", me);
 
3245
 
 
3246
        endJoiningForces();
 
3247
 
 
3248
        /* If we were doing something before defending, resume it */
 
3249
        if(lastState != stNone)
 
3250
        {
 
3251
                resumeState();
 
3252
        }
 
3253
        else
 
3254
        {
 
3255
                goRTB();
 
3256
                resetSendForceCoords();
 
3257
        }
 
3258
}
 
3259
 
 
3260
function void cancelJoiningForces()
 
3261
{
 
3262
        erasePausedState();             //don't resume since cancelled
 
3263
 
 
3264
        goRTB();
 
3265
 
 
3266
        resetSendForceCoords();
 
3267
 
 
3268
        endJoiningForces();
 
3269
 
 
3270
        dbg("JOINING FORCES: cancelled", me);
 
3271
}
 
3272
 
 
3273
function void endJoiningForces()
 
3274
{
 
3275
        deselectAllDroids();
 
3276
 
 
3277
        setState(stNone);
 
3278
 
 
3279
        setPhase(phNone, NONE);
 
3280
 
 
3281
        enemy = none;
 
3282
 
 
3283
        timeGuardPos = 0;       //reset
 
3284
 
 
3285
        /* reset notification stuff */
 
3286
        bNotifiedReadyAttack = FALSE;
 
3287
        notifyReadyAttackTime = 0;
 
3288
}
 
3289
 
 
3290
//----------------------------------------------------------
 
3291
//                      stop ally defense
 
3292
//----------------------------------------------------------
 
3293
function void stopAllyDefense()
 
3294
{
 
3295
        endAllyDefense();
 
3296
 
 
3297
        dbg("stopped helping ally !!!!!!!!!!!!!!!!!!!!!!!!", me);
 
3298
 
 
3299
        /* If we were doing something before helping ally, resume it */
 
3300
        if(lastState != stNone)
 
3301
        {
 
3302
                resumeState();
 
3303
        }
 
3304
        else
 
3305
        {
 
3306
                goRTB();
 
3307
 
 
3308
                resetSendForceCoords();
 
3309
        }
 
3310
}
 
3311
 
 
3312
function void cancelAllyDefense()
 
3313
{
 
3314
        erasePausedState();             //don't resume since cancelled
 
3315
 
 
3316
        endAllyDefense();
 
3317
 
 
3318
        goRTB();
 
3319
 
 
3320
        resetSendForceCoords();
 
3321
 
 
3322
        dbg("ALLY DEFENSE: cancelled", me);
 
3323
}
 
3324
 
 
3325
function void endAllyDefense()
 
3326
{
 
3327
        deselectAllDroids();
 
3328
 
 
3329
        enemy = none;                   //allyInThreat
 
3330
 
 
3331
        helpTime = 0;
 
3332
 
 
3333
        /* reset notification stuff */
 
3334
        bNotifiedReadyAttack = FALSE;
 
3335
        notifyReadyAttackTime = 0;
 
3336
 
 
3337
        setState(stNone);
 
3338
 
 
3339
        setPhase(phNone, NONE); //phRTB;
 
3340
}
 
3341
 
 
3342
//----------------------------------------------------------
 
3343
//                      stop attack
 
3344
//----------------------------------------------------------
 
3345
function void stopAttack()
 
3346
{
 
3347
        endAttack();
 
3348
 
 
3349
        dbg("ATTACK: stopped", me);
 
3350
 
 
3351
        /* If we were doing something before attacking, resume it */
 
3352
        if(lastState != stNone)
 
3353
        {
 
3354
                resumeState();
 
3355
        }
 
3356
        else
 
3357
        {
 
3358
                goRTB();
 
3359
                resetSendForceCoords();
 
3360
                checkRequestStatus();
 
3361
        }
 
3362
}
 
3363
 
 
3364
function void cancelAttack()
 
3365
{
 
3366
        erasePausedState();             //don't resume since cancelled
 
3367
 
 
3368
        endAttack();
 
3369
 
 
3370
        goRTB();
 
3371
 
 
3372
        resetSendForceCoords();
 
3373
 
 
3374
        dbg("ATTACK: cancelled", me);
 
3375
}
 
3376
 
 
3377
function void endAttack()
 
3378
{
 
3379
        deselectAllDroids();
 
3380
 
 
3381
        setState(stNone);
 
3382
 
 
3383
        enemy = none;
 
3384
 
 
3385
        setPhase(phNone, NONE); //phRTB
 
3386
 
 
3387
        reinfTime = 0;  //timer
 
3388
 
 
3389
        countTakeOil = 0;               //allow hunting oil again
 
3390
 
 
3391
        /* reset notification stuff */
 
3392
        bNotifiedReadyAttack = FALSE;
 
3393
        notifyReadyAttackTime = 0;
 
3394
 
 
3395
        numTakeOil = random(maxTakeOil);        //allow attacking oil again
 
3396
}
 
3397
 
 
3398
function void resetSendForceCoords()
 
3399
{
 
3400
        updateStateCoord(NONE, NONE);
 
3401
}
 
3402
 
 
3403
//--------------------------------------
 
3404
//      Transport
 
3405
//--------------------------------------
 
3406
function void stopTransportState()
 
3407
{
 
3408
        endTransportState();    //first end then load otherwise endTransportState will reset state
 
3409
 
 
3410
        setPhase(phTransportDone, NONE);        //make sure drop state knows that transport finished successfully
 
3411
 
 
3412
        loadSavedState();
 
3413
}
 
3414
 
 
3415
function void cancelTransportState()
 
3416
{
 
3417
        dbg("cancelTransportState", me);
 
3418
 
 
3419
        eraseLoadSavedState();  //since cancelled
 
3420
 
 
3421
        temp = 0;
 
3422
        while(temp < maxTransporters)
 
3423
        {
 
3424
                if(transporter[temp] != NULLOBJECT)
 
3425
                {
 
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
 
3428
                        {
 
3429
                                dbg("unloading transporter", me);
 
3430
                                unloadTransporter(transporter[temp], transporter[temp].x, transporter[temp].y);
 
3431
                        }
 
3432
                        else    //Send to unload in the base
 
3433
                        {
 
3434
                                dbg("ordering transporter to disembark in the base", me);
 
3435
                                orderTranspDisembark(transporter[temp], baseX, baseY);          //make unload units in the base
 
3436
                        }
 
3437
 
 
3438
                }
 
3439
                temp = temp + 1;
 
3440
        }
 
3441
 
 
3442
        notifyCantDrop();
 
3443
 
 
3444
        checkRequestStatus();
 
3445
 
 
3446
        deselectAllDroids();
 
3447
        goRTB();                        //only sends sendAttackGr home, not transportGr
 
3448
 
 
3449
        prepareTransporters();  //send transporters back to base
 
3450
 
 
3451
        endTransportState();
 
3452
 
 
3453
        resetSendForceCoords();
 
3454
 
 
3455
        enemy = none;           //must be done here, since not done in endTransportState()
 
3456
}
 
3457
 
 
3458
function void endTransportState()
 
3459
{
 
3460
        dbg("endTransportState", me);
 
3461
 
 
3462
        groupAddGroupCmd(defendGr, transportGr);        //return unloaded units to defenders or if state cancelled
 
3463
 
 
3464
        transportX = none;
 
3465
        transportY = none;
 
3466
 
 
3467
        tWaitLoadDrop = 0;
 
3468
 
 
3469
        setState(stNone);
 
3470
 
 
3471
        setPhase(phNone, NONE);
 
3472
 
 
3473
        //enemy = none;
 
3474
}
 
3475
 
 
3476
//--------------------------------------
 
3477
//      Drop
 
3478
//--------------------------------------
 
3479
function void stopDropState()
 
3480
{
 
3481
        endDropState();
 
3482
        dbg("DROP: stopped !!!", me);
 
3483
 
 
3484
        /* If we were doing something before dropping, resume it */
 
3485
        if(lastState != stNone)
 
3486
        {
 
3487
                resumeState();
 
3488
        }
 
3489
        else
 
3490
        {
 
3491
                /* we started the drop directly, not from a different state, so just start attacking the enemy */
 
3492
                enemy = enemy;          //shouldn't change
 
3493
                if(knowBase[enemy])
 
3494
                {
 
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]);
 
3498
                }
 
3499
        }
 
3500
}
 
3501
 
 
3502
function void cancelDropState()
 
3503
{
 
3504
        erasePausedState();             //don't resume since cancelled
 
3505
 
 
3506
        enemy = none;           //should be cleard here?
 
3507
 
 
3508
        dropStartTime = none;   //doesn't belong to endDropState()
 
3509
        tSyncDrop = 0;          //doesn't belong to endDropState()
 
3510
 
 
3511
        endDropState();
 
3512
 
 
3513
        dbg("DROP: cancelled !!!", me);
 
3514
}
 
3515
 
 
3516
function void endDropState()
 
3517
{
 
3518
        setState(stNone);
 
3519
 
 
3520
        setPhase(phNone, NONE);
 
3521
 
 
3522
        if(enemy != none)
 
3523
        {
 
3524
                tempReinfCount[enemy] = 0;              //start over
 
3525
        }
 
3526
}
 
3527
 
 
3528
//----------------------------------------------------------
 
3529
//                      stop collecting
 
3530
//----------------------------------------------------------
 
3531
function void stopCollecting()
 
3532
{
 
3533
        collectTime = 0;
 
3534
 
 
3535
        setState(stNone);
 
3536
 
 
3537
        setPhase(phNone, NONE);
 
3538
 
 
3539
        collectX = none;
 
3540
        collectY = none;
 
3541
 
 
3542
        dbg("COLLECT: stopped", me);
 
3543
}
 
3544
 
 
3545
function void cancelCollecting()
 
3546
{
 
3547
        stopCollecting();
 
3548
}
 
3549
 
 
3550
function void setTechBranch()
 
3551
{
 
3552
        tech = 0;       //random(numBranches);  //FIXME
 
3553
}
 
3554
 
 
3555
function bool pendingLasSatStrike()
 
3556
{
 
3557
        local int _tempPlayer;
 
3558
 
 
3559
        _tempPlayer = 0;
 
3560
        while(_tempPlayer < 8)
 
3561
        {
 
3562
                if(allianceExistsBetween(_tempPlayer, me))
 
3563
                {
 
3564
                        if(lasSatState[_tempPlayer] == lsWaitingReply)  //someone requested lassat strike?
 
3565
                        {
 
3566
                                return TRUE;
 
3567
                        }
 
3568
                }
 
3569
                _tempPlayer = _tempPlayer + 1;
 
3570
        }
 
3571
 
 
3572
        return FALSE;
 
3573
}
 
3574
 
 
3575
function void updateLasSat()
 
3576
{
 
3577
        local STRUCTURE _lasSatTarget;
 
3578
 
 
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)
 
3581
        {
 
3582
                if(tLasSat >= tLasSatReady)             //ready
 
3583
                {
 
3584
                        dbg("lassat ready**********************", me);
 
3585
                        lasSatState[me] = lsReady;
 
3586
                }
 
3587
        }
 
3588
 
 
3589
        if(lasSatState[me] == lsReady)
 
3590
        {
 
3591
                if(pendingLasSatStrike())
 
3592
                {
 
3593
                        dbg("LASSAT: joining ****************", me);
 
3594
                        lasSatState[me] = lsRequesterWaitingRecharging; //join and tell that lassat is ready
 
3595
                }
 
3596
                else
 
3597
                {
 
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
 
3602
                }
 
3603
        }
 
3604
 
 
3605
        if(lasSatState[me] == lsWaitingReply)
 
3606
        {
 
3607
                if(tLasSatCountdown <= 0)               //waited enough for allies to reply to lassat request
 
3608
                {
 
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
 
3612
                }
 
3613
        }
 
3614
 
 
3615
// start 'someone requested lassat strike' code
 
3616
 
 
3617
        /* someone requested lassat and waiting for us to finish recharging lassat */
 
3618
        if(lasSatState[me] == lsRequesterWaitingRecharging)
 
3619
        {
 
3620
                /* check if finished recharging lassat */
 
3621
                if(tLasSat >= tLasSatReady)             //ready
 
3622
                {
 
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
 
3626
                }
 
3627
        }
 
3628
 
 
3629
        /* we finished recharging our lassat and are now waiting for the requester to start the strike */
 
3630
        if(lasSatState[me] == lsWaitingForRequester)
 
3631
        {
 
3632
                /* check if we waited to long, if yes, start the attack on our own */
 
3633
                if(tLasSatCountdown <= 0)       //requester got killed? etc
 
3634
                {
 
3635
                        dbg("waited too long for the requester, firing*************", me);
 
3636
                        lasSatState[me] = lsFiring;     //just fire, don't wait anymore
 
3637
                }
 
3638
        }
 
3639
 
 
3640
// end 'someone requested lassat strike' code
 
3641
 
 
3642
        /* all allies ready to fire? */
 
3643
        if(lasSatState[me] == lsWaiting)
 
3644
        {
 
3645
                //tLasSatCountdown = off;               //not needed anymore
 
3646
 
 
3647
                dbg("lsWaiting: waiting...********", me);
 
3648
                if(allyLasSatReady() or (tLasSatCountdown <= 0))        //if everyone can fire or waited too long
 
3649
                {
 
3650
                        if(allyLasSatReady())
 
3651
                        {
 
3652
                                dbg("lsWaiting: firing now0********", me);
 
3653
                        }
 
3654
                        else if(tLasSatCountdown <= 0)
 
3655
                        {
 
3656
                                dbg("lsWaiting: firing now1********", me);
 
3657
                        }
 
3658
 
 
3659
                        lasSatState[me] = lsFiring;
 
3660
                }
 
3661
        }
 
3662
 
 
3663
        /* everyone's ready or waited too long, fireing now! */
 
3664
/*
 
3665
        if(lasSatState[me] == lsFiring)
 
3666
        {
 
3667
                _lasSatTarget = findLasSatTarget(enemy);
 
3668
 
 
3669
                if(_lasSatTarget != NULLOBJECT)
 
3670
                {
 
3671
                        dbg("lsFiring: found target********", me);
 
3672
                        fireLasSat(_lasSatTarget);
 
3673
                }
 
3674
                else
 
3675
                {
 
3676
                        dbg("lsFiring: couldn't find target********", me);
 
3677
                }
 
3678
        }
 
3679
*/
 
3680
}
 
3681
 
 
3682
/*
 
3683
function void fireLasSat(STRUCTURE _targetStructure)
 
3684
{
 
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))
 
3687
        //{
 
3688
        //      selectStructure(_targetStructure, TRUE);
 
3689
        //}
 
3690
 
 
3691
        skFireLassat(me, _targetStructure);
 
3692
        notifyLassat(_targetStructure);
 
3693
 
 
3694
        resetLasSat();          //reset all counters etc
 
3695
        lasSatState[me] = lsRecharging;         //start recharging lassat (after resetLasSat() !)
 
3696
}
 
3697
*/
 
3698
 
 
3699
function void notifyLassat(STRUCTURE _targetStructure)
 
3700
{
 
3701
        notifyAllies("let's lassat " & getPlayerName(_targetStructure.player), TRUE);           //tell allies who to lassat
 
3702
 
 
3703
        dropAllyBeacon("lassat " & getPlayerName(_targetStructure.player), _targetStructure.x, _targetStructure.y);
 
3704
}
 
3705
 
 
3706
function bool allyLasSatReady()
 
3707
{
 
3708
        local int _tempPlayer;
 
3709
 
 
3710
        /* did we wait too long for allies' lassat to finish recharging? */
 
3711
        //if(tLasSatWaitAllies >= tLasSatWaitAlliesMax)
 
3712
        //{
 
3713
        //      return TRUE;
 
3714
        //}
 
3715
 
 
3716
        /* find out if we are still waiting for someone's lassat to recharge */
 
3717
        _tempPlayer = 0;
 
3718
        while(_tempPlayer < 8)
 
3719
        {
 
3720
                if(allianceExistsBetween(_tempPlayer, me))
 
3721
                {
 
3722
                        if(lasSatState[_tempPlayer] == lsRequesterWaitingRecharging)
 
3723
                        //if((lasSatState[_tempPlayer] != lsRecharging) and (lasSatState[_tempPlayer] != lsWaitingForRequester))//ignore those who don't strike with us
 
3724
                        {
 
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
 
3727
                        }
 
3728
                }
 
3729
 
 
3730
                _tempPlayer = _tempPlayer + 1;
 
3731
        }
 
3732
 
 
3733
        return TRUE;
 
3734
}
 
3735
 
 
3736
function void resetLasSat()
 
3737
{
 
3738
        local int _tempPlayer;
 
3739
 
 
3740
        lasSatState[me] = lsNone;
 
3741
        lasSatEnemy = none;
 
3742
 
 
3743
        tLasSat = 0;                            //start recharging
 
3744
        tLasSatCountdown = off;         //reset the misc timer
 
3745
 
 
3746
        //_tempPlayer = 0;
 
3747
        //while(_tempPlayer < 8)
 
3748
        //{
 
3749
        //      lasSatState[_tempPlayer] = lsNone;
 
3750
        //      _tempPlayer = _tempPlayer + 1;
 
3751
        //}
 
3752
}
 
3753
 
 
3754
function STRUCTURE findLasSatTarget(int _prefferedEnemy)
 
3755
{
 
3756
        local int _tempPlayer,_bestDist,_tempDist;
 
3757
        local   STRUCTURE       _targetStruct,_tempStruct;
 
3758
 
 
3759
        _targetStruct = NULLOBJECT;
 
3760
 
 
3761
        if(_prefferedEnemy >= 0)
 
3762
        {
 
3763
                _targetStruct = mostDamagedBaseStructure(_prefferedEnemy);
 
3764
        }
 
3765
 
 
3766
        /* check all other enemies */
 
3767
        if(_targetStruct == NULLOBJECT)
 
3768
        {
 
3769
                /* find closest target */
 
3770
                _bestDist = 99999;
 
3771
                _tempPlayer = 0;
 
3772
                while(_tempPlayer < 8)
 
3773
                {
 
3774
                        if((not allianceExistsBetween(_tempPlayer, me)) and (_tempPlayer != me))
 
3775
                        {
 
3776
                                _tempStruct = mostDamagedBaseStructure(_tempPlayer);
 
3777
 
 
3778
 
 
3779
                                if(_tempStruct != NULLOBJECT)
 
3780
                                {
 
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)
 
3785
                                        {
 
3786
                                                //dbg("findLasSatTarget: assigned struct********", me);
 
3787
                                                _targetStruct = _tempStruct;
 
3788
                                                _bestDist = _tempDist;
 
3789
                                        }
 
3790
                                }
 
3791
                                //else
 
3792
                                //{
 
3793
                                //      dbg("mostDamagedBaseStructure: NULL ", me);
 
3794
                                //}
 
3795
                        }
 
3796
 
 
3797
                        _tempPlayer = _tempPlayer + 1;
 
3798
                }
 
3799
        }
 
3800
 
 
3801
        return _targetStruct;
 
3802
}
 
3803
 
 
3804
function STRUCTURE mostDamagedBaseStructure(int _targetPlayer)
 
3805
{
 
3806
        local   int                     _structTypeIndex,_lowestHP,_tempHP;
 
3807
        local   STRUCTURE       _returnStruct,_tempStruct;
 
3808
 
 
3809
        _structTypeIndex = 0;
 
3810
        _lowestHP = 99999;
 
3811
        _returnStruct = NULLOBJECT;
 
3812
 
 
3813
        while(_structTypeIndex < numBaseStructs)
 
3814
        {
 
3815
                initEnumStruct(FALSE,baseStructs[_structTypeIndex],_targetPlayer,me);
 
3816
 
 
3817
                _tempStruct = enumStruct();
 
3818
                while(_tempStruct != NULLOBJECT)
 
3819
                {
 
3820
                        _tempHP = _tempStruct.health;
 
3821
                        if(_tempHP < _lowestHP)
 
3822
                        {
 
3823
                                _lowestHP = _tempHP;
 
3824
                                _returnStruct = _tempStruct;
 
3825
                        }
 
3826
 
 
3827
                        _tempStruct = enumStruct();
 
3828
                }
 
3829
 
 
3830
                _structTypeIndex = _structTypeIndex + 1;
 
3831
        }
 
3832
 
 
3833
        return _returnStruct;
 
3834
}
 
3835
 
 
3836
function int checkAllyThreat()
 
3837
{
 
3838
        //return value - player in danger
 
3839
 
 
3840
        range = (23 * 128);
 
3841
 
 
3842
        if(state == stHelpingAlly){return(enemy);}              //already defending
 
3843
 
 
3844
        count = 0;
 
3845
        while(count < multiPlayerMaxPlayers)
 
3846
        {
 
3847
                if(ally[count])
 
3848
                {
 
3849
                        if(knowBase[count])             //know where his base is?
 
3850
                        {
 
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);
 
3853
 
 
3854
                                if(result > result2)
 
3855
                                {
 
3856
                                        //if(enemy == none)     //don't suddenly switch the player, only if not already set     //allyInThreat
 
3857
                                        //{
 
3858
                                                dbg("ally " & count & " is in danger", me);
 
3859
                                                //enemy = count;        //allyInThreat
 
3860
                                                //exit; //must exit here
 
3861
                                                return(count);
 
3862
                                        //}
 
3863
                                }
 
3864
                                //else if(result < 4)           //we have much more and they only < 4
 
3865
                                //{
 
3866
                                //      if(mapRevealedInRange(curBase[count][0],curBase[count][1],(5 * 128),me))        //can judge if safe only if can see the base
 
3867
                                //      {
 
3868
                                //              if(allyInThreat == count)       //same we were helping
 
3869
                                //              {
 
3870
                                //                      dbg(" " & me & ")  HELP ALLY: this player seems to be safe now");
 
3871
                                //                      allyInThreat = none;    //can stop helping now
 
3872
                                //                      exit;   //must exit here
 
3873
                                //              }
 
3874
                                //      }
 
3875
                                //}
 
3876
                        }
 
3877
                }
 
3878
 
 
3879
                count = count + 1;
 
3880
        }
 
3881
 
 
3882
        return(none);   //nothing found
 
3883
}
 
3884
 
 
3885
function void startDefending(int _counterEnemy)
 
3886
{
 
3887
        if((state != stNone) and !defendingBase())      //units busy with something else
 
3888
        {
 
3889
                dbg("BASE: we need our units in the base now, cancel current state", me);
 
3890
                cancelState();
 
3891
        }
 
3892
 
 
3893
        requestHelpTime = 0;    //reset since started over
 
3894
 
 
3895
        setState(stDefendingBase);
 
3896
        
 
3897
        setPhase(phMoveToLoc, NONE);
 
3898
 
 
3899
        //move to base
 
3900
        updateStateCoord(baseX,baseY);
 
3901
 
 
3902
        enemy = me;
 
3903
        counterEnemy = _counterEnemy;
 
3904
 
 
3905
        dbg("DEFENDING: defend mode on (enemy = " & counterEnemy & ")", me);
 
3906
}
 
3907
 
 
3908
function void startHelpAlly(int _allyToHelp, int _helpx, int _helpy)
 
3909
{
 
3910
        enemy = _allyToHelp;            //store it in the enemy var, since he invoked this state
 
3911
 
 
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);
 
3914
 
 
3915
        circlePerimPoint(_helpx, _helpy, ref sendForceX, ref sendForceY, sendHelpRange);
 
3916
 
 
3917
        //sendForceX = _helpx;  //curBase[enemy][0];    //allyInThreat
 
3918
        //sendForceY = _helpy;  //curBase[enemy][1];    //allyInThreat
 
3919
 
 
3920
        if((sendForceX <= 0) or (sendForceY <= 0))
 
3921
        {
 
3922
                MsgBox("startHelpAlly() - sendForceX <= 0");
 
3923
                exit;
 
3924
        }
 
3925
 
 
3926
        setState(stHelpingAlly);
 
3927
 
 
3928
        setPhase(phMoveToLoc, NONE);
 
3929
 
 
3930
        helpTime = maxHelpTime;         //limited time we can help this ally or can stuck forever
 
3931
 
 
3932
        /* Set minimum number of defenders to leave in the base */
 
3933
        updateNumDefenders();
 
3934
 
 
3935
        dbg("helping " & getPlayerName(enemy) & " !!!!!!!!!!!!!!!!!!!!!!!!", me);       //allyInThreat
 
3936
 
 
3937
        /* Add required number of units from defendGr to sendAttackGr */
 
3938
        fillHelpers();
 
3939
 
 
3940
        //selectGroup(sendAttackGr, TRUE);
 
3941
 
 
3942
 
 
3943
        //ToDo: <check if enough attackers and send to the ally player base>
 
3944
        //ToDo: <send message to ally>
 
3945
 
 
3946
        //orderGroupLoc(sendAttackGr, DORDER_SCOUT, curBase[enemy][0], curBase[enemy][1]);      //allyInThreat
 
3947
}
 
3948
 
 
3949
function void manageHelpAlly()
 
3950
{
 
3951
        local bool _bFoundTarget;
 
3952
 
 
3953
        ASSERT(enemy >= 0, "manageHelpAlly: wrong ally index (" & enemy & ")", me);
 
3954
 
 
3955
        dbg("manageHelpAlly", me);
 
3956
 
 
3957
        if(enemy == none)
 
3958
        {
 
3959
                stopAllyDefense();
 
3960
                ASSERT(FALSE,"manageHelpAlly() - no player set", me);
 
3961
                exit;
 
3962
        }
 
3963
 
 
3964
        if((sendForceX <= 0) or (sendForceY <= 0))
 
3965
        {
 
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);
 
3969
 
 
3970
                stopAllyDefense();
 
3971
 
 
3972
                //MsgBox("manageHelpAlly() - sendForceX not initialized");
 
3973
                exit;
 
3974
        }
 
3975
 
 
3976
        if(not knowBase[enemy])         //no visible structures left for this ally
 
3977
        {
 
3978
                notifyAllies(getPlayerName(enemy) & ", I don't see your base" , false); //allyInThreat
 
3979
                dbg("manageHelpAlly - not haveBase", me);
 
3980
 
 
3981
                stopAllyDefense();
 
3982
                exit;
 
3983
        }
 
3984
 
 
3985
        //--------------------------------------
 
3986
        //Manage Attack
 
3987
        //--------------------------------------
 
3988
        if(phase == phAttackingLoc)
 
3989
        {
 
3990
                /* Attack any ally's base intruders */
 
3991
                defendArea(attackGr, sendHelpRange, sendForceX, sendForceY, defendCorridor, 1);
 
3992
        }
 
3993
}
 
3994
 
 
3995
//--------------------------------------------------------
 
3996
//Add required number of units from defendGr to attackGr
 
3997
//--------------------------------------------------------
 
3998
/*  function void fillAttackers(bool _highPriorityTask)
 
3999
{
 
4000
        local   int             _numDefenders;
 
4001
        //_highPriorityTask - if task is a high priority, then use more units
 
4002
 
 
4003
        //don't leave BBs in defend group
 
4004
        sortOutBBs();
 
4005
 
 
4006
        _numDefenders = groupSizeCmds(defendGr,false,true) - numDefenders;
 
4007
        if(_highPriorityTask)
 
4008
        {
 
4009
                _numDefenders = groupSizeCmds(defendGr,false,true) - minDefenders;      //leave less units in the base
 
4010
        }
 
4011
 
 
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
 
4015
        {
 
4016
                groupAddDroid(sendAttackGr, tempDroid);
 
4017
                _numDefenders = _numDefenders - 1;
 
4018
                tempDroid = iterateGroupCmd(defendGr);
 
4019
        }
 
4020
 
 
4021
        selectGroup(sendAttackGr, TRUE);
 
4022
} */
 
4023
 
 
4024
function void fillAttackers(int _numAttackers)
 
4025
{
 
4026
        local   DROID   _droid;
 
4027
        local   int     _bucket,_numBBs;
 
4028
 
 
4029
        //don't leave BBs in defend group
 
4030
        _numBBs = sortOutBBs();
 
4031
 
 
4032
        // subtract BBs
 
4033
        _numAttackers = _numAttackers - _numBBs;
 
4034
 
 
4035
        _bucket = initIterateGroupCmd(defendGr,true,false,true);
 
4036
        _droid = iterateGroupCmd(defendGr, _bucket);
 
4037
        while((_droid != NULLOBJECT) and (_numAttackers > 0))
 
4038
        {
 
4039
                groupAddDroid(sendAttackGr, _droid);
 
4040
                _numAttackers--;
 
4041
                _droid = iterateGroupCmd(defendGr, _bucket);
 
4042
        }
 
4043
 
 
4044
        selectGroup(sendAttackGr, TRUE);
 
4045
}
 
4046
 
 
4047
function int numAttackersFromPriorty(bool _highPriorityTask)
 
4048
{
 
4049
        local int       _numAttackers;
 
4050
 
 
4051
 
 
4052
        if(_highPriorityTask)
 
4053
        {
 
4054
                _numAttackers = groupSizeCmds(defendGr,true,false,true) - minDefenders; //leave less units in the base
 
4055
        }
 
4056
        else
 
4057
        {
 
4058
                _numAttackers = groupSizeCmds(defendGr,true,false,true) - numDefenders;
 
4059
        }
 
4060
 
 
4061
        return _numAttackers;
 
4062
}
 
4063
 
 
4064
//--------------------------------------------------------
 
4065
//Add required number of units from defendGr to attackGr
 
4066
//--------------------------------------------------------
 
4067
function void fillReinforcements(bool _bHelping)
 
4068
{
 
4069
        dbg("MANAGE UNITS: sending reinforcements", me);
 
4070
 
 
4071
        //fillAttackers(numAttackersFromPriorty(_bHelping));    //reinforcements have high priority ONLY if defendig ally
 
4072
 
 
4073
        prepareAttackers(_bHelping);
 
4074
 
 
4075
        //Take care of statistic stuff
 
4076
        if((state != stTakingOil) and !helpingAlly() and !defendingOil())
 
4077
        {
 
4078
                reinfCount[enemy] = reinfCount[enemy] + 1;
 
4079
                tempReinfCount[enemy] = tempReinfCount[enemy] + 1;
 
4080
        }
 
4081
 
 
4082
        if((state == stAttacking) or (state == stTakingOil))
 
4083
        {
 
4084
                reinfTime = maxReinfTime;       //restart "cancel attack" countdown
 
4085
        }
 
4086
}
 
4087
 
 
4088
function void fillHelpers()
 
4089
{
 
4090
        // prepare helpers
 
4091
        prepareAttackers(true);
 
4092
 
 
4093
/*      //don't leave BBs in defend group
 
4094
        sortOutBBs();
 
4095
 
 
4096
        temp = groupSizeCmds(defendGr,true,false,true) - minDefenders;          //send more units if sent not enough
 
4097
 
 
4098
        if((temp + groupSizeCmds(attackGr,true,false,true) + groupSizeCmds(sendAttackGr,true,false,true)) > (numDefenders * 3))
 
4099
        {
 
4100
                temp = groupSizeCmds(defendGr,true,false,true) - numDefenders;
 
4101
        }
 
4102
 
 
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
 
4106
        {
 
4107
                groupAddDroid(sendAttackGr, tempDroid);
 
4108
                temp = temp - 1;
 
4109
                tempDroid = iterateGroupCmd(defendGr);
 
4110
        }
 
4111
 
 
4112
        selectGroup(sendAttackGr, TRUE);
 
4113
*/
 
4114
}
 
4115
 
 
4116
//---------------------------------------------------------
 
4117
//      For all trucks with build orders, if there's a
 
4118
//      closer idle truck, use it instead
 
4119
//---------------------------------------------------------
 
4120
function void closerTruck()
 
4121
{
 
4122
        range = (25 * 128);
 
4123
 
 
4124
        initIterateGroupB(buildGr, 0);
 
4125
        droid = iterateGroupB(buildGr, 0);
 
4126
        while(droid != NULLOBJECT)
 
4127
        {
 
4128
                //if((droid.action == DACTION_MOVETOBUILD) and (droid.stat != NULLSTAT))                //has a build order
 
4129
                if(droid.action == DACTION_MOVETOBUILD)
 
4130
                {
 
4131
                        //pointless, if too close already
 
4132
                        result = distBetweenTwoPoints(droid.orderx, droid.ordery, droid.x, droid.y);
 
4133
                        if(result > range)              //will build soon
 
4134
                        {
 
4135
 
 
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)
 
4140
                                {
 
4141
                                        if((droid2.order == DORDER_NONE) or (droid2.order == DORDER_RTB))
 
4142
                                        {
 
4143
                                                result2 = distBetweenTwoPoints(droid.orderx, droid.ordery, droid2.x, droid2.y);
 
4144
                                                if((result - result2) > range)  //the second one is much closer
 
4145
                                                {
 
4146
                                                        //build what first droid was going to build
 
4147
 
 
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
 
4151
                                                }
 
4152
                                        }
 
4153
                                        droid2 = iterateGroupB(buildGr, 1);
 
4154
                                }
 
4155
                        }
 
4156
                }
 
4157
 
 
4158
                droid = iterateGroupB(buildGr, 0);
 
4159
        }
 
4160
}
 
4161
 
 
4162
function STRUCTURE closestDerrick(int _x, int _y)
 
4163
{
 
4164
        local   int                             _bestDist,_tempDist;
 
4165
        local   STRUCTURE               _closestDerrick,_tempDerrick;
 
4166
 
 
4167
        _bestDist = 99999;
 
4168
 
 
4169
        _closestDerrick = NULLOBJECT;
 
4170
 
 
4171
        initEnumStruct(FALSE,derrick,me,me);
 
4172
        _tempDerrick = enumStruct();
 
4173
        while(_tempDerrick != NULLOBJECT)
 
4174
        {
 
4175
                _tempDist = distBetweenTwoPoints(_tempDerrick.x, _tempDerrick.y, _x, _y);
 
4176
                if(_tempDist < _bestDist)       //already going to some derrick
 
4177
                {
 
4178
                        _closestDerrick = _tempDerrick;
 
4179
                        _bestDist = _tempDist;
 
4180
                }
 
4181
 
 
4182
                _tempDerrick = enumStruct();
 
4183
        }
 
4184
 
 
4185
        return _closestDerrick;
 
4186
}
 
4187
 
 
4188
function FEATURE closestOilResource(int _x, int _y)
 
4189
{
 
4190
        local   int                             _bestDist,_tempDist;
 
4191
        local   FEATURE                 _closestOil,_tempOil;
 
4192
 
 
4193
        _bestDist = 99999;
 
4194
 
 
4195
        _closestOil = NULLOBJECT;
 
4196
 
 
4197
        // check oil resources
 
4198
        initGetFeature(oilRes,me,me);
 
4199
        _tempOil = getFeatureB(me);
 
4200
        while(_tempOil != NULLOBJECT)
 
4201
        {
 
4202
                _tempDist = distBetweenTwoPoints(_tempOil.x, _tempOil.y, _x, _y);
 
4203
                if(_tempDist < _bestDist)       //already going to some derrick
 
4204
                {
 
4205
                        _tempOil = _tempOil;
 
4206
                        _bestDist = _tempDist;
 
4207
                }
 
4208
                _tempOil = getFeatureB(me);
 
4209
        }
 
4210
 
 
4211
        return _closestOil;
 
4212
}
 
4213
 
 
4214
function int findBestDefense()
 
4215
{
 
4216
        //return        - defense index
 
4217
        /* find best defense */
 
4218
        _temp2 = none;
 
4219
        _temp = 0;
 
4220
        while(_temp < numDef)
 
4221
        {
 
4222
                if(isStructureAvailable(def[_temp],me))
 
4223
                {
 
4224
                        _temp2 = _temp;         //Best defense
 
4225
                }
 
4226
                _temp = _temp + 1;
 
4227
        }
 
4228
 
 
4229
        return(_temp2);
 
4230
}
 
4231
 
 
4232
//---------------------------------------------------------
 
4233
//      Build oil defenses
 
4234
//---------------------------------------------------------
 
4235
event buildNormalOilDefenses(inactive)
 
4236
{
 
4237
        if(defendingBase()){exit;}
 
4238
 
 
4239
        if(idleGroupCmd(buildGr,true,false) == 0){exit;}
 
4240
 
 
4241
        /* find best defense */
 
4242
        best = findBestDefense();
 
4243
 
 
4244
        if(best == none){exit;}
 
4245
 
 
4246
        /* make sure not too many trucks are busy with defenses */
 
4247
        result = numBuildingNoBaseDefenses();
 
4248
 
 
4249
        if(result >= maxOilDefenseTrucks)
 
4250
        {
 
4251
                exit;
 
4252
        }
 
4253
 
 
4254
        /* set number of defenses allowed */
 
4255
        count = numOilDef;
 
4256
        // count = minOilDef;
 
4257
        // if(playerPower(me) >= highPower)
 
4258
        // {
 
4259
                // count = maxOilDef;
 
4260
        // }
 
4261
 
 
4262
 
 
4263
        /* find undefended derrick */
 
4264
        initEnumStruct(FALSE,derrick,me,me);
 
4265
        structure = enumStruct();
 
4266
        while(structure != NULLOBJECT)
 
4267
        {
 
4268
                /* check if this derrick has a defense location stored */
 
4269
                result = getOilDefendLocIndex(me, structure.x, structure.y);
 
4270
 
 
4271
                if((result < 0) or (not bLearn))                //no defense loc stored for this derrick
 
4272
                {
 
4273
                        /* check if too many defenses around already */
 
4274
                        result = numFriendlyWeapStructsInRange(me, structure.x, structure.y, RANGE_ALL_OIL_DEFENSES, false);
 
4275
                        if(result < count)
 
4276
                        {
 
4277
                                /* make sure derrick is not in the base */
 
4278
                                //result = isInMyBase(structure.x, structure.y);
 
4279
 
 
4280
                                if(!isInMyBase(structure.x, structure.y))
 
4281
                                {
 
4282
                                        /* is anyone already on the way to build something nearby? */
 
4283
                                        //result =buildingSiteBlocked(NULLOBJECT, range, structure.x, structure.y);
 
4284
 
 
4285
                                        if(!buildingSiteBlocked(NULLOBJECT, RANGE_ALL_OIL_DEFENSES, structure.x, structure.y, true))    //anyone going to do ANYTHIN Gon that spot?
 
4286
                                        {
 
4287
                                                /* build the normal way */
 
4288
                                                dbg("building oil defense the normal way at " & (structure.x / 128) & " - " & (structure.y / 128), me);
 
4289
 
 
4290
                                                buildOnMap(def[best], structure.x, structure.y, 1);
 
4291
                                        }
 
4292
                                }
 
4293
                        }
 
4294
                }
 
4295
 
 
4296
                structure = enumStruct();
 
4297
        }
 
4298
}
 
4299
 
 
4300
/* Build a single defense for a single derrick */
 
4301
function bool buildDerrickDefence(STRUCTURE _derrick, DROID _truck)
 
4302
{
 
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
        //--------------------------------------------------------
 
4308
 
 
4309
        /* find _bestDefIndex defense */
 
4310
        _bestDefIndex = findBestDefense();
 
4311
 
 
4312
        if(_bestDefIndex == none){
 
4313
                return false;
 
4314
        }
 
4315
 
 
4316
        /* make sure derrick is not in the base */
 
4317
        //result = isInMyBase(_derrick.x, _derrick.y);
 
4318
 
 
4319
        if(!DEFEND_BASE_DERRICKS and isInMyBase(_derrick.x, _derrick.y)){       //in base, so exit
 
4320
                return false;
 
4321
        }
 
4322
 
 
4323
        /* is anyone already on the way to build something nearby? */
 
4324
        //result = buildingSiteBlocked(_truck, oilDefensesRange, _derrick.x, _derrick.y);
 
4325
 
 
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)
 
4328
        }
 
4329
 
 
4330
 
 
4331
        /* check if too many defenses around already */
 
4332
        _numFreandlyDefenses = numFriendlyWeapStructsInRange(me, _derrick.x, _derrick.y, RANGE_ALL_OIL_DEFENSES, false);
 
4333
 
 
4334
        /* make sure not too many trucks are busy with defenses */
 
4335
        //result = numBuildingNoBaseDefenses();
 
4336
 
 
4337
        //if((result >= maxOilDefenseTrucks) and (_numFreandlyDefenses >= 1))
 
4338
        if(_numFreandlyDefenses >= numOilDef)
 
4339
        {
 
4340
                return false;           //has basic defense, so exit
 
4341
        }
 
4342
 
 
4343
        if(bLearn)
 
4344
        {
 
4345
                // check if this derrick has a defense location stored
 
4346
                _oilDefLocIndex = getOilDefendLocIndex(me, _derrick.x, _derrick.y);
 
4347
 
 
4348
                if(_oilDefLocIndex >= 0)                //we have a defense loc stored for this derrick
 
4349
                {
 
4350
                        /* check if priority is high enough */
 
4351
                        if(recallOilDefendLoc(me, _oilDefLocIndex, ref _x, ref _y, ref _oilRecallPrior))        //get priority
 
4352
                        {
 
4353
                                if(_oilRecallPrior >= minOilRecallPrior)        //prior high enough
 
4354
                                {
 
4355
                                        circlePerimPoint(_derrick.x, _derrick.y, ref _x, ref _y, DEFENSE_DIST_FROM_OIL);
 
4356
 
 
4357
                                        if(pickStructLocation(def[_bestDefIndex], ref _x, ref _y, me))
 
4358
                                        {
 
4359
                                                orderDroidStatsLoc(_truck, DORDER_BUILD, def[_bestDefIndex], _x, _y);
 
4360
                                                return true;
 
4361
                                        }
 
4362
                                }
 
4363
                        }
 
4364
                }
 
4365
        }
 
4366
 
 
4367
        if(_numFreandlyDefenses >= numOilDef){
 
4368
                return false;   //already has a basic defence, so exit
 
4369
        }
 
4370
 
 
4371
        /* this derrick doesn't have a defense loc, build the normal way */
 
4372
        _buildX = _derrick.x;
 
4373
        _buildY = _derrick.y;
 
4374
 
 
4375
        if(pickStructLocation(def[_bestDefIndex], ref _buildX, ref _buildY, me))
 
4376
        {
 
4377
                orderDroidStatsLoc(_truck, DORDER_BUILD, def[_bestDefIndex], _buildX, _buildY);
 
4378
                return true;
 
4379
        }
 
4380
 
 
4381
        return false;
 
4382
}
 
4383
 
 
4384
event defendOil(inactive)
 
4385
{
 
4386
        local   int             _numDefensesToBuild,_maxDefRange,_totalOil;
 
4387
        local   STRUCTURE       _closestDerrick;
 
4388
        local   DROID           _nullTruck;
 
4389
 
 
4390
        if(not bLearn){exit;}
 
4391
 
 
4392
        if(defendingBase()){exit;}
 
4393
 
 
4394
        if(idleGroupCmd(buildGr,true,false) == 0){exit;}        //no trucks
 
4395
 
 
4396
        /* make sure not too many trucks are busy with defenses */
 
4397
        result = numBuildingNoBaseDefenses();
 
4398
 
 
4399
        if(result >= maxOilDefenseTrucks)
 
4400
        {
 
4401
                exit;
 
4402
        }
 
4403
 
 
4404
        result = 0;
 
4405
        count = 0;
 
4406
        best = none;
 
4407
        while(count < numDef)
 
4408
        {
 
4409
                result2 = numStatBusy(def[count], TRUE);        //How many trucks are busy with defenses
 
4410
                result = result + result2;
 
4411
 
 
4412
                count = count + 1;
 
4413
        }
 
4414
 
 
4415
        /* find best defense */
 
4416
        best = findBestDefense();
 
4417
 
 
4418
        if(best == none){exit;}         //no defenses available
 
4419
 
 
4420
        if(result > maxOilDefenseTrucks){exit;}         //too many busy
 
4421
 
 
4422
        result = 99999;
 
4423
 
 
4424
        //Go through remembered oil defense locations
 
4425
        //------------------------------------------------
 
4426
        count2 = getOilDefendLocCount();
 
4427
 
 
4428
        count = 0;
 
4429
        count4 = 0;
 
4430
        while((count < count2) and (count4 < MAX_OIL_DEFENSES_SIDES))   //pick max 3 locs
 
4431
        {
 
4432
                if(recallOilDefendLoc(me, count, ref x, ref y, ref result))             //if this one stored
 
4433
                {
 
4434
                        if(result >= minOilRecallPrior) //at least priority of 3
 
4435
                        {
 
4436
                                //find oil derrick which is supposed to be defended (closest one)
 
4437
                                //---------------------------------------------------------------
 
4438
                                _closestDerrick = closestDerrick(x, y);
 
4439
 
 
4440
                                if(_closestDerrick != NULLOBJECT)       //found anything?
 
4441
                                {
 
4442
                                        buildX = _closestDerrick.x;
 
4443
                                        buildY = _closestDerrick.y;
 
4444
 
 
4445
                                        //make sure derrick is not in the base
 
4446
                                        //result = isInMyBase(buildX, buildY);
 
4447
 
 
4448
                                        if(!isInMyBase(buildX, buildY)) //not in base
 
4449
                                        {
 
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
 
4452
 
 
4453
                                                // count how many oil resources we are going to defend
 
4454
                                                _totalOil = numTotalOilInRange(_closestDerrick.x, _closestDerrick.y, (TILE * 3));
 
4455
 
 
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));
 
4458
 
 
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
 
4461
                                                {
 
4462
                                                        buildX = x;     //remember coords before using pickStructLocation() to check if corrected coords too far away
 
4463
                                                        buildY = y;
 
4464
 
 
4465
                                                        //MsgBox("11");
 
4466
                                                        if(pickStructLocation(def[best], ref buildX, ref buildY, me))
 
4467
                                                        {
 
4468
                                                                //Make sure not too many building already
 
4469
                                                                //--------------------------------------------
 
4470
                                                                retInt = numTrucksOrderInRange(buildX, buildY, RANGE_ALL_OIL_DEFENSES, DORDER_BUILD);
 
4471
 
 
4472
                                                                if(retInt < MAX_TRUCKS_PER_OIL_DEFENSE) //max 1
 
4473
                                                                {
 
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
 
4477
                                                                        {
 
4478
                                                                                //MsgBox("22");
 
4479
                                                                                intOK[count4] = count;
 
4480
                                                                                //MsgBox("33");
 
4481
                                                                                count4 = count4 + 1;            //picked another one
 
4482
                                                                        }
 
4483
                                                                }
 
4484
                                                        }
 
4485
                                                }
 
4486
                                        }
 
4487
                                }
 
4488
                        }
 
4489
                }
 
4490
                count = count + 1;
 
4491
        }
 
4492
 
 
4493
        //MsgBox("2");
 
4494
 
 
4495
        if(count4 == 0){exit;}          //couldn't find anything
 
4496
 
 
4497
        //Now choose a random location from the picked ones
 
4498
        //-------------------------------------------------
 
4499
        result = intOK[random(count4 - 1)];
 
4500
 
 
4501
        // now recall defend location and build defenses
 
4502
        bDummy = buildOilDefenseFromExperience(result, _nullTruck);
 
4503
}
 
4504
 
 
4505
function bool buildOilDefenseFromExperience(int _index, DROID _truck)
 
4506
{
 
4507
        local   int                     _prior,_defx,_defy;
 
4508
        local   STRUCTURE       _closestDerrick;
 
4509
 
 
4510
        recallOilDefendLoc(me, _index, ref _defx, ref _defy, ref _prior);
 
4511
 
 
4512
        //find oil derrick which is supposed to be defended (closest one)
 
4513
        //---------------------------------------------------------------
 
4514
        _closestDerrick = closestDerrick(_defx, _defy);
 
4515
 
 
4516
        if(_closestDerrick == NULLOBJECT)       //found anything?
 
4517
        {
 
4518
                dbg("defendOil() - couldn't find closest derrick !!!!!!!!!!!!!!!!", me);
 
4519
                return false;
 
4520
        }
 
4521
 
 
4522
        // build a defense
 
4523
        bDummy = buildOilDefense(_defx, _defy, _closestDerrick.x, _closestDerrick.y, _truck);
 
4524
 
 
4525
        return true;
 
4526
}
 
4527
 
 
4528
function bool buildOilDefense(int _buildX, int _buildY, int _oilx,
 
4529
                                                                int _oily, DROID _truck)
 
4530
{
 
4531
        local   STRUCTURE       _closestDerrick;
 
4532
        local   int                     _x,_y,_closestDist,_bucket,_dist,_dist2;
 
4533
        local   bool            _bFound,_bResult2;
 
4534
        local   DROID           _droid2,_droid3;
 
4535
 
 
4536
        //find oil derrick which is supposed to be defended (closest one)
 
4537
        //---------------------------------------------------------------
 
4538
        // _closestDerrick = closestDerrick(_oilx, _oily);
 
4539
 
 
4540
        // if(_closestDerrick != NULLOBJECT)    //found anything?
 
4541
        // {
 
4542
                // buildX = _closestDerrick.x;
 
4543
                // buildY = _closestDerrick.y;
 
4544
        // }
 
4545
        // else
 
4546
        // {
 
4547
                // dbg("buildOilDefense() - couldn't find closest derrick !!!!!!!!!!!!!!!!", me);
 
4548
                // return false;
 
4549
        // }
 
4550
 
 
4551
        //move locations to the base perimeter
 
4552
        circlePerimPoint(_oilx, _oily, ref _buildX, ref _buildY, DEFENSE_DIST_FROM_OIL);
 
4553
 
 
4554
 
 
4555
        //if(structure2 == NULLOBJECT){exit;}   //no derrick found
 
4556
 
 
4557
        if(_truck == NULLOBJECT)
 
4558
        {
 
4559
                //Now find the closest truck
 
4560
                //---------------------------------------------
 
4561
                _closestDist = 99999;
 
4562
                _bFound = FALSE;        //found any?
 
4563
 
 
4564
                _droid2 = NULLOBJECT;
 
4565
                _droid3 = NULLOBJECT;
 
4566
 
 
4567
                //MsgBox("4");
 
4568
 
 
4569
                _bucket = initIterateGroupCmd(buildGr,true,false,true);
 
4570
                _truck = iterateGroupCmd(buildGr,_bucket);
 
4571
                while(_truck != NULLOBJECT)
 
4572
                {
 
4573
                        _dist2 = distBetweenTwoPoints(_truck.x, _truck.y, _buildX, _buildY);
 
4574
 
 
4575
                        if(_dist2 < _closestDist)       //closer
 
4576
                        {
 
4577
                                if(droidOrderIdle(_truck))
 
4578
                                {
 
4579
                                        _droid2 = _truck;               //totally idle
 
4580
                                        _closestDist = _dist2;
 
4581
                                        _bFound = TRUE;
 
4582
                                }
 
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))
 
4585
                                {
 
4586
                                        _bResult2 = TRUE;               //can take this truck
 
4587
                                        if(_truck.stat == derrick)
 
4588
                                        {
 
4589
                                                _bResult2 = FALSE;              //don't touch him, probably going far
 
4590
                                        }
 
4591
                                        else
 
4592
                                        {
 
4593
                                                initEnumStruct(FALSE,derrick,me,me);
 
4594
                                                structure = enumStruct();
 
4595
                                                while((structure != NULLOBJECT) and (_bResult2))
 
4596
                                                {
 
4597
                                                        //skip derricks in the base
 
4598
                                                        //result3 = isInMyBase(structure.x, structure.y);
 
4599
                                                        if(!isInMyBase(structure.x, structure.y))               //not in base
 
4600
                                                        {
 
4601
                                                                if(distBetweenTwoPoints(_truck.orderx, _truck.ordery, structure.x, structure.y) < oilDefensesRange)     //already going to some derrick
 
4602
                                                                {
 
4603
                                                                        _bResult2 = FALSE;      //don't touch this truck, going far already
 
4604
                                                                }
 
4605
                                                        }
 
4606
 
 
4607
                                                        structure = enumStruct();
 
4608
                                                }
 
4609
                                        }
 
4610
 
 
4611
                                        if(_bResult2)   //safe to 'kidnap' this busy truck
 
4612
                                        {
 
4613
                                                _droid3 = _truck;               //remember this one too
 
4614
                                                _closestDist = _dist2;
 
4615
                                                _bFound = TRUE;
 
4616
                                        }
 
4617
                                }
 
4618
                        }
 
4619
                        _truck = iterateGroupCmd(buildGr,_bucket);
 
4620
                }
 
4621
 
 
4622
                //MsgBox("5");
 
4623
 
 
4624
 
 
4625
                //no trucks
 
4626
                if(!_bFound)
 
4627
                {
 
4628
                        dbg("buildOilDefense() - no idle trucks (MUST BE SOME!)", me);
 
4629
                        return false;
 
4630
                }
 
4631
 
 
4632
                //decide which _truck to take
 
4633
                //-----------------------------------------
 
4634
                _truck = _droid2;               //default
 
4635
                if((_droid2 != NULLOBJECT) and (_droid3 != NULLOBJECT))         //which of 2?
 
4636
                {
 
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);
 
4640
 
 
4641
                        if((_dist - _dist2) > (TILE * 12))              //busy one is much closer
 
4642
                        {
 
4643
                                _truck = _droid3;
 
4644
                        }
 
4645
                }
 
4646
                else if(_droid3 != NULLOBJECT)
 
4647
                {
 
4648
                        _truck = _droid3;
 
4649
                }
 
4650
        }
 
4651
 
 
4652
        if(_truck == NULLOBJECT)
 
4653
        {
 
4654
                return false;
 
4655
        }
 
4656
 
 
4657
        // build a defense
 
4658
        if(pickStructLocation(def[best], ref _buildX, ref _buildY, me))
 
4659
        {
 
4660
                orderDroidStatsLoc(_truck, DORDER_BUILD, def[best], _buildX, _buildY);
 
4661
 
 
4662
                return true;
 
4663
        }
 
4664
        //buildOnMap(def[best], _x, _y, 1);
 
4665
 
 
4666
        return false;
 
4667
}
 
4668
 
 
4669
 
 
4670
//take over enemy derricks
 
4671
function STRUCTURE findEnemyDerrick(int _targetPlayer)
 
4672
{
 
4673
        local   int             _numAttackers,_numEnemies;
 
4674
        local   STRUCTURE       _enemyDerrick;
 
4675
 
 
4676
        //find enemy derrick
 
4677
        _enemyDerrick = findBestEnemyDerrick(_targetPlayer, numAvailableAttackers(),
 
4678
                                                        baseX, baseY, -1);
 
4679
 
 
4680
        //if none found
 
4681
        if(_enemyDerrick == NULLOBJECT){
 
4682
                return _enemyDerrick;
 
4683
        }
 
4684
 
 
4685
        //_enemyDerrick = retStruct;
 
4686
 
 
4687
        dbg("findEnemyDerrick() - found derrick", me);
 
4688
 
 
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);
 
4692
 
 
4693
        if(_numAttackers < (_numEnemies + 1))
 
4694
        {
 
4695
                _enemyDerrick = NULLOBJECT;             //clear
 
4696
                dbg("TAKE OIL: not enough attackers for this oil", me);
 
4697
                return _enemyDerrick;           //too many enemies around
 
4698
        }
 
4699
 
 
4700
        dbg("findEnemyDerrick()- safe", me);
 
4701
 
 
4702
        //enemy = _enemyDerrick.player;
 
4703
 
 
4704
        //sendForceX = _enemyDerrick.x;
 
4705
        //sendForceY = _enemyDerrick.y;
 
4706
 
 
4707
        return _enemyDerrick;
 
4708
}
 
4709
 
 
4710
//find closest enemy derrick with litte defense
 
4711
function STRUCTURE findBestEnemyDerrick(int _targetPlayer, int _numAttackers,
 
4712
                                                                                int _centerx, int _centery, int _maxRange)
 
4713
{
 
4714
        local int _numEnemies,_enemy,_x,_y,_dist,_dist2,_dist3;
 
4715
        retStruct = NULLOBJECT;
 
4716
 
 
4717
        tempResult2 = 99999;    //best weight
 
4718
 
 
4719
        _enemy = 0;
 
4720
        while(_enemy < multiPlayerMaxPlayers)
 
4721
        {
 
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
 
4725
                {
 
4726
                        initEnumStruct(false,derrick,_enemy,me);
 
4727
                        tempStruct = enumStruct();
 
4728
                        while(tempStruct != NULLOBJECT)
 
4729
                        {
 
4730
                                // make sure oil derrick is in set range
 
4731
                                if( (_maxRange <= 0) or
 
4732
                                        (distBetweenTwoPoints(tempStruct.x, tempStruct.y,
 
4733
                                        _centerx, _centery) < _maxRange) )
 
4734
                                {
 
4735
                                        _x = tempStruct.x;
 
4736
                                        _y = tempStruct.y;
 
4737
 
 
4738
                                        //don't choose if near an enemy base, since might have units nearby, which we don't see
 
4739
                                        //temp4 = isNearEnemyBase(x, y);
 
4740
 
 
4741
                                        if(not isNearEnemyBase(_x, _y))
 
4742
                                        {
 
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
 
4746
                                                {
 
4747
                                                        _dist = distBetweenTwoPoints(_x, _y, _centerx, _centery) / 128; // my base-derrick distance
 
4748
 
 
4749
                                                        //enemy-derrick distance
 
4750
                                                        _dist2 = (_dist / 2) / 128;     //if don't know enemy base location
 
4751
                                                        if(knowBase[_enemy])
 
4752
                                                        {
 
4753
                                                                _dist2 = distBetweenTwoPoints(_x, _y, curBase[_enemy][0], curBase[_enemy][1]) / 128;
 
4754
                                                        }
 
4755
 
 
4756
                                                        _dist3 = distBetweenTwoPoints(_centerx, _centery, curBase[_enemy][0], curBase[_enemy][1]) / 128;        //my base-enemy base
 
4757
 
 
4758
                                                        //calculate
 
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;}
 
4762
 
 
4763
                                                        //if(not((temp4 < criticalAngle) and ((dist - baseRange) > dist3)))     //make sure not behind the enemy base
 
4764
                                                        //{
 
4765
                                                                //tempResult = (temp2 * defWeight) + dist - dist2 - temp4;      //calculate weight of the derrick
 
4766
 
 
4767
                                                                //calculate weight for this derrick (threat)
 
4768
                                                                tempResult = oilWeight(_enemy, _x, _y, _centerx, _centery);
 
4769
 
 
4770
                                                                if(tempResult < tempResult2)
 
4771
                                                                {
 
4772
                                                                        tempResult2 = tempResult;
 
4773
                                                                        retStruct = tempStruct;
 
4774
                                                                }
 
4775
                                                        //}
 
4776
                                                }
 
4777
 
 
4778
                                        }
 
4779
                                }
 
4780
 
 
4781
                                tempStruct = enumStruct();
 
4782
                        }
 
4783
                }
 
4784
                _enemy = _enemy + 1;
 
4785
        }
 
4786
 
 
4787
        return retStruct;
 
4788
}
 
4789
 
 
4790
function int oilWeight(int _owner, int _oilx, int _oily, int _centerx, int _centery)
 
4791
{
 
4792
        local int _range;
 
4793
 
 
4794
        _range = TILE * 12;     //must be same as in posWeight()
 
4795
 
 
4796
        retInt = posWeight(_owner, _oilx, _oily, _range, _centerx, _centery);
 
4797
 
 
4798
        retInt = retInt - 250 * numFeatByTypeInRange(me, 4, _oilx, _oily, _range);      //4 = FEAT_OIL_RESOURCE
 
4799
 
 
4800
        return(retInt);
 
4801
}
 
4802
 
 
4803
 
 
4804
//calc threat
 
4805
function int posWeight(int _owner, int _x, int _y, int _range,
 
4806
                                                                                        int _centerx, int _centery)
 
4807
{
 
4808
        _result = 0;    //threat
 
4809
        _temp2 = 100;   //more integer precision
 
4810
 
 
4811
        //base - pos
 
4812
        _dist = distBetweenTwoPoints(_centerx, _centery, _x, _y) / 128;
 
4813
 
 
4814
        if(_dist == 0)
 
4815
                _dist = 1;
 
4816
 
 
4817
        //derricks
 
4818
        _temp3 = numStructsByTypeInRange(me, me, REF_RESOURCE_EXTRACTOR, _x, _y, _range);
 
4819
 
 
4820
        if(_temp3 == 0)
 
4821
                _temp3 = 1;
 
4822
 
 
4823
        //my weight //*_temp2 for precision
 
4824
        _dist = (-1) * (weightDistFactor * _temp2) / (_dist / _temp3);
 
4825
 
 
4826
        _temp3 = (_dist / _temp2);
 
4827
        //dbg("my weight = " & _temp3, me);
 
4828
 
 
4829
        //enemy - pos
 
4830
        _dist2 = 0;     //if dead, no threat
 
4831
 
 
4832
        //check object enemy
 
4833
        if(_owner != none)              //not always need one
 
4834
        {
 
4835
                if((not dead[_owner]) and (not killedBase[_owner]))
 
4836
                {
 
4837
                        _dist2 = _dist; //neutralize if enemy base loc unknown
 
4838
                        if(knowBase[_owner])
 
4839
                        {
 
4840
                                _dist2 = distBetweenTwoPoints(curBase[_owner][0], curBase[_owner][1], _x, _y) / 128;
 
4841
                                //dbg("_dist2 = " & _dist2, me);
 
4842
                                _dist2 = (weightDistFactor * _temp2) / _dist2;
 
4843
                        }
 
4844
                }
 
4845
        }
 
4846
 
 
4847
        _temp3 = (_dist2 / _temp2);
 
4848
        //dbg("his weight = " & _temp3, me);
 
4849
 
 
4850
        //calc weight
 
4851
        _result = (_dist2 + _dist);
 
4852
 
 
4853
        _temp3 = (_result / _temp2);
 
4854
        //dbg("_result = " & _temp3, me);
 
4855
 
 
4856
        //check allies and all enemies
 
4857
        _temp = 0;
 
4858
        while(_temp < multiPlayerMaxPlayers)
 
4859
        {
 
4860
                if((_temp != me) and (_temp != _owner))
 
4861
                {
 
4862
                        /* Ally/Enemy */
 
4863
                        _temp3 = (-1);
 
4864
                        if(not allianceExistsBetween(_temp ,me))
 
4865
                        {
 
4866
                                _temp3 = 1;
 
4867
                        }
 
4868
 
 
4869
                        if(knowBase[_temp] and canSeePlayerBase(_temp)) //seeBase[] - otherwise this player might have been destroyed already or not loaded at all
 
4870
                        {
 
4871
                                _dist2 = distBetweenTwoPoints(curBase[_temp][0], curBase[_temp][1], _x, _y) / 128;
 
4872
                                if(_dist2 == 0){_dist2 = 1;}
 
4873
 
 
4874
                                _result = _result + (_temp3 * (weightDistFactor / 4 * _temp2)) / _dist2;        //weightDistFactor / 2 => allies and other enemies have less weight     //was /4
 
4875
                        }
 
4876
                }
 
4877
                _temp = _temp + 1;
 
4878
        }
 
4879
 
 
4880
        _result = _result / _temp2;
 
4881
 
 
4882
        //dbg("ally _result = " & _result, me);
 
4883
 
 
4884
        //also check enemy defenses nearby
 
4885
        _temp3 = numEnemyWeapObjInRange(me, _x, _y, (_range + TILE * 2), true, true);   //also check VTOLs
 
4886
 
 
4887
        //dbg("num defenses = " & _temp3, me);
 
4888
 
 
4889
        _result = _result + _temp3;
 
4890
 
 
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;
 
4894
 
 
4895
        return(_result);
 
4896
}
 
4897
 
 
4898
//---------------------------------------------------------
 
4899
//      Check if point is in base
 
4900
//---------------------------------------------------------
 
4901
function bool isInMyBase(int _checkX, int _checkY)
 
4902
{
 
4903
        if(distBetweenTwoPoints(_checkX, _checkY, baseX, baseY) > (baseRange + defendCorridor)) //not in the base
 
4904
        {
 
4905
                return(FALSE);
 
4906
        }
 
4907
 
 
4908
        return(TRUE);
 
4909
}
 
4910
 
 
4911
//---------------------------------------------------------
 
4912
//      Check if point is near anyone's base
 
4913
//---------------------------------------------------------
 
4914
function bool isNearAnyBase(int _x, int _y)
 
4915
{
 
4916
        _range = (25 * 128);
 
4917
 
 
4918
        _temp = 0;
 
4919
        while(_temp < multiPlayerMaxPlayers)
 
4920
        {
 
4921
                if(knowBase[_temp] and canSeePlayerBase(_temp)) //seeBase[] - otherwise this player might have been destroyed already or not loaded at all
 
4922
                {
 
4923
                        if(distBetweenTwoPoints(curBase[_temp][0], curBase[_temp][1], _x, _y) < _range)
 
4924
                        {
 
4925
                                return(TRUE);
 
4926
                        }
 
4927
                }
 
4928
                _temp = _temp + 1;
 
4929
        }
 
4930
 
 
4931
        return(FALSE);
 
4932
}
 
4933
 
 
4934
function bool isNearEnemyBase(int _x, int _y)
 
4935
{
 
4936
        local int _enemy,_range;
 
4937
 
 
4938
        _range = (TILE * 25);
 
4939
 
 
4940
        _enemy = 0;
 
4941
        while(_enemy < multiPlayerMaxPlayers)
 
4942
        {
 
4943
                if(not allianceExistsBetween(_enemy ,me))
 
4944
                {
 
4945
                        if(!dead[_enemy] and knowBase[_enemy] and canSeePlayerBase(_enemy))     //seeBase[] - otherwise this player might have been destroyed already or not loaded at all
 
4946
                        {
 
4947
                                if(distBetweenTwoPoints(curBase[_enemy][0], curBase[_enemy][1], _x, _y) < _range)
 
4948
                                {
 
4949
                                        return true;
 
4950
                                }
 
4951
                        }
 
4952
                }
 
4953
                _enemy = _enemy + 1;
 
4954
        }
 
4955
 
 
4956
        return false;
 
4957
}
 
4958
 
 
4959
//---------------------------------------------------------
 
4960
//      Returns TRUE if a base structures (not defense etc)
 
4961
//---------------------------------------------------------
 
4962
function bool isBaseStruct(STRUCTURE _checkStruct)
 
4963
{
 
4964
        if(_checkStruct == NULLOBJECT)
 
4965
        {
 
4966
                MsgBox("isBaseSTruct - _checkStruct is NULLOBJECT");
 
4967
                return(FALSE);
 
4968
        }
 
4969
 
 
4970
        temp = 0;
 
4971
        while(temp < numBaseStructs)
 
4972
        {
 
4973
                if(_checkStruct.stat == baseStructs[temp])
 
4974
                {
 
4975
                        return(TRUE);
 
4976
                }
 
4977
                temp = temp + 1;
 
4978
        }
 
4979
 
 
4980
        return(FALSE);
 
4981
}
 
4982
 
 
4983
//---------------------------------------------------------
 
4984
//      Build derricks
 
4985
//---------------------------------------------------------
 
4986
function void buildOil(bool _bInBaseOnly)
 
4987
{
 
4988
        local   FEATURE         _oil;
 
4989
        local   int                     _numBuildingOil;
 
4990
 
 
4991
        //dbg(" " & me & ")  Executing buildOil()");
 
4992
 
 
4993
        //How many trucks already working on derricks
 
4994
        _numBuildingOil = numStatBusy(derrick, true);   //How many trucks are busy with derricks
 
4995
 
 
4996
        _oil = NULLOBJECT;
 
4997
 
 
4998
        //dbg(" " & me & ")  right now building " & _numBuildingOil & " oil resoirces");
 
4999
 
 
5000
        if(_numBuildingOil < maxBuildOilTrucks) //Not too many
 
5001
        {
 
5002
                if(_bInBaseOnly){
 
5003
                        _oil = findBestOilToBuildOn(baseX, baseY, baseRange);   //Look near the base
 
5004
                }else{
 
5005
                        _oil = findBestOilToBuildOn(baseX, baseY, -1);                  //Normal way
 
5006
                }
 
5007
 
 
5008
                if(_oil != NULLOBJECT)
 
5009
                {
 
5010
                        //dbg(" " & me & ")  found unoccupied oil resource");
 
5011
 
 
5012
                        bDummy = buildUsingClosestTruck(derrick, _oil.x, _oil.y, 1);    //Can skip "buildOnMap" for oil
 
5013
                }
 
5014
        }
 
5015
 
 
5016
        //dbg(" " & me & ")  End buildOil()");
 
5017
}
 
5018
 
 
5019
/* Build oil near some location */
 
5020
function bool buildNextOil(DROID _truck, int _maxRange, bool _bClosestOil)
 
5021
{
 
5022
        local   int                     _oilDist,_bestDist,_bucket,_oilRange;
 
5023
        local   bool            _bCanBuild;
 
5024
        local   FEATURE         _oil,_bestOil;
 
5025
        local   DROID           _otherTruck;
 
5026
 
 
5027
        _bestDist = 99999;
 
5028
        _bestOil = NULLOBJECT;  //Not found right now
 
5029
 
 
5030
        _oilRange = _maxRange;  //max range to look for further oil
 
5031
        _bCanBuild = false;             //can we build using callback truck?
 
5032
 
 
5033
        if(_bClosestOil)
 
5034
        {
 
5035
                initGetFeature(oilRes,me,me);
 
5036
                _oil = getFeature(me);
 
5037
                while(_oil != NULLOBJECT)
 
5038
                {
 
5039
                        _oilDist = distBetweenTwoPoints(_truck.x, _truck.y, _oil.x, _oil.y);
 
5040
                        if(_oilDist < _oilRange)        //oil very near
 
5041
                        {
 
5042
                                if(_oilDist < _bestDist)        //closest one
 
5043
                                {
 
5044
                                        if(!buildingSiteBlocked(_truck, _maxRange, _oil.x, _oil.y, true))
 
5045
                                        {
 
5046
                                                //make sure not dangerous
 
5047
                                                if(!threatInRange(me, _oil.x, _oil.y, threatRange, false))
 
5048
                                                {
 
5049
                                                        _bestDist = _oilDist;
 
5050
                                                        _bestOil = _oil;        //Remember and return it
 
5051
                                                }
 
5052
                                                else
 
5053
                                                {
 
5054
                                                        dbg("dangerous to build more oil", me);
 
5055
                                                }
 
5056
                                        }
 
5057
                                        else
 
5058
                                        {
 
5059
                                                dbg("oil blocked", me);
 
5060
                                        }
 
5061
                                }
 
5062
                        }
 
5063
                        _oil = getFeature(me);
 
5064
                }
 
5065
        }
 
5066
        else
 
5067
        {
 
5068
                // if not looking for the best oil, just find the closest possible
 
5069
                _bestOil = findBestOilToBuildOn(_truck.x, _truck.y, _maxRange);
 
5070
        }
 
5071
 
 
5072
        //now check if any other trucks were sent to build there already
 
5073
        if(_bestOil != NULLOBJECT)      //found oil
 
5074
        {
 
5075
                _bCanBuild = true;
 
5076
 
 
5077
                _bucket = initIterateGroupCmd(buildGr,true,false,true);
 
5078
                _otherTruck = iterateGroupCmd(buildGr,_bucket);
 
5079
                while(_otherTruck != NULLOBJECT)
 
5080
                {
 
5081
                        if((_otherTruck.orderx == _bestOil.x) and (_otherTruck.ordery == _bestOil.y))
 
5082
                        {
 
5083
                                _bCanBuild = false;     //someone already going to build
 
5084
 
 
5085
                                //check if it's closer than callback _truck
 
5086
                                if(distBetweenTwoPoints(_otherTruck.x, _otherTruck.y, _bestOil.x, _bestOil.y) > _bestDist)
 
5087
                                {
 
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 !!!)
 
5091
                                }
 
5092
                        }
 
5093
                        _otherTruck = iterateGroupCmd(buildGr,_bucket);
 
5094
                }
 
5095
        }
 
5096
 
 
5097
        if(_bCanBuild)          //safe to build with callback _truck
 
5098
        {
 
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
 
5102
        }
 
5103
 
 
5104
        return false;
 
5105
}
 
5106
 
 
5107
//-----------------------------------------------------
 
5108
//Build ArgStrStat0 (passes STRUCTURESTAT) somewhere
 
5109
//-----------------------------------------------------
 
5110
function void buildOnMap(STRUCTURESTAT _statToBuild, int _buildX, int _buildY, int _maxTrucks)
 
5111
{
 
5112
        bTempResult = pickStructLocation(_statToBuild, ref _buildX, ref _buildY, me);
 
5113
        if(bTempResult)
 
5114
        {
 
5115
                bDummy = buildUsingClosestTruck(_statToBuild, _buildX, _buildY, _maxTrucks);            //can re-use all arguments
 
5116
        }
 
5117
}
 
5118
 
 
5119
function FEATURE findBestOilToBuildOn(int _lookx, int _looky, int _maxRange)
 
5120
{
 
5121
        local   FEATURE         _oil,_tempOil;
 
5122
        local   int                     _bestWeight,_tempWeight;
 
5123
 
 
5124
        //dbg(" " & me & ")  Executing findBestOilToBuildOn()");
 
5125
 
 
5126
        _oil = NULLOBJECT;      //Not found right now
 
5127
        _bestWeight = 99999;
 
5128
 
 
5129
        initGetFeature(oilRes,me,me);
 
5130
        _tempOil = getFeature(me);
 
5131
        while(_tempOil != NULLOBJECT)
 
5132
        {
 
5133
                //_tempWeight = distBetweenTwoPoints(temp3, temp4, _tempOil.x, _tempOil.y);
 
5134
                //if(_tempWeight < _bestWeight)
 
5135
                //{
 
5136
                        //make sure not dangerous
 
5137
                        if(not threatInRange(me, _tempOil.x, _tempOil.y, threatRange, false))
 
5138
                        {
 
5139
                                //Any trucks already were sent to build there?
 
5140
                                //temp5 = buildingSiteBlocked(NULLOBJECT, (5 * 128), _tempOil.x, _tempOil.y);   //anyone going there already?
 
5141
 
 
5142
                                if(not buildingSiteBlocked(NULLOBJECT, (TILE * 5), _tempOil.x, _tempOil.y, true))       //No one going there
 
5143
                                {
 
5144
                                        //make sure close enough to provided position
 
5145
                                        if(not ((_maxRange > 0) and
 
5146
                                                (distBetweenTwoPoints(_lookx, _looky, _tempOil.x, _tempOil.y) < _maxRange)))
 
5147
                                        {
 
5148
                                                _tempWeight = oilWeight(none, _tempOil.x, _tempOil.y,
 
5149
                                                                                        _lookx, _looky);
 
5150
 
 
5151
                                                if(_tempWeight < _bestWeight)
 
5152
                                                {
 
5153
                                                        _bestWeight = _tempWeight;
 
5154
                                                        _oil = _tempOil;        //Remember it
 
5155
                                                }
 
5156
                                        }
 
5157
                                }
 
5158
                        }
 
5159
                //}
 
5160
                _tempOil = getFeature(me);
 
5161
        }
 
5162
 
 
5163
        return _oil;
 
5164
 
 
5165
        //dbg(" " & me & ")  End findBestOilToBuildOn()");
 
5166
}
 
5167
 
 
5168
function bool needTrucks()
 
5169
{
 
5170
        local   int     _totalTrucks,_numHaveTrucks;
 
5171
 
 
5172
        // we always need at least minTrucks
 
5173
        if( !gettingMinTrucks() ){
 
5174
                return true;
 
5175
        }
 
5176
 
 
5177
        _numHaveTrucks = groupSizeCmds(buildGr,true,false,true);
 
5178
 
 
5179
        _totalTrucks = numBuildersInProduction(me) + _numHaveTrucks;
 
5180
 
 
5181
        if((idleGroupCmd(buildGr,true,false) == 0) and (_totalTrucks < MAX_BUILDERS)){
 
5182
                return true;
 
5183
        }
 
5184
 
 
5185
        return false;
 
5186
/*
 
5187
 
 
5188
        if(_totalTrucks >= maxTrucks)
 
5189
        {
 
5190
                return false;
 
5191
        }
 
5192
 
 
5193
        if(_totalTrucks < minTrucks)
 
5194
        {
 
5195
                return true;
 
5196
        }
 
5197
 
 
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))
 
5200
        {
 
5201
                return true;
 
5202
        }
 
5203
 
 
5204
        return false; */
 
5205
}
 
5206
 
 
5207
function void buildTrucks()
 
5208
{
 
5209
        local   int             _numBuilding,_haveTrucks,_tmplIndex,_totalTrucks,
 
5210
                                                _maxBuiltMinTrucks;
 
5211
        local   STRUCTURE       _factory;
 
5212
        local   bool            _bFoundTemplate,_bStartedBuilding;
 
5213
 
 
5214
        _haveTrucks = groupSizeCmds(buildGr,true,false,true);
 
5215
 
 
5216
        _numBuilding = numBuildersInProduction(me);     //How many builders are being built at the moment
 
5217
 
 
5218
        _totalTrucks = _haveTrucks + _numBuilding;
 
5219
 
 
5220
        if(_totalTrucks >= MAX_BUILDERS){
 
5221
                dbg("HAVE TOO MANY TRUCKS", me);
 
5222
                exit;
 
5223
        }
 
5224
 
 
5225
        _maxBuiltMinTrucks = 2;
 
5226
        if(defendingBase()){
 
5227
                _maxBuiltMinTrucks = 1;
 
5228
        }
 
5229
 
 
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)
 
5235
        {
 
5236
                if(structureComplete(_factory))
 
5237
                {
 
5238
                        if(structureIdle(_factory))
 
5239
                        {
 
5240
                                // find best availabe truck template for this factory
 
5241
                                _tmplIndex = numTruckTmpl - 1;
 
5242
                                _bFoundTemplate = false;
 
5243
                                while(!_bFoundTemplate and (_tmplIndex >= 0))
 
5244
                                {
 
5245
                                        if(skCanBuildTemplate(me,_factory, truck[_tmplIndex]))
 
5246
                                        {
 
5247
                                                tmplOK[0] = truck[_tmplIndex];
 
5248
                                                _bFoundTemplate = true;
 
5249
                                        }
 
5250
                                        _tmplIndex--;
 
5251
                                }
 
5252
 
 
5253
                                // build a truck
 
5254
                                if(_bFoundTemplate)
 
5255
                                {
 
5256
                                        buildDroid(tmplOK[0], _factory, me, 1);
 
5257
                                        _numBuilding++;
 
5258
                                        _totalTrucks++;
 
5259
                                }
 
5260
                        }
 
5261
                }
 
5262
                _factory = enumStruct();
 
5263
        }
 
5264
 
 
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
 
5271
        {
 
5272
                if(structureComplete(_factory))
 
5273
                {
 
5274
                        if(structureIdle(_factory))
 
5275
                        {
 
5276
                                //Try to build an engineer
 
5277
                                if( skCanBuildTemplate(me,_factory, cybEngineer) )      //make sure we have researched cyb engineer
 
5278
                                {
 
5279
                                        buildDroid(cybEngineer, _factory, me, 1);
 
5280
                                        _numBuilding++;
 
5281
                                        _totalTrucks++;
 
5282
                                }
 
5283
                        }
 
5284
                }
 
5285
                _factory = enumStruct();
 
5286
        }
 
5287
}
 
5288
 
 
5289
function void checkPowerGen()
 
5290
{
 
5291
        local   bool    _bStartedBuilding;
 
5292
        //dbg(" " & me & ")  Executing checkPowerGen()");
 
5293
 
 
5294
        _bStartedBuilding = FALSE;
 
5295
 
 
5296
        if(not structureLimitReached(powGen, me))
 
5297
        {
 
5298
                result = getNumStructures(derrick, me);
 
5299
                result = result + numStatBusy(derrick, FALSE);  //"Think ahead"
 
5300
 
 
5301
                result2 = getNumStructures(powGen,me);
 
5302
 
 
5303
                if((result2 * 4) < result)      //not enough pow gens
 
5304
                {
 
5305
                        count = (((result+3)/4) - result2);             //How many power gens are missing
 
5306
 
 
5307
                        //dbg(" " & me & ")  num gens to build: " & count);
 
5308
 
 
5309
                        while(count > 0)
 
5310
                        {
 
5311
                                _bStartedBuilding = buildInBase(powGen, 1);     //Build power gen in the base  (can re-use argument ArgStrStat0)
 
5312
 
 
5313
                                if(_bStartedBuilding){
 
5314
                                        count--;
 
5315
                                }else{
 
5316
                                        count = -1;             //break loop
 
5317
                                }
 
5318
                        }
 
5319
                }
 
5320
        }
 
5321
 
 
5322
        //dbg(" " & me & ")  End checkPowerGen()");
 
5323
}
 
5324
 
 
5325
function void upgradePow()
 
5326
{
 
5327
        local   int                     _numUpgrading;
 
5328
        local   STRUCTURE       _structure;
 
5329
 
 
5330
        if(idleGroupCmd(buildGr,true,false) == 0){exit;}
 
5331
 
 
5332
        //powergen
 
5333
        initEnumStruct(FALSE,powGen,me,me);
 
5334
        _structure = enumStruct();
 
5335
        while(_structure != NULLOBJECT)
 
5336
        {
 
5337
                if(isStructureAvailable(powMod,me) and (not testStructureModule(me, _structure, 0)))
 
5338
                {
 
5339
                        //result = buildingSiteBlocked(NULLOBJECT, 128, _structure.x, _structure.y);
 
5340
 
 
5341
                        if(numBuildSameBuilding(powMod, _structure.x, _structure.y) <= MAX_POWGEN_UPGRADE_TRUCKS)       //Make sure not too many upgrading
 
5342
                        {
 
5343
                                _numUpgrading = numStatBusy(powMod, true);      //How many trucks are busy with facMod
 
5344
 
 
5345
                                if(_numUpgrading == 0)          //Make sure not too many trucks are doing the same thing at a time
 
5346
                                {
 
5347
                                        buildOnMap(powMod, _structure.x, _structure.y, MAX_POWGEN_UPGRADE_TRUCKS);
 
5348
                                }
 
5349
                        }
 
5350
                }
 
5351
                _structure = enumStruct();
 
5352
        }
 
5353
}
 
5354
 
 
5355
function void upgradeFac()
 
5356
{
 
5357
        local   int                     _numUpgrading;
 
5358
        local   STRUCTURE       _structure;
 
5359
        local   bool            _bLetFinishProduction;
 
5360
 
 
5361
        if(idleGroupCmd(buildGr,true,false) == 0){exit;}
 
5362
 
 
5363
        initEnumStruct(FALSE,fac,me,me);
 
5364
        _structure = enumStruct();
 
5365
        while(_structure != NULLOBJECT)
 
5366
        {
 
5367
                if(isStructureAvailable(facMod,me) and (skGetFactoryCapacity(_structure) < 2 ))
 
5368
                {
 
5369
                        //result = buildingSiteBlocked(NULLOBJECT, 128, _structure.x, _structure.y);
 
5370
 
 
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())
 
5374
                        {
 
5375
                                // see if this tank can be used as a scout (and probably will be)
 
5376
                                _bLetFinishProduction = isTankTemplate(factoryGetTemplate(_structure));
 
5377
                        }
 
5378
 
 
5379
                        if(!_bLetFinishProduction)
 
5380
                        {
 
5381
                                if(numBuildSameBuilding(facMod, _structure.x, _structure.y) <= MAX_FACTORY_UPGRADE_TRUCKS)      //Make sure not too many upgrading
 
5382
                                {
 
5383
                                        _numUpgrading = numStatBusy(facMod, TRUE);      //How many trucks are busy with facMod
 
5384
 
 
5385
                                        if(_numUpgrading <= (MAX_FACTORY_UPGRADE_TRUCKS + 1))           //Make sure not too many trucks are doing the same thing at a time
 
5386
                                        {
 
5387
                                                buildOnMap(facMod, _structure.x, _structure.y, MAX_FACTORY_UPGRADE_TRUCKS);
 
5388
                                        }
 
5389
                                }
 
5390
                        }
 
5391
                }
 
5392
                _structure = enumStruct();
 
5393
        }
 
5394
}
 
5395
 
 
5396
function void upgradeVtolFac()
 
5397
{
 
5398
        local   int                     _numUpgrading;
 
5399
        local   STRUCTURE       _structure;
 
5400
 
 
5401
        if(idleGroupCmd(buildGr,true,false) == 0){exit;}
 
5402
 
 
5403
        //vtol Factory
 
5404
        initEnumStruct(FALSE,vtolfac,me,me);
 
5405
        _structure = enumStruct();
 
5406
        while(_structure != NULLOBJECT)
 
5407
        {
 
5408
                if(isStructureAvailable(facMod,me) and (skGetFactoryCapacity(_structure) < 2))
 
5409
                {
 
5410
                        //result = buildingSiteBlocked(NULLOBJECT, 128, _structure.x, _structure.y);
 
5411
 
 
5412
                        if(not buildingSiteBlocked(NULLOBJECT, 128, _structure.x, _structure.y, false))
 
5413
                        {
 
5414
                                _numUpgrading = numStatBusy(facMod, TRUE);      //How many trucks are busy with resMod
 
5415
 
 
5416
                                if(_numUpgrading <= 1)          //Max 2 at a time
 
5417
                                {
 
5418
                                        buildOnMap(facMod, _structure.x, _structure.y, 1);
 
5419
                                }
 
5420
                        }
 
5421
                }
 
5422
                _structure = enumStruct();
 
5423
        }
 
5424
}
 
5425
 
 
5426
function void upgradeResFac()
 
5427
{
 
5428
        local   int                     _numUpgrading;
 
5429
        local   STRUCTURE       _structure;
 
5430
 
 
5431
        //dbg(" " & me & ")  Executing doUpgrades()");
 
5432
 
 
5433
        if(idleGroupCmd(buildGr,true,false) == 0){exit;}
 
5434
 
 
5435
        //research
 
5436
        initEnumStruct(FALSE,resFac,me,me);
 
5437
        _structure = enumStruct();
 
5438
        while(_structure != NULLOBJECT)
 
5439
        {
 
5440
                if(isStructureAvailable(resMod,me) and (not testStructureModule(me, _structure, 0)))
 
5441
                {
 
5442
                        //result = buildingSiteBlocked(NULLOBJECT, 128, _structure.x, _structure.y);
 
5443
 
 
5444
                        if(not buildingSiteBlocked(NULLOBJECT, 128, _structure.x, _structure.y, false))
 
5445
                        {
 
5446
                                _numUpgrading = numStatBusy(resMod, TRUE);      //How many trucks are busy with resMod
 
5447
 
 
5448
                                if(_numUpgrading <= 1)          //Max 2 at a time
 
5449
                                {
 
5450
                                        buildOnMap(resMod, _structure.x, _structure.y, 1);
 
5451
                                }
 
5452
                        }
 
5453
                }
 
5454
                _structure = enumStruct();
 
5455
        }
 
5456
 
 
5457
        //dbg(" " & me & ")  End doUpgrades()");
 
5458
}
 
5459
 
 
5460
function void deselectAllDroids()
 
5461
{
 
5462
        //Iterate through all player droids
 
5463
        InitEnumDroids(me,me);
 
5464
        tempDroid = EnumDroid();
 
5465
        while(tempDroid != NULLOBJECT)
 
5466
        {
 
5467
                selectDroid(tempDroid, FALSE);
 
5468
                tempDroid = EnumDroid();
 
5469
        }
 
5470
}
 
5471
 
 
5472
/* Calculate how many research facilities need to start researching */
 
5473
function int calcNeededRes()
 
5474
{
 
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,
 
5480
                                                _fMissingDefCost;
 
5481
 
 
5482
        /* decide how many research facilities we want to use */
 
5483
        _needRes = maxResearch;
 
5484
 
 
5485
        /*
 
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.
 
5488
        */
 
5489
 
 
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
 
5493
 
 
5494
        _availableAttackers = numAvailableAttackers();
 
5495
        _minAttackers = minAttackers;
 
5496
        _availableAttackersCost = _availableAttackers * (int)_tankCost;
 
5497
        _minAttackersCost = _minAttackers * (int)_tankCost;
 
5498
 
 
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
 
5502
 
 
5503
        _stateCost = 0;
 
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
 
5510
        }
 
5511
 
 
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
 
5518
                        - _stateCost
 
5519
                        - enemyAttackers; */                            //Do less research if enemy is about to invade with a huge force
 
5520
 
 
5521
        _fMinResCost = _topicCost * fMinResearch;
 
5522
        _fPlayerPow = (float)playerPower(me);
 
5523
        _fMissingDefCost = (float)_missingDefendersCost;
 
5524
 
 
5525
        _fNeedResInPower = (_fMinResCost + _fPlayerPow -
 
5526
                _fMissingDefCost +
 
5527
                (float)((int)toPow((float)_availableAttackers / (float)max(_minAttackers, 1), 2.0) * (int)_tankCost) +
 
5528
                (float)(_researchActivityCost - _stateCost));   // - enemyAttackers;
 
5529
 
 
5530
        /* Convert from power currency into number of research facilities needed to put to work */
 
5531
        _needRes = (int)(_fNeedResInPower / _topicCost);
 
5532
        _fNeedRes = (_fNeedResInPower / _topicCost);
 
5533
 
 
5534
        // round to the nearest integer
 
5535
        if((_fNeedRes - (float)(int)_fNeedRes) > 0.5){
 
5536
                _needRes++;
 
5537
        }
 
5538
 
 
5539
        // don't do more than fMinResearch reserahces if defendingBase the base
 
5540
        if(defendingBase() and (playerPower(me) < highPower)){
 
5541
                _needRes = min(0, _needRes);
 
5542
        }
 
5543
        else
 
5544
        {
 
5545
                _needRes = min((int)fMinResearch, _needRes);
 
5546
        }
 
5547
 
 
5548
        /* Update debug menu */
 
5549
        if(watchWindowDebug == WATCH_DEBUG_RESEARCH)
 
5550
        {
 
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);
 
5555
 
 
5556
                setDebugMenuEntry("maxOilScouts: " & maxOilScouts, 5);
 
5557
                setDebugMenuEntry("addScout: " & addScout, 6);
 
5558
                setDebugMenuEntry("numEnemyScouts: " & numEnemyScouts, 7);
 
5559
                setDebugMenuEntry("fMapRevealFactor: " & fMapRevealFactor, 9);
 
5560
        }
 
5561
 
 
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  */
 
5567
 
 
5568
        return _needRes;
 
5569
}
 
5570
 
 
5571
/* Put all research facilities to work, done at startup */
 
5572
event startAllResearch(inactive)
 
5573
{
 
5574
        // start research facilities
 
5575
        doResearchAll();
 
5576
}
 
5577
 
 
5578
event doResearchEv(inactive)
 
5579
{
 
5580
        doResearchAll();
 
5581
}
 
5582
 
 
5583
function void doResearchAll()
 
5584
{
 
5585
        local   STRUCTURE       _resFac;
 
5586
        local   int                     _needRes,_resIndex,_numResearching;
 
5587
 
 
5588
 
 
5589
        /* find out how many research facilities are busy */
 
5590
        _numResearching = numBusyByType(resFac);
 
5591
 
 
5592
        if(_numResearching > 0){
 
5593
                tLastResearch = 0;      //reset, since we are not idle
 
5594
        }
 
5595
 
 
5596
        /* Calculate how many research facilities should be researching */
 
5597
        _needRes = calcNeededRes();
 
5598
 
 
5599
        /* see if we already have enough research facilities busy */
 
5600
        if(_numResearching >= _needRes){
 
5601
                exit;
 
5602
        }
 
5603
 
 
5604
        _resIndex = none;               //research index
 
5605
 
 
5606
 
 
5607
        /* Put research facilities to work */
 
5608
        initEnumStruct(FALSE,resFac,me,me);
 
5609
        _resFac = enumStruct();
 
5610
 
 
5611
        while((_resFac != NULLOBJECT) and (_numResearching < _needRes))         //not too many working
 
5612
        {
 
5613
 
 
5614
                _resIndex = doResearch(_resFac, _resIndex);
 
5615
 
 
5616
                if(_resIndex >= 0)
 
5617
                {
 
5618
 
 
5619
                        _numResearching++;      //one more working
 
5620
                        tLastResearch = 0;      //reset, since we are not idle now
 
5621
                }
 
5622
 
 
5623
                _resFac = enumStruct();
 
5624
 
 
5625
        }
 
5626
 
 
5627
}
 
5628
 
 
5629
event startNewResearch(inactive)
 
5630
{
 
5631
        local   STRUCTURE       _resFac;
 
5632
        local   int                     _needRes,_resIndex,_numResearching;
 
5633
 
 
5634
        // structure can be null sometimes
 
5635
        if(structure == NULLOBJECT){
 
5636
                exit;
 
5637
        }
 
5638
 
 
5639
        ASSERT(structureIdle(structure), "startNewResearch: Res fac is not idle", me);
 
5640
 
 
5641
        /* find out how many research facilities are busy */
 
5642
        _numResearching = numBusyByType(resFac);
 
5643
 
 
5644
        if(_numResearching > 0){
 
5645
                tLastResearch = 0;      //reset, since we are not idle
 
5646
        }
 
5647
 
 
5648
        /* Calculate how many research facilities should be researching */
 
5649
        _needRes = calcNeededRes();
 
5650
 
 
5651
        /* see if we already have enough research facilities busy */
 
5652
        if(_numResearching >= _needRes){
 
5653
                exit;
 
5654
        }
 
5655
 
 
5656
        _resIndex = none;               //research index
 
5657
 
 
5658
        // start researching next research topic with this idle res fac
 
5659
        _resIndex = doResearch(structure,_resIndex);
 
5660
}
 
5661
 
 
5662
function int doResearch(STRUCTURE _resFac, int _resIndex)
 
5663
{
 
5664
        local   bool    _bStarted;
 
5665
        local   int             _tech;
 
5666
 
 
5667
        /* current tech tree */
 
5668
        _tech = 0;      //default tank tech //TODO: fix
 
5669
        if(tech != none){
 
5670
                _tech = tech;   //use whatever we selected as our new preference
 
5671
        }
 
5672
 
 
5673
        if(structureIdle(_resFac))
 
5674
        {
 
5675
 
 
5676
                if(structureComplete(_resFac))
 
5677
                {
 
5678
                        _bStarted = FALSE;      //this res lab idle for now
 
5679
 
 
5680
                        /* check if need unit transporter ASAP */
 
5681
/*
 
5682
                        if((state == stDrop) and (not researchFinished(resUnitTransporter, me)))
 
5683
                        {
 
5684
                                _bStarted = pursueResearch(_resFac,me,resUnitTransporter);
 
5685
 
 
5686
                                if(_bStarted)
 
5687
                                {
 
5688
                                        dbg("getting transporter tech", me);
 
5689
                                }
 
5690
                        }
 
5691
*/
 
5692
 
 
5693
                        /* do normal research */
 
5694
                        while(not _bStarted)
 
5695
                        {
 
5696
 
 
5697
                                _resIndex = findResearch(_resIndex + 1, _tech);
 
5698
 
 
5699
                                if(_resIndex > none)    //found research
 
5700
                                {
 
5701
 
 
5702
                                        _bStarted = pursueResearch(_resFac,me,research[_tech][_resIndex]);
 
5703
 
 
5704
                                        // if(_bStarted)
 
5705
                                        // {
 
5706
                                                // _numResearching++;   //one more working
 
5707
                                                // tLastResearch = 0;   //reset, since we are not idle now
 
5708
                                        // }
 
5709
                                }
 
5710
                                else
 
5711
                                {
 
5712
                                        _bStarted = TRUE;       //make loop end, no research found
 
5713
                                }
 
5714
                        }
 
5715
                }
 
5716
        }
 
5717
 
 
5718
        if(!_bStarted)
 
5719
        {
 
5720
                return none;
 
5721
        }
 
5722
 
 
5723
        return _resIndex;
 
5724
}
 
5725
 
 
5726
function int findResearch(int _searchStart, int _techTree)
 
5727
{
 
5728
        ASSERT(_searchStart >= 0, "findResearch: _searchStart < 0", me);
 
5729
        ASSERT(_techTree >= 0, "findResearch: _techTree < 0", me);
 
5730
 
 
5731
        retInt = _searchStart;
 
5732
        while(retInt < numRes[_techTree])
 
5733
        {
 
5734
                if((not researchFinished(research[_techTree][retInt], me)) and (not researchStarted(research[_techTree][retInt], me)))
 
5735
                {
 
5736
                        return(retInt);         //found research
 
5737
                }
 
5738
                retInt = retInt + 1;
 
5739
        }
 
5740
 
 
5741
        retInt = none;          //not found
 
5742
        return(retInt);
 
5743
}
 
5744
 
 
5745
//--------------------------------------------------------
 
5746
//Number of busy structures by type
 
5747
//--------------------------------------------------------
 
5748
function int numBusyByType(STRUCTURESTAT _busyStructType)
 
5749
{
 
5750
        local   int             _result;
 
5751
        local   STRUCTURE       _structure;
 
5752
 
 
5753
        initEnumStruct(FALSE,_busyStructType,me,me);
 
5754
        _structure = enumStruct();
 
5755
        _result = 0;
 
5756
        while(_structure != NULLOBJECT)
 
5757
        {
 
5758
                if(not structureIdle(_structure))
 
5759
                {
 
5760
                        _result++;
 
5761
                }
 
5762
                _structure = enumStruct();
 
5763
        }
 
5764
 
 
5765
        return(_result);
 
5766
}
 
5767
 
 
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)
 
5773
{
 
5774
        local   int             _numStatBusy,_bucket;
 
5775
        local   DROID   _bTruck;
 
5776
 
 
5777
        _numStatBusy = 0;
 
5778
 
 
5779
        _bucket = initIterateGroupCmd(buildGr,true,false,true);
 
5780
        _bTruck = iterateGroupCmd(buildGr,_bucket);
 
5781
        while(_bTruck != NULLOBJECT)
 
5782
        {
 
5783
                if(_bTruck.order == DORDER_BUILD)
 
5784
                {
 
5785
                        if(not (_bExcludeAlreadyBuilding and _bTruck.action == DACTION_BUILD))
 
5786
                        {
 
5787
                                if(_bTruck.stat == _structureToCheck)   //going to build it
 
5788
                                {
 
5789
                                        _numStatBusy++;
 
5790
                                }
 
5791
                        }
 
5792
                }
 
5793
                _bTruck = iterateGroupCmd(buildGr,_bucket);
 
5794
        }
 
5795
 
 
5796
        return _numStatBusy;
 
5797
}
 
5798
 
 
5799
//--------------------------------------------------------
 
5800
//Total number of trucks are have started building
 
5801
//something (not just going to the building site)
 
5802
//--------------------------------------------------------
 
5803
function int numTrucksBuilding()
 
5804
{
 
5805
        local   int     _bucket;
 
5806
 
 
5807
        retInt = 0;
 
5808
        _bucket = initIterateGroupCmd(buildGr,true,false,true);
 
5809
        tempDroid = iterateGroupCmd(buildGr,_bucket);
 
5810
        while(tempDroid != NULLOBJECT)
 
5811
        {
 
5812
                if((tempDroid.order == DORDER_BUILD) and (tempDroid.action != DACTION_MOVETOBUILD))     //Started building
 
5813
                {
 
5814
                        retInt = retInt + 1;
 
5815
                }
 
5816
                tempDroid = iterateGroupCmd(buildGr,_bucket);
 
5817
        }
 
5818
 
 
5819
        return(retInt);
 
5820
}
 
5821
 
 
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)
 
5827
{
 
5828
        local   int     _bucket,_numBusy;
 
5829
        local   DROID   _truck;
 
5830
 
 
5831
        _numBusy = 0;
 
5832
        _bucket = initIterateGroupCmd(buildGr,true,false,true);
 
5833
        _truck = iterateGroupCmd(buildGr,_bucket);
 
5834
        while(_truck != NULLOBJECT)
 
5835
        {
 
5836
                if((_truck.order == DORDER_BUILD) and (_truck.action == DACTION_MOVETOBUILD)) //Not reached the building site yet
 
5837
                {
 
5838
                        if(_truck.stat == _structStatToCheck)   //going to build it
 
5839
                        {
 
5840
                                _numBusy = _numBusy + 1;
 
5841
                        }
 
5842
                }
 
5843
                _truck = iterateGroupCmd(buildGr,_bucket);
 
5844
        }
 
5845
 
 
5846
        return(_numBusy);
 
5847
}
 
5848
 
 
5849
//-----------------------------------------------------
 
5850
function bool buildInBase(STRUCTURESTAT _statToBuild, int _maxTrucks)
 
5851
{
 
5852
        local   bool            _bStartedBuilding;
 
5853
 
 
5854
        _bStartedBuilding = FALSE;
 
5855
 
 
5856
        //dbg(" " & me & ")  Executing buildInBase()");
 
5857
 
 
5858
        temp = 6 * 128;
 
5859
        temp2 = baseX + (random(temp) - (temp/2));      //Randomize a bit
 
5860
        temp3 = baseY + (random(temp) - (temp/2));
 
5861
 
 
5862
        if(pickStructLocation(_statToBuild, ref temp2, ref temp3, me))
 
5863
        {
 
5864
                _bStartedBuilding = buildUsingClosestTruck(_statToBuild, temp2, temp3, _maxTrucks);             //can re-use ArgStrStat0
 
5865
        }
 
5866
 
 
5867
        //dbg(" " & me & ")  End buildInBase()");
 
5868
 
 
5869
        return _bStartedBuilding;
 
5870
}
 
5871
 
 
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
 
5876
{
 
5877
        local   int             _numTrucks;
 
5878
        local   bool    _bHaveMoreTrucks;
 
5879
        local   DROID   _truck;
 
5880
 
 
5881
        //dbg(" " & me & ")  Executing buildUsingClosestTruck()");
 
5882
 
 
5883
        _numTrucks = 0;
 
5884
        _bHaveMoreTrucks = TRUE;
 
5885
        while((_numTrucks < _maxTrucks) and _bHaveMoreTrucks)
 
5886
        {
 
5887
                _bHaveMoreTrucks = FALSE;
 
5888
 
 
5889
                _truck = closestIdleTruck(_buildX, _buildY);
 
5890
                if(_truck != NULLOBJECT)
 
5891
                {
 
5892
                        _bHaveMoreTrucks = TRUE;
 
5893
                        orderDroidStatsLoc(_truck, DORDER_BUILD, _statToBuild, _buildX, _buildY);
 
5894
 
 
5895
                        //dbg(" " & me & ")  End buildUsingClosestTruck()");
 
5896
                        _numTrucks++;
 
5897
                }
 
5898
        }
 
5899
 
 
5900
        //dbg(" " & me & ")  End buildUsingClosestTruck()");
 
5901
 
 
5902
        return (_numTrucks > 0);
 
5903
}
 
5904
 
 
5905
//-----------------------------------------------------
 
5906
//Build factories and research facilities dynamically
 
5907
//-----------------------------------------------------
 
5908
function void buildBaseStructs()
 
5909
{
 
5910
        local   int _maxResFac,_numResFac,_maxFacs,_numFacs,_buildX,_buildY,
 
5911
                                _range,_result3;
 
5912
        local   bool _bStartedBuild,_bNeedFac,_bNeedResFac,_bResult;
 
5913
 
 
5914
        if(idleGroupCmd(buildGr,true,false) == 0)
 
5915
                exit;
 
5916
 
 
5917
        _range = 6 * 128;
 
5918
 
 
5919
        _buildX = baseX + random(_range) - (_range / 2);
 
5920
        _buildY = baseY + random(_range) - (_range / 2);
 
5921
 
 
5922
        _maxFacs = getStructureLimit(fac, me);
 
5923
        _maxResFac = getStructureLimit(resFac, me);
 
5924
 
 
5925
        // num already built plus num pending
 
5926
        _numFacs = getNumStructures(fac,me) + numStatMoveBusy(fac);
 
5927
        _numResFac = getNumStructures(resFac,me) + numStatMoveBusy(resFac);
 
5928
 
 
5929
        /* limit num of facs when critical power or low on defenders */
 
5930
        if(alert)
 
5931
        {
 
5932
                _maxFacs = min(minFacs, _maxFacs);              //limit facs,
 
5933
                _maxResFac = min(minResFacs, _maxResFac);               //limit res fac
 
5934
        }
 
5935
 
 
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));
 
5939
 
 
5940
        dbg("max facs/res facs: " & _maxFacs & "/" & _maxResFac & ", need: " &
 
5941
                _bNeedFac & "/" & _bNeedResFac, me);
 
5942
 
 
5943
        _bStartedBuild = FALSE;
 
5944
 
 
5945
        /* Build HQ */
 
5946
        if(getStructure(HQ, me) == NULLOBJECT)  //not built and no one's on the way to build
 
5947
        {
 
5948
                //Check if someone's already on the way to build HQ
 
5949
                _result3 = numStatBusy(HQ, TRUE);
 
5950
 
 
5951
                if(_result3 == 0)               //no one's on the way to build
 
5952
                {
 
5953
                        bDummy = buildInBase(HQ, 1);
 
5954
                }
 
5955
        }
 
5956
 
 
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
 
5960
        {
 
5961
                if((_numFacs > 0) and (_numResFac > 0) and isStructureAvailable(vtolfac, me))
 
5962
                {
 
5963
                        //if(numResearchLeft(me, resUnitTransporter) <= 6)      //don't bother if still to far away from being able to build transporter
 
5964
                        //{
 
5965
                                if(getNumStructures(vtolfac, me) < min(0, getStructureLimit(vtolfac, me)))      //don't try to build more than allowed
 
5966
                                {
 
5967
                                        //Check if someone's already on the way to build VTOL fac
 
5968
                                        _result3 = numStatBusy(vtolfac, TRUE);
 
5969
 
 
5970
                                        if(_result3 == 0)               //no one's on the way to build
 
5971
                                        {
 
5972
                                                bDummy = buildInBase(vtolfac, 2);
 
5973
                                                dbg("Building VTOL Factory", me);
 
5974
                                                exit;
 
5975
                                        }
 
5976
                                }
 
5977
                        //}
 
5978
                }
 
5979
        }
 
5980
 
 
5981
        //if((not _bNeedFac) and (not _bNeedResFac)){exit;}
 
5982
 
 
5983
 
 
5984
 
 
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)
 
5990
        {
 
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!)
 
5993
 
 
5994
                //dbg(" " & me & ")  buildBaseStructs() - factory - have: " & _numFacs & " pending: " & _result3);
 
5995
 
 
5996
                if((_numFacs + _result3) < _maxFacs)    //Will not max out
 
5997
                {
 
5998
                        _bResult = pickStructLocation(fac, ref _buildX, ref _buildY, me);
 
5999
                        if(_bResult == TRUE)
 
6000
                        {
 
6001
                                //Anyone already wants to build something else on this spot?
 
6002
                                //_result3 = buildingSiteBlocked(NULLOBJECT, 128, _buildX, _buildY);
 
6003
 
 
6004
                                if(not buildingSiteBlocked(NULLOBJECT, 128, _buildX, _buildY, false))
 
6005
                                {
 
6006
                                        _bResult = buildUsingClosestTruck(fac, _buildX, _buildY, 2);            //Building coords and STRUCTURESTAT are passed
 
6007
 
 
6008
                                        if(_bResult)
 
6009
                                        {
 
6010
                                                _bStartedBuild = TRUE;  //Build successfull
 
6011
                                        }
 
6012
                                }
 
6013
                                else
 
6014
                                {
 
6015
                                        dbg("buildBaseStructs() - factory someone's building (!!!!!!!!!!)", me);
 
6016
                                }
 
6017
                        }
 
6018
                }
 
6019
        }
 
6020
 
 
6021
        if(alert){
 
6022
                exit;
 
6023
        }
 
6024
 
 
6025
        /* build res fac */
 
6026
        if(!_bStartedBuild and _bNeedResFac)    //Factory unavailable (didn't start build it) and Rec fac available
 
6027
        {
 
6028
                //dbg(" " & me & ")  buildBaseStructs() - must build res fac (*)");
 
6029
 
 
6030
                //How many trucks are on the way to build res fac
 
6031
                _result3 = numStatMoveBusy(resFac);     //How many builds are in progress or pending
 
6032
 
 
6033
                if((_result3 + _numResFac) < min(_maxResFac, maxResearch))      //Will not max out, or don't build more than required (maxResearch)
 
6034
                {
 
6035
                        dbg("Building res fac", me);
 
6036
 
 
6037
                        _bResult = pickStructLocation(resFac, ref _buildX, ref _buildY, me);
 
6038
                        if(_bResult == TRUE)
 
6039
                        {
 
6040
                                //Anyone already wants to build something else on this spot?
 
6041
                                //_result3 = buildingSiteBlocked(NULLOBJECT, 128, _buildX, _buildY);
 
6042
 
 
6043
                                if(not buildingSiteBlocked(NULLOBJECT, 128, _buildX, _buildY, false))
 
6044
                                {
 
6045
                                        bDummy = buildUsingClosestTruck(resFac, _buildX, _buildY, 1);           //Building coords and STRUCTURESTAT are passed
 
6046
                                }
 
6047
                        }
 
6048
                }
 
6049
        }
 
6050
 
 
6051
        /* build uplink center */
 
6052
        if(getNumStructures(uplink,me) >= 1){exit;}
 
6053
        if(not isStructureAvailable(uplink, me)){exit;}
 
6054
 
 
6055
        if((_numFacs < 1) or (_numResFac < 1)){exit;}   //no facs, no research
 
6056
 
 
6057
        //How many trucks are on the way to build uplink
 
6058
        _result3 = numStatMoveBusy(uplink);     //How many builds are in progress or pending
 
6059
 
 
6060
        if(_result3 > 0){exit;}
 
6061
 
 
6062
        _buildX = baseX + random(_range) - (_range / 2);
 
6063
        _buildY = baseY + random(_range) - (_range / 2);
 
6064
 
 
6065
        _bResult = pickStructLocation(uplink, ref _buildX, ref _buildY, me);
 
6066
        if(_bResult == TRUE)
 
6067
        {
 
6068
                //Anyone already wants to build something else on this spot?
 
6069
                //_result3 = buildingSiteBlocked(NULLOBJECT, 128, _buildX, _buildY);
 
6070
 
 
6071
                if(not buildingSiteBlocked(NULLOBJECT, 128, _buildX, _buildY, false))
 
6072
                {
 
6073
                        bDummy = buildUsingClosestTruck(uplink, _buildX, _buildY, 1);           //Building coords and STRUCTURESTAT are passed
 
6074
                }
 
6075
        }
 
6076
 
 
6077
 
 
6078
        //dbg(" " & me & ")  End buildBaseStructs()");
 
6079
}
 
6080
 
 
6081
//---------------------------------------------------------
 
6082
//      Find droids without a group
 
6083
//---------------------------------------------------------
 
6084
function void unassignedDroids(GROUP defendersGr, GROUP buildersGr)
 
6085
{
 
6086
        _temp = 0;
 
6087
 
 
6088
        //Iterate through all player droids
 
6089
        InitEnumDroids(me,me);
 
6090
        tempDroid = EnumDroid();
 
6091
        while(tempDroid != NULLOBJECT)
 
6092
        {
 
6093
                if(not hasGroup(tempDroid))
 
6094
                {
 
6095
                        if(tempDroid.droidType == DROID_CONSTRUCT)
 
6096
                        {
 
6097
                                groupAddDroid(buildersGr, tempDroid);
 
6098
                                _temp = _temp + 1;
 
6099
                        }
 
6100
                        else
 
6101
                        {
 
6102
                                if((tempDroid.droidType != DROID_TRANSPORTER) and
 
6103
                                (tempDroid.droidType != DROID_COMMAND))
 
6104
                                {
 
6105
                                        groupAddDroid(defendersGr, tempDroid);
 
6106
                                        _temp = _temp + 1;
 
6107
                                }
 
6108
                        }
 
6109
                }
 
6110
                tempDroid = EnumDroid();
 
6111
        }
 
6112
 
 
6113
        dbg("found " & _temp & " unassigned droids", me);
 
6114
}
 
6115
 
 
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)
 
6121
{
 
6122
        local   int     _bucket;
 
6123
 
 
6124
        retInt = 0;
 
6125
 
 
6126
        _bucket = initIterateGroupCmd(buildGr,true,false,true);
 
6127
        tempDroid = iterateGroupCmd(buildGr,_bucket);
 
6128
        while(tempDroid != NULLOBJECT)
 
6129
        {
 
6130
                if(tempDroid.order == DORDER_BUILD)
 
6131
                {
 
6132
                        if(tempDroid.stat == _checkStat)        //Same struct type
 
6133
                        {
 
6134
                                //Within some range
 
6135
                                if(distBetweenTwoPoints(_x, _y, tempDroid.orderx , tempDroid.ordery) <= 128)
 
6136
                                {
 
6137
                                        retInt = retInt + 1;
 
6138
                                }
 
6139
                        }
 
6140
                }
 
6141
                tempDroid = iterateGroupCmd(buildGr,_bucket);
 
6142
        }
 
6143
 
 
6144
        return(retInt);
 
6145
}
 
6146
 
 
6147
function int numTrucksSameOrder(int _orderIndex)
 
6148
{
 
6149
        local   int     _bucket;
 
6150
 
 
6151
        retInt = 0;
 
6152
 
 
6153
        _bucket = initIterateGroupCmd(buildGr,true,false,true);
 
6154
        tempDroid = iterateGroupCmd(buildGr,_bucket);
 
6155
        while(tempDroid != NULLOBJECT)
 
6156
        {
 
6157
                if(tempDroid.order == _orderIndex)      //right order type
 
6158
                {
 
6159
                        retInt = retInt + 1;
 
6160
                }
 
6161
                tempDroid = iterateGroupCmd(buildGr,_bucket);
 
6162
        }
 
6163
 
 
6164
        return(retInt);
 
6165
}
 
6166
 
 
6167
 
 
6168
//---------------------------------------------------------------
 
6169
//Returns how many trucks have order in a range
 
6170
//---------------------------------------------------------------
 
6171
function int numTrucksOrderInRange(int _rangex, int _rangey, int _range, int _order)
 
6172
{
 
6173
        local   int     _bucket;
 
6174
        local   DROID   _truck;
 
6175
 
 
6176
        retInt = 0;
 
6177
 
 
6178
        _bucket = initIterateGroupCmd(buildGr,true,false,true);
 
6179
        _truck = iterateGroupCmd(buildGr,_bucket);
 
6180
        while(_truck != NULLOBJECT)
 
6181
        {
 
6182
                if((_order < 0) or (_truck.order == _order))    //Any order or right order type
 
6183
                {
 
6184
                        //Within some range
 
6185
                        if(distBetweenTwoPoints(_rangex, _rangey, _truck.orderx , _truck.ordery) <= _range)
 
6186
                        {
 
6187
                                retInt = retInt + 1;
 
6188
                        }
 
6189
                }
 
6190
                _truck = iterateGroupCmd(buildGr,_bucket);
 
6191
        }
 
6192
 
 
6193
        return(retInt);
 
6194
}
 
6195
 
 
6196
//---------------------------------------------------------------
 
6197
//Returns how many trucks have the same order location
 
6198
//---------------------------------------------------------------
 
6199
function int numTrucksSameOrderLoc(int _x, int _y, int _orderIndex)
 
6200
{
 
6201
        local   int     _bucket;
 
6202
 
 
6203
        retInt = 0;
 
6204
 
 
6205
        _bucket = initIterateGroupCmd(buildGr,true,false,true);
 
6206
        tempDroid = iterateGroupCmd(buildGr,_bucket);
 
6207
        while(tempDroid != NULLOBJECT)
 
6208
        {
 
6209
                if((_orderIndex < 0) or (tempDroid.order == _orderIndex))       //Any order or right order type
 
6210
                {
 
6211
                        //Within some range
 
6212
                        if(distBetweenTwoPoints(_x, _y, tempDroid.orderx , tempDroid.ordery) <= 64)
 
6213
                        {
 
6214
                                retInt = retInt + 1;
 
6215
                        }
 
6216
                }
 
6217
                tempDroid = iterateGroupCmd(buildGr,_bucket);
 
6218
        }
 
6219
 
 
6220
        return(retInt);
 
6221
}
 
6222
 
 
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)
 
6228
{
 
6229
        local   int     _bucket;
 
6230
        local   DROID   _tempDroid;
 
6231
 
 
6232
        _bucket = initIterateGroupCmd(buildGr,true,false,true);
 
6233
        _tempDroid = iterateGroupCmd(buildGr,_bucket);
 
6234
        while(_tempDroid != NULLOBJECT)
 
6235
        {
 
6236
                if(_tempDroid != _truck)                //Not himself (_truck allowed to be NULLOBJECT)
 
6237
                {
 
6238
                        if(_tempDroid.orderx > 0)
 
6239
                        {
 
6240
                                //Within some range
 
6241
                                if(distBetweenTwoPoints(_x, _y, _tempDroid.orderx , _tempDroid.ordery) <= _radius)
 
6242
                                {
 
6243
                                        if(_bAllOrders)
 
6244
                                        {
 
6245
                                                if(_tempDroid.order != DORDER_NONE)
 
6246
                                                {
 
6247
                                                        return true;
 
6248
                                                }
 
6249
                                        }
 
6250
                                        else
 
6251
                                        {
 
6252
                                                if((_tempDroid.order == DORDER_BUILD) or (_tempDroid.order == DORDER_LINEBUILD))
 
6253
                                                {
 
6254
                                                        return true;            //Spot busy
 
6255
                                                }
 
6256
                                        }
 
6257
                                }
 
6258
                        }
 
6259
 
 
6260
                }
 
6261
                _tempDroid = iterateGroupCmd(buildGr,_bucket);
 
6262
        }
 
6263
 
 
6264
        return false;
 
6265
}
 
6266
 
 
6267
//Don't have to be deactivated
 
6268
event droidDestroyed(droidDestroyedTr)
 
6269
{
 
6270
        local   DROID           _commander,_newDroid,_droid;
 
6271
        local   GROUP           _cmdGroup,_group;
 
6272
        local   int                     _cmdIndex;
 
6273
 
 
6274
        //ASSERT(count >= 0 and count < MAX_PLAYERS, "wrong player index: " & count, me);
 
6275
 
 
6276
        //Calculate how much a player has lost in power currency
 
6277
        lostDroids[me] = lostDroids[me] + calcDroidPower(droid);
 
6278
 
 
6279
        //If a commander has lost a unit give it another unit
 
6280
 
 
6281
        if(droid.droidType == DROID_COMMAND)
 
6282
        {
 
6283
                _cmdGroup = droid.group;
 
6284
                _cmdIndex = cmdToIndex(droid);
 
6285
 
 
6286
                if(_cmdIndex >= 0)
 
6287
                {
 
6288
                        _group = cmdGr[_cmdIndex];      //group a commander belonged to
 
6289
 
 
6290
                        dbg("Destroyed commander had " & _cmdGroup.members & " attached", me);
 
6291
 
 
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)
 
6296
                        {
 
6297
                                groupAddDroid(_group, _droid);
 
6298
                                _droid = iterateGroup(_cmdGroup);
 
6299
                        }
 
6300
 
 
6301
                        //refill other commanders from the same group as this commander with unassigned droids
 
6302
                        assignDroidsToBestCommandersFromGroup(_group, _group);
 
6303
                }
 
6304
 
 
6305
        }
 
6306
 
 
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))
 
6309
        {
 
6310
                if(droid.group != NULLOBJECT)           //this droid belonged to a group
 
6311
                {
 
6312
                        if(droid.group.type == GT_COMMAND)              //if it's a commander group unit belonged to
 
6313
                        {
 
6314
                                dbg("Destroyed unit from a commander group", me);
 
6315
 
 
6316
                                _commander = droid.group.commander;
 
6317
                                _cmdIndex = cmdToIndex(_commander);
 
6318
                                if(_commander != NULLOBJECT and _cmdIndex >= 0)
 
6319
                                {
 
6320
                                        ASSERT(_commander.droidType == DROID_COMMAND, "Droid is not a commander", me);
 
6321
 
 
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);
 
6325
 
 
6326
                                        if(_newDroid != NULLOBJECT)
 
6327
                                        {
 
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)
 
6330
                                                {
 
6331
                                                        dbg("Assigned a new droid to a commander", me);
 
6332
                                                        cmdDroidAddDroid(_commander, _newDroid);
 
6333
                                                }
 
6334
                                        }
 
6335
                                }
 
6336
                        }
 
6337
                }
 
6338
        }
 
6339
}
 
6340
 
 
6341
event structDestroyed(inactive)
 
6342
{
 
6343
        local   int i,_numEnemies;
 
6344
 
 
6345
        if(structure == NULLOBJECT)
 
6346
                exit;
 
6347
 
 
6348
        // deal with a destroyed derrick
 
6349
        if(structure.stat == derrick)
 
6350
        {
 
6351
                if(!isInMyBase(structure.x,structure.y))
 
6352
                {
 
6353
                        _numEnemies = enemyWeapObjCostInRange(me, structure.x, structure.y,
 
6354
                                CHECK_OIL_THREAT_RANGE, false, true);
 
6355
 
 
6356
                        tOilAttackBegin = GAME_TIME_IN_SECS;
 
6357
                        tLastOilAttack = GAME_TIME_IN_SECS;
 
6358
                        lastOilAttackedX = structure.x;
 
6359
                        lastOilAttackedY = structure.y;
 
6360
 
 
6361
                        //if(checkOilThreat(structure.x, structure.y))
 
6362
                        //{
 
6363
                                if(canStartDefendingOil())
 
6364
                                {
 
6365
                                        // start defending oil
 
6366
                                        initializeStartDefeindingOil(structure.x, structure.y);
 
6367
                                }
 
6368
                        //}
 
6369
                }
 
6370
        }
 
6371
 
 
6372
 
 
6373
        /* Update ghost data */
 
6374
        if(structure.player == me)
 
6375
        {
 
6376
                if((structure.stat == wall) or (structure.stattype == REF_DEFENSE))
 
6377
                {
 
6378
                        /* Find structure that was destroyed */
 
6379
                        i = 0;
 
6380
                        while(i < maxGhosts)
 
6381
                        {
 
6382
                                if((ghostx[i] == structure.x) and (ghosty[i] == structure.y) and (ghostStat[i] == structure.stat))
 
6383
                                {
 
6384
                                        dbg("FOUND DESTROYED STRUCTURE!!!!!", me);
 
6385
                                        ghostDead[i] = TRUE;
 
6386
                                        i = maxGhosts;                  //exit
 
6387
                                }
 
6388
                                i = i + 1;
 
6389
                        }
 
6390
                }
 
6391
        }
 
6392
 
 
6393
        /* remember we lost LasSat */
 
6394
        if(structure.stat == lasSat)
 
6395
        {
 
6396
                lasSatState[me] = lsNone;
 
6397
        }
 
6398
}
 
6399
 
 
6400
function bool manageOilSite(DROID _truck, STRUCTURE _derrick)
 
6401
{
 
6402
        local   int                     _threatRange;
 
6403
        local   bool            _bBusy,_bThreat;
 
6404
        local   STRUCTURE       _enemyDerrick;
 
6405
 
 
6406
        _threatRange = (TILE * 8);
 
6407
 
 
6408
        _bBusy = false;
 
6409
 
 
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)
 
6413
        {
 
6414
                // check if there are any enemy structures or droid nearby
 
6415
                _bThreat = false;
 
6416
                if(threatInRange(me, _enemyDerrick.x, _enemyDerrick.y, _threatRange, false))
 
6417
                {
 
6418
                        _bThreat = true;
 
6419
                }
 
6420
 
 
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)
 
6422
                if(!_bThreat)
 
6423
                {
 
6424
                        if(numEnemyWeapStructsInRange(me, _enemyDerrick.x, _enemyDerrick.y, NEXT_OIL_RANGE, false) > 0)
 
6425
                        {
 
6426
                                if(closestEnemyDroidByType(_enemyDerrick.x, _enemyDerrick.x , _threatRange, DROID_CONSTRUCT) != NULLOBJECT)
 
6427
                                {
 
6428
                                        _bThreat = true;
 
6429
                                }
 
6430
 
 
6431
                                if(closestEnemyDroidByType(_enemyDerrick.x, _enemyDerrick.x, _threatRange, DROID_CYBORG_CONSTRUCT) != NULLOBJECT)
 
6432
                                {
 
6433
                                        _bThreat = true;
 
6434
                                }
 
6435
                        }
 
6436
                }
 
6437
 
 
6438
                // build defenses near enemy derrick, if it's not dangerous
 
6439
                if(!_bThreat)
 
6440
                {
 
6441
                        // build defenses near enemy derrick => destroy it
 
6442
                        if(buildDerrickDefence(_enemyDerrick, _truck))
 
6443
                        {
 
6444
                                dbg("ATTACKING ENEMY DERRICK WITH DEFENSES!!!", me);
 
6445
                                return true;
 
6446
                        }
 
6447
                }
 
6448
        }
 
6449
 
 
6450
        // TODO: also protect burning oil derricks, with a lower priority
 
6451
 
 
6452
        /* check if we can build another derrick near this one */
 
6453
        if(!structureLimitReached(derrick, me))
 
6454
        {
 
6455
                // try to build next oil nearby, exit here if succeeded
 
6456
                if(buildNextOil(_truck, NEXT_OIL_RANGE, true))
 
6457
                {
 
6458
                        return true;
 
6459
                }
 
6460
        }
 
6461
        else
 
6462
        {
 
6463
                dbg("can't build more derricks", me);
 
6464
        }
 
6465
 
 
6466
        // if there's threat nearby, then first try to repair structures
 
6467
        if(threatInRange(me, _derrick.x, _derrick.y, _threatRange, false))
 
6468
        {
 
6469
                if(repairDamagedDefenses(_derrick.x, _derrick.y, _truck, 50, RANGE_ALL_OIL_DEFENSES)){
 
6470
                        return true;
 
6471
                }
 
6472
 
 
6473
                if(finishDefenses(_truck, _derrick.x, _derrick.y, RANGE_ALL_OIL_DEFENSES)){
 
6474
                        return true;
 
6475
                }
 
6476
        }
 
6477
        else
 
6478
        {
 
6479
                if(finishDefenses(_truck, _derrick.x, _derrick.y, RANGE_ALL_OIL_DEFENSES)){
 
6480
                        return true;
 
6481
                }
 
6482
 
 
6483
                if(repairDamagedDefenses(_derrick.x, _derrick.y, _truck, 50, RANGE_ALL_OIL_DEFENSES)){
 
6484
                        return true;
 
6485
                }
 
6486
        }
 
6487
 
 
6488
        if(buildDerrickDefence(_derrick, _truck))
 
6489
        {
 
6490
                return true;
 
6491
        }
 
6492
 
 
6493
        return false;
 
6494
}
 
6495
 
 
6496
event structBuilt(inactive)
 
6497
{
 
6498
        local   FEATURE         _oilResource;
 
6499
        local   STRUCTURE       _closestDerrick;
 
6500
        local   int                     _count,_count2;
 
6501
 
 
6502
        //dbg(" " & me & ")  CALLBACK - built (" & structure.x & "-" & structure.y & ")", me);
 
6503
 
 
6504
        if(structure == NULLOBJECT)
 
6505
        {
 
6506
                MsgBox("structBuilt - structure NULLOBJECT");
 
6507
                exit;
 
6508
        }
 
6509
 
 
6510
        if(droid == NULLOBJECT)
 
6511
        {
 
6512
                MsgBox("structBuilt - droid NULLOBJECT");
 
6513
                exit;
 
6514
        }
 
6515
 
 
6516
        /* remember we have LasSat */
 
6517
        if(structure.stat == lasSat)
 
6518
        {
 
6519
                dbg("buildInitialDefenses() - lassat built", me);
 
6520
                resetLasSat();
 
6521
                lasSatState[me] = lsRecharging;
 
6522
        }
 
6523
 
 
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))
 
6527
        {
 
6528
                buildInitialDefenses(TRUE);
 
6529
                exit;
 
6530
        }
 
6531
 
 
6532
        /* give allies vision of the entire map */
 
6533
        if(structure.stat == uplink)
 
6534
        {
 
6535
                refreshAllyRadar();
 
6536
        }
 
6537
 
 
6538
        /* check if it's the right structure type */
 
6539
        if(structure.stattype == REF_DEFENSE)
 
6540
        {
 
6541
                /* find derrick we were building defense for */
 
6542
                _closestDerrick = closestDerrick(structure.x, structure.y);
 
6543
 
 
6544
                if(_closestDerrick == NULLOBJECT){
 
6545
                        exit;
 
6546
                }
 
6547
 
 
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
 
6551
                        exit;
 
6552
                }
 
6553
 
 
6554
                structure = _closestDerrick;            //remember derrick for defenses building
 
6555
 
 
6556
                // if(!isInMyBase(_closestDerrick.x, _closestDerrick.y))
 
6557
                // {
 
6558
                        if(manageOilSite(droid, _closestDerrick))
 
6559
                        {
 
6560
                                exit;
 
6561
                        }
 
6562
                // }
 
6563
 
 
6564
                // try to find any unoccupied oil resource
 
6565
                if(buildNextOil(droid, NEXT_OIL_RANGE, false))
 
6566
                {
 
6567
                        exit;
 
6568
                }
 
6569
        }
 
6570
        else if(structure.stat == derrick)
 
6571
        {
 
6572
                // if(!isInMyBase(structure.x, structure.y))
 
6573
                // {
 
6574
                        if(manageOilSite(droid, structure))
 
6575
                        {
 
6576
                                exit;
 
6577
                        }
 
6578
                // }
 
6579
 
 
6580
                // try to find any unoccupied oil resource
 
6581
                if(buildNextOil(droid, NEXT_OIL_RANGE, false))
 
6582
                {
 
6583
                        exit;
 
6584
                }
 
6585
        }
 
6586
        else if(structure.stattype == REF_FACTORY)      /* factory or factory module */
 
6587
        {
 
6588
                if( isStructureAvailable(facMod,me) and (skGetFactoryCapacity(structure) < 2 ))
 
6589
                {
 
6590
                        orderDroidStatsLoc(droid, DORDER_BUILD, facMod, structure.x, structure.y);      // upgrade it.
 
6591
                        exit;
 
6592
                }
 
6593
        }
 
6594
        else if(!defendingBase() and structure.stattype == REF_VTOL_FACTORY)    /* vtol factory or vtol factory module */
 
6595
        {
 
6596
                if( isStructureAvailable(facMod,me) and (skGetFactoryCapacity(structure) < 2 ))
 
6597
                {
 
6598
                        orderDroidStatsLoc(droid, DORDER_BUILD,facMod, structure.x,structure.y);        // upgrade it.
 
6599
                        exit;
 
6600
                }
 
6601
        }
 
6602
        else if(!defendingBase() and structure.stattype == REF_POWER_GEN)       /* power generator */
 
6603
        {
 
6604
                if( isStructureAvailable(powMod,me) and (not testStructureModule(me, structure, 0)))
 
6605
                {
 
6606
                        orderDroidStatsLoc(droid, DORDER_BUILD,powMod, structure.x,structure.y);        // upgrade it.
 
6607
                        exit;
 
6608
                }
 
6609
        }
 
6610
        else
 
6611
        {
 
6612
                exit;
 
6613
        }
 
6614
 
 
6615
        //if(bResult){exit;}            //already started building with this truck
 
6616
 
 
6617
/*      if(structure == NULLOBJECT){exit;}      //don't have a derrick to defend
 
6618
 
 
6619
        if(structure.stat != derrick){exit;}    //make sure we are going to build defenses for a derrick
 
6620
 
 
6621
        if(defendingBase()){exit;}
 
6622
 
 
6623
        // make the callback droid build a defence near this oil derrick
 
6624
        buildDerrickDefence(structure, droid, NEXT_OIL_RANGE); */
 
6625
}
 
6626
 
 
6627
event droidTakeOverEv(inactive)
 
6628
{
 
6629
        if(droid != NULLOBJECT)
 
6630
        {
 
6631
                if(droid.player == me)
 
6632
                {
 
6633
                        assignDroid(droid);
 
6634
                        notifyAllies(strGratitude(), false);
 
6635
                }
 
6636
        }
 
6637
        else
 
6638
        {
 
6639
                MsgBox("droidTakeOverEv - NULLOBJECT passed");
 
6640
        }
 
6641
}
 
6642
 
 
6643
//deal with a droid being built
 
6644
event droidBuilt(inactive)
 
6645
{
 
6646
        assignDroid(droid);
 
6647
 
 
6648
        // start building trucks if we need any
 
6649
        if(needTrucks()){
 
6650
                buildTrucks();
 
6651
        }
 
6652
 
 
6653
        // start build tanks
 
6654
        if((tech == techTanks) or (playerPower(me) > muchoPower))
 
6655
        {
 
6656
                // if(canBuildTanks())
 
6657
                // {
 
6658
                        buildTanks();
 
6659
                // }
 
6660
        }
 
6661
}
 
6662
 
 
6663
function void assignDroid(DROID _droid)
 
6664
{
 
6665
        local   DROID   _commander;
 
6666
 
 
6667
        if(isVtol(_droid))
 
6668
        {
 
6669
                groupAddDroid(vtolGr, _droid);
 
6670
        }
 
6671
        else if(_droid.droidType == DROID_COMMAND)
 
6672
        {
 
6673
                assignCommander(_droid, defendGr);
 
6674
        }
 
6675
        else
 
6676
        {
 
6677
                setDroidSecondary(_droid, DSO_ATTACK_RANGE, DSS_ARANGE_LONG);
 
6678
                setDroidSecondary(_droid, DSO_HALTTYPE, DSS_HALT_GUARD);
 
6679
 
 
6680
                if((_droid.droidType == DROID_CONSTRUCT) or
 
6681
                        (_droid.droidType == DROID_CYBORG_CONSTRUCT))                           // if constructor droid
 
6682
                {
 
6683
                        /* make it build anti-rush defenses if still not finished */
 
6684
                        if(!initialDefensesFinished)
 
6685
                        {
 
6686
                                if((groupSizeCmds(buildGr,true,false,true) >= 5) and (initialDefensesTruck == NULLOBJECT))
 
6687
                                {
 
6688
                                        dbg("buildInitialDefenses() assigned truck", me);
 
6689
                                        initialDefensesTruck = _droid;
 
6690
                                        buildInitialDefenses(true);
 
6691
                                        return;
 
6692
                                }
 
6693
                        }
 
6694
 
 
6695
                        // add to the build group
 
6696
                        groupAddDroid(buildGr, _droid);
 
6697
                }
 
6698
                else if(_droid.droidType == DROID_TRANSPORTER)
 
6699
                {
 
6700
                        dbg("built transporter", me);
 
6701
 
 
6702
                        temp = 0;
 
6703
                        bResult = TRUE;
 
6704
                        while((temp < 10) and bResult)
 
6705
                        {
 
6706
                                if(transporter[temp] == NULLOBJECT)
 
6707
                                {
 
6708
                                        dbg("built transporter " & temp, me);
 
6709
                                        transporter[temp] = _droid;
 
6710
                                        orderDroidLoc(_droid, DORDER_MOVE, baseX, baseY);
 
6711
                                        bResult = FALSE;
 
6712
                                }
 
6713
                                temp = temp + 1;
 
6714
                        }
 
6715
                }
 
6716
                else if((_droid.droidType == DROID_REPAIR) or
 
6717
                           (_droid.droidType == DROID_CYBORG_REPAIR))
 
6718
                {
 
6719
                        setDroidSecondary(_droid, DSO_HALTTYPE, DSS_HALT_PERSUE);
 
6720
 
 
6721
                        //commanders have priority
 
6722
                        _commander = bestCommanderWithoutRepairer();
 
6723
                        if(_commander != NULLOBJECT)
 
6724
                        {
 
6725
                                dbg("Added repeir droid to commander " & cmdToIndex(_commander), me);
 
6726
 
 
6727
                                ASSERT(_commander.droidType == DROID_COMMAND, "Droid is not a commander", me);
 
6728
 
 
6729
                                groupAddDroid(cmdRepGr[ cmdToIndex(_commander) ], _droid);
 
6730
                        }
 
6731
                        else    //add to defenders if no commander needs repair units
 
6732
                        {
 
6733
                                groupAddDroid(defendRepairGr, _droid);
 
6734
                        }
 
6735
                }
 
6736
                else if(_droid.weapon == weaponBB)
 
6737
                {
 
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);
 
6742
                }
 
6743
                else
 
6744
                {
 
6745
                        bResult = FALSE;
 
6746
 
 
6747
                        //don't add to scouts if not early-game anymore and not enough defenders
 
6748
                        bResult2 = TRUE;
 
6749
                        if((groupSizeCmds(defendGr,true,false,true) < numDefenders) and (GAME_TIME_IN_SECS > SCOUT_BUILD_TIME))
 
6750
                        {
 
6751
                                bResult2 = FALSE;
 
6752
                        }
 
6753
 
 
6754
                        if(defendingBase()){
 
6755
                                bResult2 = false;
 
6756
                        }
 
6757
 
 
6758
                        if(watchWindowDebug == WATCH_DEBUG_RESEARCH){
 
6759
                                setDebugMenuEntry("to scouts: " & addScout & "/" & lowMilitary & "/" & bResult2, 8);
 
6760
                        }
 
6761
 
 
6762
                        if((addScout == 0) and !lowMilitary and bResult2)       //for scouts?
 
6763
                        {
 
6764
                                if(groupSizeCmds(enemyScoutGr,true,false,true) < numEnemyScouts and bToEnemyScoutGr)
 
6765
                                {
 
6766
                                        // send to the scout location immediately
 
6767
                                        if(realEnemyScoutX > 0 and realEnemyScoutY > 0){
 
6768
                                                orderDroidLoc(_droid, DORDER_MOVE, realEnemyScoutX, realEnemyScoutY);
 
6769
                                        }
 
6770
 
 
6771
                                        groupAddDroid(enemyScoutGr, _droid);
 
6772
                                        bResult = TRUE;
 
6773
                                        bToEnemyScoutGr = !bToEnemyScoutGr;
 
6774
                                }
 
6775
                                else if(groupSizeCmds(scoutGr,true,false,true) < numOilScouts and !bToEnemyScoutGr)
 
6776
                                {
 
6777
                                        groupAddDroid(scoutGr, _droid);
 
6778
                                        bResult = TRUE;
 
6779
                                        bToEnemyScoutGr = !bToEnemyScoutGr;
 
6780
                                }
 
6781
                        }
 
6782
 
 
6783
                        if((addScout != 0) or !bResult)         //for attackers, or scouts were full
 
6784
                        {
 
6785
                                if((defendX != none) and (defendY != none))
 
6786
                                {
 
6787
                                        result = numFriendlyWeapObjInRange(me, defendX, defendY, (10 * 128), false, true);
 
6788
                                        result2 = numEnemyWeapObjInRange(me, defendX, defendY, (10 * 128), false, true);
 
6789
 
 
6790
                                        if((groupSizeCmds(defendGr,true,false,true) >= minDefenders) or (result >= result2))    //don't send one by one or if dangerous
 
6791
                                        {
 
6792
                                                orderDroidLoc(_droid, DORDER_SCOUT, defendX, defendY);
 
6793
                                        }
 
6794
                                }
 
6795
 
 
6796
                                groupAddDroid(defendGr, _droid);
 
6797
                                assignDroidToBestCommander(_droid, defendGr);
 
6798
 
 
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;
 
6802
                        }
 
6803
 
 
6804
                        addScout++;
 
6805
                        if(addScout > addScoutInterval)
 
6806
                        {
 
6807
                                addScout = 0;           //add to scouts next one
 
6808
                        }
 
6809
                }
 
6810
        }
 
6811
}
 
6812
 
 
6813
// Update scout variables
 
6814
function void updateMaxScouts()
 
6815
{
 
6816
        minEnemyScouts = 1;
 
6817
 
 
6818
        enemyScoutRange = (13 * 128);           //revealed when within this range
 
6819
 
 
6820
        addScout = 0;   //next tank is for scouts
 
6821
 
 
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 );
 
6825
 
 
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) *
 
6829
                                                fMapRevealFactor +
 
6830
                                                (float)MAX_SCOUTS_PRIORITY);
 
6831
        if(watchWindowDebug == WATCH_DEBUG_RESEARCH)
 
6832
        {
 
6833
                setDebugMenuEntry("addScoutInterval: " & addScoutInterval & "(" &  min(addScoutInterval, MIN_SCOUTS_PRIORITY)
 
6834
                 & "/" & max(min(addScoutInterval, MIN_SCOUTS_PRIORITY), MAX_SCOUTS_PRIORITY) & ")", 4);
 
6835
        }
 
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);
 
6839
 
 
6840
        // use 2 scouts when scouting has a high priority
 
6841
        // if(addScoutInterval <= MAX_SCOUTS_PRIORITY){
 
6842
                // maxEnemyScouts = 2;
 
6843
        // }else{
 
6844
                maxEnemyScouts = 1;
 
6845
        // }
 
6846
 
 
6847
        numEnemyScouts = maxEnemyScouts;
 
6848
 
 
6849
        if(GAME_TIME_IN_SECS <= STARTUP_PHASE_LEN){
 
6850
                dbg("addScoutInterval = " & addScoutInterval, me);
 
6851
        }
 
6852
 
 
6853
 
 
6854
        scoutStep = (25 * 128);         //inacrease search area by this value
 
6855
        scoutRange = scoutStep;         //start with small area
 
6856
 
 
6857
        enemyScoutX = none;
 
6858
        enemyScoutY = none;
 
6859
 
 
6860
        enemyScoutStep = (18 * 128);
 
6861
 
 
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;
 
6866
 
 
6867
        //adapt for big maps
 
6868
        if(bigMap)
 
6869
        {
 
6870
                enemyScoutStep = (25 * 128);
 
6871
 
 
6872
                maxOilScouts++;
 
6873
                scoutStep = scoutStep + (TILE * 12);
 
6874
                scoutRange = scoutStep;
 
6875
        }
 
6876
 
 
6877
        numOilScouts = maxOilScouts;
 
6878
}
 
6879
 
 
6880
//Group can be NULLOBJECT
 
6881
function DROID closestDroidByGroup(GROUP _group, int _x, int _y, bool _bIncludeCommanders)
 
6882
{
 
6883
        local   DROID   _droid,_closestDroid;
 
6884
        local   int             _closestDistance,_dist,_bucket;
 
6885
 
 
6886
        _closestDistance = 99999;
 
6887
        _closestDroid = NULLOBJECT;
 
6888
 
 
6889
        if(_group != NULLOBJECT)
 
6890
        {
 
6891
                _bucket = initIterateGroupCmd(_group,true,_bIncludeCommanders,_bIncludeCommanders);
 
6892
                _droid = iterateGroupCmd(_group, _bucket);
 
6893
                while(_droid != NULLOBJECT)
 
6894
                {
 
6895
                        //calculate the distance between the _commander and droid
 
6896
                        _dist = distBetweenTwoPoints(_x, _y, _droid.x, _droid.y);
 
6897
 
 
6898
                        if(_dist < _closestDistance)
 
6899
                        {
 
6900
                                _closestDistance = _dist;
 
6901
                                _closestDroid = _droid;
 
6902
                        }
 
6903
 
 
6904
                        _droid = iterateGroupCmd(_group,_bucket);
 
6905
                }
 
6906
        }
 
6907
 
 
6908
        return _closestDroid;
 
6909
}
 
6910
 
 
6911
        /************************************
 
6912
                        COMMANDER STUFF
 
6913
        *************************************/
 
6914
/* Unassign all droids from all commanders belonging to a certain group */
 
6915
function void unassignAllDroidsFromCMDsFromGroup(GROUP _unassignGroup, GROUP _toGroup)
 
6916
{
 
6917
        local   int             _cmdIndex;
 
6918
 
 
6919
        _cmdIndex = 0;
 
6920
        while(_cmdIndex < MAX_COMMANDERS)
 
6921
        {
 
6922
                if(cmds[_cmdIndex] != NULLOBJECT)
 
6923
                {
 
6924
                        if((_unassignGroup == NULLOBJECT) or (_unassignGroup == cmdGr[_cmdIndex]))
 
6925
                        {
 
6926
                                unassignAllDroidsFromCMD(cmds[_cmdIndex], _toGroup);
 
6927
                        }
 
6928
                }
 
6929
                _cmdIndex++;
 
6930
        }
 
6931
}
 
6932
 
 
6933
/* Unassign all units from a commander */
 
6934
function void unassignAllDroidsFromCMD(DROID _commander, GROUP _toGroup)
 
6935
{
 
6936
        local   GROUP   _cmdGroup;
 
6937
        local   DROID   _groupMember;
 
6938
 
 
6939
        ASSERT(_commander != NULLOBJECT,
 
6940
                "unassignAllDroidsFromCMD: _commander is NULL", me);
 
6941
 
 
6942
        _cmdGroup = _commander.group;
 
6943
 
 
6944
        initIterateGroup(_cmdGroup);
 
6945
        _groupMember = iterateGroup(_cmdGroup);
 
6946
        while(_groupMember != NULLOBJECT)
 
6947
        {
 
6948
                ASSERT(_groupMember.droidType != DROID_COMMAND,
 
6949
                        "unassignAllDroidsFromCMD: unassigning a commander from a commander group?", me);
 
6950
 
 
6951
                //droidLeaveGroup(_groupMember);
 
6952
                groupAddDroid(_toGroup, _groupMember);
 
6953
                _groupMember = iterateGroup(_cmdGroup);
 
6954
        }
 
6955
}
 
6956
 
 
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)
 
6959
{
 
6960
        local   int             _cmdIndex,_bestCMDKills,_tmpCmdKills,_bestCost,_tmpCost,
 
6961
                                        _bucket,_bestCmdMaxDroids;
 
6962
        local   DROID   _droid,_bestCMD,_bestDroid;
 
6963
        local   bool    _bStop;
 
6964
 
 
6965
        _bStop = false;
 
6966
 
 
6967
        while(!_bStop and               // still have more commanders
 
6968
                groupSizeCmds(_fromGroup, true, false, false) > 0)      //only count unassigned droids
 
6969
        {
 
6970
                _cmdIndex = 0;
 
6971
                _bestCMDKills = (-1);
 
6972
                _bestCMD = NULLOBJECT;
 
6973
 
 
6974
                while(_cmdIndex < MAX_COMMANDERS)
 
6975
                {
 
6976
                        // find best commander with highest rank
 
6977
                        if(cmds[_cmdIndex] != NULLOBJECT)
 
6978
                        {
 
6979
                                if( (_toGroup == cmdGr[_cmdIndex]) and                  //the right group
 
6980
                                        (cmds[_cmdIndex].group.members < cmdDroidMaxGroup(cmds[_cmdIndex])) )   //commander can take more droids
 
6981
                                {
 
6982
                                        _tmpCmdKills = getDroidKills(cmds[_cmdIndex]);
 
6983
 
 
6984
                                        if(_tmpCmdKills > _bestCMDKills)
 
6985
                                        {
 
6986
                                                _bestCMD = cmds[_cmdIndex];
 
6987
                                                _bestCMDKills = _tmpCmdKills;
 
6988
                                        }
 
6989
                                }
 
6990
                        }
 
6991
                        _cmdIndex++;
 
6992
                }
 
6993
 
 
6994
                //Now fill droids for the best found commander
 
6995
                if(_bestCMD != NULLOBJECT)
 
6996
                {
 
6997
                        //find out how many droid this commander can have assigned
 
6998
                        _bestCmdMaxDroids = cmdDroidMaxGroup(_bestCMD);
 
6999
 
 
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
 
7002
                        {
 
7003
                                _bestCost = (-1);
 
7004
                                _bestDroid = NULLOBJECT;
 
7005
 
 
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)
 
7010
                                {
 
7011
                                        _tmpCost = calcDroidPower(_droid);
 
7012
 
 
7013
                                        if(_tmpCost > _bestCost)
 
7014
                                        {
 
7015
                                                _bestCost = _tmpCost;
 
7016
                                                _bestDroid = _droid;
 
7017
                                        }
 
7018
 
 
7019
                                        _droid = iterateGroupCmd(_fromGroup,_bucket);
 
7020
                                }
 
7021
 
 
7022
                                //Add best droid to the best commander
 
7023
                                cmdDroidAddDroid(_bestCMD, _bestDroid);
 
7024
                        }
 
7025
                }
 
7026
                else
 
7027
                {
 
7028
                        _bStop = true;  //No more commanders left, stop here
 
7029
                }
 
7030
        }
 
7031
 
 
7032
}
 
7033
 
 
7034
/* Uses MCDM */
 
7035
function void assignDroidToBestCommander(DROID _droid, GROUP _group)
 
7036
{
 
7037
        local   int             _cmdIndex,_tilesPerDroid,_tilesPerRank,_tileDist,_bestScore,
 
7038
                                        _score,_rank,_cmdGroupSize;
 
7039
        local   DROID   _bestCommander;
 
7040
 
 
7041
        _tilesPerDroid = (TILE * 3);    //1 droid = 3 tiles
 
7042
        _tilesPerRank = (TILE * 7);             //1 rank higher = 6 tiles
 
7043
 
 
7044
        _bestScore = (-99999);
 
7045
        _bestCommander = NULLOBJECT;
 
7046
 
 
7047
        //find the most suitable commander, consider distance to the commander, size of its group and commander rank
 
7048
        _cmdIndex = 0;
 
7049
        while(_cmdIndex < MAX_COMMANDERS)
 
7050
        {
 
7051
                if(cmds[_cmdIndex] != NULLOBJECT)
 
7052
                {
 
7053
                        //if group is specified make sure commander belongs to this group
 
7054
                        if((_group == NULLOBJECT) or (cmdGr[_cmdIndex] == _group))
 
7055
                        {
 
7056
                                //skip commanders who already have a full group
 
7057
                                if(cmds[_cmdIndex].group.members < cmdDroidMaxGroup(cmds[_cmdIndex]))
 
7058
                                {
 
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
 
7063
 
 
7064
                                        _rank = getDroidRank(cmds[_cmdIndex]);
 
7065
                                        _cmdGroupSize = cmds[_cmdIndex].group.members;
 
7066
 
 
7067
                                        //calculate score
 
7068
                                        _score = _rank * _tilesPerRank - _cmdGroupSize * _tilesPerDroid - _dist;
 
7069
 
 
7070
                                        //check if this commander is the best one so far
 
7071
                                        if(_score > _bestScore)
 
7072
                                        {
 
7073
                                                _bestScore = _score;
 
7074
                                                _bestCommander = cmds[_cmdIndex];
 
7075
                                        }
 
7076
                                }
 
7077
                        }
 
7078
                }
 
7079
 
 
7080
                _cmdIndex++;
 
7081
        }
 
7082
 
 
7083
        //add droid to the group of the best suitable commander
 
7084
        if(_bestCommander != NULLOBJECT)
 
7085
        {
 
7086
                cmdDroidAddDroid(_bestCommander, _droid);
 
7087
        }
 
7088
}
 
7089
 
 
7090
//Store a newly built comander
 
7091
function void assignCommander(DROID _newCommander, GROUP _group)
 
7092
{
 
7093
        local   int             _index;
 
7094
 
 
7095
        // FIXME: number of commander can exceed MAX_COMMANDERS
 
7096
 
 
7097
        _index = 0;
 
7098
        while(_index < MAX_COMMANDERS)
 
7099
        {
 
7100
                if(cmds[_index] == NULLOBJECT)          //found a free slot
 
7101
                {
 
7102
                        //store commander
 
7103
                        cmds[_index] = _newCommander;
 
7104
                        cmdGr[_index] = _group;                 //set group commander belongs to
 
7105
 
 
7106
                        //Add droids without commander to the new commander
 
7107
                        fillCommanderGroup(_newCommander, _group);
 
7108
 
 
7109
                        return;
 
7110
                }
 
7111
                _index++;
 
7112
        }
 
7113
}
 
7114
 
 
7115
/* Add droids to the _commander */
 
7116
function void fillCommanderGroup(DROID _commander, GROUP _fillFromGroup)
 
7117
{
 
7118
        local   GROUP   _cmdGroup;
 
7119
        local   DROID   _droid,_closestDroid;
 
7120
        local   int             _freeCapacity,_index,_closestDistance,_cmdX,_cmdY,_dist;
 
7121
 
 
7122
        _cmdGroup = _commander.group;
 
7123
 
 
7124
        //Find out how many droids this commander can have in a group
 
7125
        _freeCapacity = cmdDroidMaxGroup(_commander) - _cmdGroup.members;
 
7126
 
 
7127
        _cmdX = _commander.x;
 
7128
        _cmdY = _commander.x;
 
7129
 
 
7130
        _index = 0;
 
7131
        while(_index < _freeCapacity)
 
7132
        {
 
7133
                _closestDroid = NULLOBJECT;
 
7134
                _closestDistance = 99999;
 
7135
 
 
7136
                _closestDroid = closestDroidByGroup(_fillFromGroup, _commander.x, _commander.y, false);
 
7137
 
 
7138
                //Add found droid to the _commander
 
7139
                if(_closestDroid != NULLOBJECT)
 
7140
                {
 
7141
                        cmdDroidAddDroid(_commander, _closestDroid);
 
7142
                }
 
7143
 
 
7144
                _index++;
 
7145
        }
 
7146
 
 
7147
        dbg("Adding " & _index & "/" & _freeCapacity & " to the commander", me);
 
7148
}
 
7149
 
 
7150
/* Check if we can build commanders */
 
7151
function bool canUseCommanders()
 
7152
{
 
7153
        haveCommandTech = researchFinished(resCmd, me);
 
7154
 
 
7155
        if(haveCommandTech)
 
7156
        {
 
7157
                if(structureBuilt(cmdCenter, me))               //make sure command center is finished building
 
7158
                {
 
7159
                        return true;
 
7160
                }
 
7161
        }
 
7162
 
 
7163
        return false;
 
7164
}
 
7165
 
 
7166
/* Returns number of commanders */
 
7167
function int getNumCommanders()
 
7168
{
 
7169
        /* local        int             _index,_numCmds;
 
7170
 
 
7171
        _numCmds = 0;
 
7172
        _index = 0;
 
7173
        while(_index < MAX_COMMANDERS)
 
7174
        {
 
7175
                if(cmds[_index] != NULLOBJECT)
 
7176
                {
 
7177
                        _numCmds++;
 
7178
                }
 
7179
                _index++;
 
7180
        }
 
7181
 
 
7182
        return _numCmds; */
 
7183
 
 
7184
        return numDroidsByComponent(cmdTurret, me, me);
 
7185
}
 
7186
 
 
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)
 
7189
{
 
7190
        local   int             _index,_numDroids;
 
7191
 
 
7192
        _numDroids = 0;
 
7193
        _index = 0;
 
7194
        while(_index < MAX_COMMANDERS)
 
7195
        {
 
7196
                if(cmds[_index] != NULLOBJECT)
 
7197
                {
 
7198
                        if((_group == NULLOBJECT) or (cmdGr[_index] == _group))         //make sure commander belongs to the right group
 
7199
                        {
 
7200
                                _numDroids = _numDroids + cmdDroidMaxGroup(cmds[_index]);
 
7201
                        }
 
7202
                }
 
7203
                _index++;
 
7204
        }
 
7205
 
 
7206
        //Check if we have to include commanders that are getting built now
 
7207
        if(_bIncludeInProduction)
 
7208
        {
 
7209
                _numDroids = _numDroids + numCommandersInProduction() * CMD_INIT_CAPACITY;
 
7210
        }
 
7211
 
 
7212
        return _numDroids;
 
7213
}
 
7214
 
 
7215
/* Returns total number of droids that can still be assigned to commanders belonging to a certain group */
 
7216
function int getFreeCmdsCapacityInGroup(GROUP _group)
 
7217
{
 
7218
        local   int             _index,_numDroids;
 
7219
 
 
7220
        _numDroids = 0;
 
7221
        _index = 0;
 
7222
        while(_index < MAX_COMMANDERS)
 
7223
        {
 
7224
                if(cmds[_index] != NULLOBJECT)
 
7225
                {
 
7226
                        if((_group == NULLOBJECT) or (cmdGr[_index] == _group))         //make sure commander belongs to the right group
 
7227
                        {
 
7228
                                _numDroids = _numDroids +
 
7229
                                        cmdDroidMaxGroup(cmds[_index]) - cmds[_index].group.members;
 
7230
                        }
 
7231
                }
 
7232
                _index++;
 
7233
        }
 
7234
 
 
7235
        return _numDroids;
 
7236
}
 
7237
 
 
7238
/* fill commanders with highest rank into some group until some tatal capacity is reached */
 
7239
function void fillBestCommandersCapacity(int _maxCapacity, GROUP _newGroup,
 
7240
                                                                                                                        GROUP _oldGroup)
 
7241
{
 
7242
        local int       _curCapacity,_cmdIndex,_bestKills,_tmpKills,_bestCMDIndex;
 
7243
        local bool      _bCMDsLeftToIterate;
 
7244
        local DROID     _bestCommander;
 
7245
 
 
7246
        dbg("fillBestCommandersCapacity: _maxCapacity = " & _maxCapacity, me);
 
7247
 
 
7248
        _curCapacity = 0;
 
7249
        _cmdIndex = 0;
 
7250
 
 
7251
        //make sure there are commanders left in the old group we can iterate over
 
7252
        _bCMDsLeftToIterate = (groupSizeCmds(_oldGroup, false, true, false) > 0);
 
7253
 
 
7254
        //iterate over all commanders until capacity is filled or no commanders left in the old group
 
7255
        while((_curCapacity < _maxCapacity) and _bCMDsLeftToIterate)
 
7256
        {
 
7257
                _cmdIndex = 0;
 
7258
                _bestKills = (-1);
 
7259
                _bestCMDIndex = (-1);
 
7260
                _bestCommander = NULLOBJECT;
 
7261
 
 
7262
                while(_cmdIndex < MAX_COMMANDERS)
 
7263
                {
 
7264
                        if(cmds[_cmdIndex] != NULLOBJECT)
 
7265
                        {
 
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
 
7268
                                {
 
7269
                                        _tmpKills = getDroidKills(cmds[_cmdIndex]);
 
7270
 
 
7271
                                        if(_tmpKills > _bestKills)
 
7272
                                        {
 
7273
                                                _bestCommander = cmds[_cmdIndex];
 
7274
                                                _bestCMDIndex = _cmdIndex;
 
7275
                                                _bestKills = _tmpKills;
 
7276
                                        }
 
7277
                                }
 
7278
                        }
 
7279
                        _cmdIndex++;
 
7280
                }
 
7281
 
 
7282
                // add commander with the most kills to the new group
 
7283
                if(_bestCommander != NULLOBJECT)
 
7284
                {
 
7285
                        cmdGr[_bestCMDIndex] = _newGroup;       //change commander's group
 
7286
                        _curCapacity = _curCapacity + cmdDroidMaxGroup(_bestCommander);
 
7287
                }
 
7288
 
 
7289
                //make sure there are commanders left in the old group we can iterate over
 
7290
                _bCMDsLeftToIterate = (groupSizeCmds(_oldGroup, false, true, false) > 0);
 
7291
        }
 
7292
}
 
7293
 
 
7294
/* Goes through all commander groups and counts how many repairers are missing in total */
 
7295
function int numMissingCmdRepairers(int _groupIndex, bool _bIncludeDeadCmds)
 
7296
{
 
7297
        local   int             _numMissing,_index;
 
7298
 
 
7299
        _index = 0;
 
7300
        _numMissing = 0;
 
7301
        while(_index < MAX_COMMANDERS)
 
7302
        {
 
7303
                if(_bIncludeDeadCmds or (cmds[_index] != NULLOBJECT))
 
7304
                {
 
7305
                        if((_groupIndex < 0) or (_index == _groupIndex))
 
7306
                        {
 
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))
 
7310
                                {
 
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
 
7313
                                }
 
7314
                        }
 
7315
                }
 
7316
                _index++;
 
7317
        }
 
7318
 
 
7319
        return _numMissing;
 
7320
}
 
7321
 
 
7322
/* Returns the commander the deserves to get a new repair unit */
 
7323
function DROID bestCommanderWithoutRepairer()
 
7324
{
 
7325
        local   int                     _index,_tmpScore,_bestScore;
 
7326
        local   DROID           _bestCommander,_commander;
 
7327
 
 
7328
        _bestScore = 0;
 
7329
        _index = 0;
 
7330
        _bestCommander = NULLOBJECT;
 
7331
        while(_index < MAX_COMMANDERS)
 
7332
        {
 
7333
                if(cmds[_index] != NULLOBJECT)
 
7334
                {
 
7335
                        //make sure this commander still needs repair units
 
7336
                        if(cmdRepGr[_index].members < NUM_REPAIRS_FOR_CMD)      //not to omany
 
7337
                        {
 
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
 
7342
 
 
7343
                                if(_tmpScore > _bestScore)
 
7344
                                {
 
7345
                                        _bestScore = _tmpScore;
 
7346
                                        _bestCommander = cmds[_index];
 
7347
                                }
 
7348
                        }
 
7349
                }
 
7350
                _index++;
 
7351
        }
 
7352
 
 
7353
        return _bestCommander;
 
7354
}
 
7355
 
 
7356
 
 
7357
//==============================================================================================
 
7358
//      >>>>>>>>>>>>>>>>>>>>>>>>        MILITARY STUFF          <<<<<<<<<<<<<<<<<<<<<<<<<
 
7359
//==============================================================================================
 
7360
 
 
7361
event manageCMDRepairsEv(inactive)
 
7362
{
 
7363
        repairCMDGroup();
 
7364
}
 
7365
 
 
7366
/* Repair and follow commanders */
 
7367
function void repairCMDGroup()
 
7368
{
 
7369
        local   int             _cmdIndex,_x,_y,_maxDistanceFromCMD,_bucket,_distanceFromCMD;
 
7370
        local   DROID   _repairer,_droidToRepair,_commanderToRepair;
 
7371
        local   bool    _bBusy;
 
7372
 
 
7373
        _bBusy = false;
 
7374
 
 
7375
        _cmdIndex = 0;
 
7376
        while(_cmdIndex < MAX_COMMANDERS)
 
7377
        {
 
7378
                if((cmds[_cmdIndex] != NULLOBJECT) and (cmdRepGr[_cmdIndex].members > 0))
 
7379
                {
 
7380
                        // see if we have to repair commander
 
7381
                        _commanderToRepair = NULLOBJECT;
 
7382
                        if(cmds[_cmdIndex].health < 95){
 
7383
                                _commanderToRepair = cmds[_cmdIndex];
 
7384
                        }
 
7385
 
 
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)
 
7390
                        {
 
7391
                                _bBusy = false;
 
7392
 
 
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]) )
 
7396
                                {
 
7397
                                        // see if we have to repair our commander
 
7398
                                        if(_commanderToRepair != NULLOBJECT)
 
7399
                                        {
 
7400
                                                _bBusy = true;
 
7401
                                                orderDroidObj(_repairer, DORDER_DROIDREPAIR, _commanderToRepair);
 
7402
                                        }
 
7403
                                        else    // see if we have to come closer to the commander if we are not already on the way to the commander
 
7404
                                        {
 
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)))
 
7409
                                                {
 
7410
                                                        _maxDistanceFromCMD = MAX_REP_DIST_FROM_CMD_WHILE_REP;
 
7411
                                                }
 
7412
 
 
7413
                                                // find cur dist to the commander
 
7414
                                                _distanceFromCMD = distBetweenTwoPoints(cmds[_cmdIndex].x,
 
7415
                                                                                        cmds[_cmdIndex].y, _repairer.x, _repairer.y);
 
7416
 
 
7417
                                                if(_distanceFromCMD > _maxDistanceFromCMD)      // too far away from commander
 
7418
                                                {
 
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) )) )
 
7423
                                                        {
 
7424
                                                                _x = baseX;             //_repairer.x;
 
7425
                                                                _y = baseY;             //_repairer.y;
 
7426
 
 
7427
                                                                _bBusy = true;
 
7428
 
 
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);
 
7431
 
 
7432
                                                                dbg("Moving repairer to commander " & _cmdIndex & "(" & _x / TILE & "-" & _y / TILE & ")", me);
 
7433
                                                        }
 
7434
                                                }
 
7435
                                        }
 
7436
 
 
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
 
7440
                                        {
 
7441
                                                // find a damaged unit
 
7442
                                                _droidToRepair = findCMDGroupObjectToRepair(_cmdIndex, _repairer);
 
7443
 
 
7444
                                                if(_droidToRepair != NULLOBJECT)
 
7445
                                                {
 
7446
                                                        // order repair droid to repair this unit
 
7447
                                                        if(_droidToRepair != NULLOBJECT){
 
7448
                                                                orderDroidObj(_repairer, DORDER_DROIDREPAIR, _droidToRepair);
 
7449
                                                        }
 
7450
                                                }
 
7451
                                        }
 
7452
                                }
 
7453
                                _repairer = iterateGroupCmd(cmdRepGr[_cmdIndex],_bucket);
 
7454
                        }
 
7455
                }
 
7456
                _cmdIndex++;
 
7457
        }
 
7458
}
 
7459
 
 
7460
/* Find a droid commander repairs should repair */
 
7461
function DROID findCMDGroupObjectToRepair(int _cmdIndex, DROID _repairer)
 
7462
{
 
7463
        local   DROID   _choiceDroid,_droid,_mostDamagedDroid,_damagedRepairer;
 
7464
        local   int             _mostDamage,_tempDamage,_tempScore,_bestScore,_bucket,
 
7465
                                        _distScore,_damageScore,_dist;
 
7466
 
 
7467
        _choiceDroid = NULLOBJECT;
 
7468
        _mostDamagedDroid = NULLOBJECT;
 
7469
 
 
7470
        if(_cmdIndex >= MAX_COMMANDERS){
 
7471
                return _choiceDroid;
 
7472
        }
 
7473
 
 
7474
        // find a damaged repair unit
 
7475
        _mostDamage = 0;
 
7476
        _choiceDroid = NULLOBJECT;
 
7477
        _bucket = initIterateGroupCmd(cmdRepGr[_cmdIndex],true,true,true);
 
7478
        _damagedRepairer = iterateGroupCmd(cmdRepGr[_cmdIndex],_bucket);
 
7479
        while(_damagedRepairer != NULLOBJECT)
 
7480
        {
 
7481
                // make sure we are not going to repair ourselves
 
7482
                if(_damagedRepairer != _repairer)
 
7483
                {
 
7484
                        _tempDamage = 100 - _damagedRepairer.health;
 
7485
 
 
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)
 
7489
                        {
 
7490
                                // remember the most damaged repair unit
 
7491
                                if(_tempDamage > _mostDamage)
 
7492
                                {
 
7493
                                        _mostDamage = _tempDamage;
 
7494
                                        _choiceDroid = _damagedRepairer;
 
7495
                                }
 
7496
                        }
 
7497
                }
 
7498
                _damagedRepairer = iterateGroupCmd(cmdRepGr[_cmdIndex],_bucket);
 
7499
        }
 
7500
 
 
7501
        // see if repair unit is slightly damaged
 
7502
        if(_choiceDroid != NULLOBJECT)
 
7503
        {
 
7504
                if(_choiceDroid.health < 90)
 
7505
                {
 
7506
                        return _choiceDroid;
 
7507
                }
 
7508
        }
 
7509
 
 
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)
 
7516
        {
 
7517
                // find out how far the damaged unit is from the repairer
 
7518
                _dist = distBetweenTwoPoints(_repairer.x,_repairer.y,_droid.x,_droid.y);
 
7519
 
 
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))
 
7522
                {
 
7523
                        // the closer the better
 
7524
                        _distScore = _dist / TILE;
 
7525
 
 
7526
                        // the more damaged the better
 
7527
                        _damageScore = (100 - _droid.health);
 
7528
 
 
7529
                        // calculate final score
 
7530
                        _tempScore = (int)((float)_damageScore * 2.3) - _distScore;
 
7531
 
 
7532
                        // remember the most damaged repair unit
 
7533
                        if(_tempScore > _bestScore)
 
7534
                        {
 
7535
                                _bestScore = _tempScore;
 
7536
                                _choiceDroid = _droid;
 
7537
                        }
 
7538
                }
 
7539
 
 
7540
                _droid = iterateGroupCmd(cmdRepGr[_cmdIndex],_bucket);
 
7541
        }
 
7542
 
 
7543
        // see if this unit is really damaged and needs to be repaired
 
7544
        if(_choiceDroid != NULLOBJECT)
 
7545
        {
 
7546
                return _choiceDroid;
 
7547
        }
 
7548
 
 
7549
        _choiceDroid = NULLOBJECT;
 
7550
 
 
7551
        return _choiceDroid;
 
7552
}
 
7553
 
 
7554
function bool repairDamagedDefenses(int _repairx, int _repairy, DROID _truck,
 
7555
                                                                        int _minDamage, int _maxRange)
 
7556
{
 
7557
        local   int                     _def,_mostDamage,_tempDamage;
 
7558
        local   STRUCTURE       _defense, _mostDamagedDefense;
 
7559
 
 
7560
        _mostDamage = 0;
 
7561
        _mostDamagedDefense = NULLOBJECT;
 
7562
 
 
7563
        _def = numDef;
 
7564
        while(_def >= 0)
 
7565
        {
 
7566
                initEnumStruct(FALSE,def[_def],me,me);
 
7567
                _defense = enumStruct();
 
7568
                while(_defense != NULLOBJECT)
 
7569
                {
 
7570
                        if(distBetweenTwoPoints(_defense.x, _defense.y, _repairx, _repairy) < _maxRange)
 
7571
                        {
 
7572
                                if(!buildingSiteBlocked(_truck, _maxRange, _defense.x, _defense.y, true))
 
7573
                                {
 
7574
                                        _tempDamage = 100 - _defense.health;
 
7575
 
 
7576
                                        // damaged at least by _minDamage %
 
7577
                                        if(_tempDamage >= _minDamage)
 
7578
                                        {
 
7579
                                                // remember the most damaged defense
 
7580
                                                if(_tempDamage > _mostDamage)
 
7581
                                                {
 
7582
                                                        _mostDamage = _tempDamage;
 
7583
                                                        _mostDamagedDefense = _defense;
 
7584
                                                }
 
7585
                                        }
 
7586
                                }
 
7587
                        }
 
7588
                        _defense = enumStruct();
 
7589
                }
 
7590
 
 
7591
                _def--;
 
7592
        }
 
7593
 
 
7594
        if(_mostDamagedDefense != NULLOBJECT)
 
7595
        {
 
7596
                orderDroidObj(_truck, DORDER_REPAIR, _mostDamagedDefense);
 
7597
                return true;
 
7598
        }
 
7599
 
 
7600
        return false;
 
7601
}
 
7602
 
 
7603
event repairDefendDroids(inactive)
 
7604
{
 
7605
        if(groupSizeCmds(defendRepairGr,true,false,true) == 0){exit;}
 
7606
        if(groupSizeCmds(defendGr,true,true,true) == 0){exit;}
 
7607
 
 
7608
        groupRepairGroup(defendGr, defendRepairGr);
 
7609
 
 
7610
        /* repair the repair droids if idle */
 
7611
        if((groupSizeCmds(defendRepairGr,true,false,true) > 1) and (idleGroupCmd(defendRepairGr,true,false) > 0))
 
7612
        {
 
7613
                groupRepairGroup(defendGr, defendRepairGr);
 
7614
        }
 
7615
}
 
7616
 
 
7617
function void groupRepairGroup(GROUP _damagedGr, GROUP _repairerGr)
 
7618
{
 
7619
        local   int     _bucket;
 
7620
 
 
7621
        _temp = maxDamageLevels - 1;    //start with heavyDamage, don't reset before loop to save CPU time
 
7622
        _temp2 = 0;
 
7623
 
 
7624
        _bucket = initIterateGroupCmd(_repairerGr,true,false,true);
 
7625
        _droid = iterateGroupCmd(_repairerGr,_bucket);
 
7626
        while(_droid != NULLOBJECT)
 
7627
        {
 
7628
                if(_droid.order != DORDER_DROIDREPAIR)  //not already busy
 
7629
                {
 
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
 
7633
                        {
 
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)
 
7637
                                {
 
7638
                                        _temp = _temp - 1;      //go to lighter damage levels
 
7639
                                }
 
7640
                        }
 
7641
 
 
7642
                        if((_droid2 != NULLOBJECT) and (_droid != _droid2))     //found someone and him going to repair himself
 
7643
                        {
 
7644
                                //dbg("FOUND DAMAGED UNIT!!!! (for unit " & _temp2 & ")", me);
 
7645
                                orderDroidObj(_droid, DORDER_DROIDREPAIR, _droid2);
 
7646
                        }
 
7647
                        else if(droidOrderIdle(_droid) or (_droid.target == _droid))    //if idle or auto-repairing
 
7648
                        {
 
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
 
7652
                                //{
 
7653
                                //      _range = baseRange;     //move closer to base
 
7654
                                //}
 
7655
 
 
7656
                                _range = baseRange;
 
7657
 
 
7658
                                if(distBetweenTwoPoints(_droid.x, _droid.y, baseX, baseY) > _range)
 
7659
                                {
 
7660
                                        //dbg("ORDERING REPAIR UNIT BACK TO BASE", me);
 
7661
                                        _x = _droid.x;
 
7662
                                        _y = _droid.y;
 
7663
                                        circlePerimPoint(baseX, baseY, ref _x, ref _y, baseRange);      //send back to base
 
7664
                                        orderDroidLoc(_droid, DORDER_MOVE, _x, _y);
 
7665
                                }
 
7666
                        }
 
7667
 
 
7668
                        //don't reset _temp and don't start over for every repair unit, since nothing changes
 
7669
                }
 
7670
 
 
7671
                _temp2++;
 
7672
                _droid = iterateGroupCmd(_repairerGr,_bucket);
 
7673
        }
 
7674
}
 
7675
 
 
7676
/* Goes through trucks and compares target */
 
7677
function DROID getTruckByTarget(BASEOBJ _target)
 
7678
{
 
7679
        local   DROID   _droid;
 
7680
        local   int     _bucket;
 
7681
 
 
7682
        _bucket = initIterateGroupCmd(buildGr,true,false,true);
 
7683
        _droid = iterateGroupCmd(buildGr,_bucket);
 
7684
        while(_droid != NULLOBJECT)
 
7685
        {
 
7686
                if(_droid.target == _target)
 
7687
                        return _droid;
 
7688
 
 
7689
                _droid = iterateGroupCmd(buildGr,_bucket);
 
7690
        }
 
7691
 
 
7692
        return NULLOBJECT;
 
7693
}
 
7694
 
 
7695
/* Number of BB templates a player is currently building */
 
7696
function int numBBsInProduction(int _player)
 
7697
{
 
7698
        local   int                     _index,_numBBsInProd;
 
7699
 
 
7700
        _index = 0;
 
7701
        _numBBsInProd = 0;
 
7702
        while(_index < numBBTempl)
 
7703
        {
 
7704
                _numBBsInProd = _numBBsInProd + numTemplatesInProduction(tmplBB[_index], _player);
 
7705
                _index++;
 
7706
        }
 
7707
 
 
7708
        return _numBBsInProd;
 
7709
}
 
7710
 
 
7711
function int numBuildersInProduction(int _player)
 
7712
{
 
7713
        local   int                     _index,_numBuildersInProd;
 
7714
 
 
7715
        /* Trucks */
 
7716
        _index = 0;
 
7717
        _numBuildersInProd = 0;
 
7718
        while(_index < numTruckTmpl)
 
7719
        {
 
7720
                _numBuildersInProd = _numBuildersInProd +
 
7721
                        numTemplatesInProduction(truck[_index], _player);
 
7722
 
 
7723
                _index++;
 
7724
        }
 
7725
 
 
7726
        /* Cyborg Engineers */
 
7727
        _numBuildersInProd = _numBuildersInProd +
 
7728
                numTemplatesInProduction(cybEngineer,me);       //engineers
 
7729
 
 
7730
        return _numBuildersInProd;
 
7731
}
 
7732
 
 
7733
function int numCommandersInProduction()
 
7734
{
 
7735
        local   int                     _index,_numCmdsInProd;
 
7736
 
 
7737
        _index = 0;
 
7738
        _numCmdsInProd = 0;
 
7739
        while(_index < numCmdTmpl)
 
7740
        {
 
7741
                _numCmdsInProd = _numCmdsInProd + numTemplatesInProduction(tmplCmd[_index], me);
 
7742
                _index++;
 
7743
        }
 
7744
 
 
7745
        return _numCmdsInProd;
 
7746
}
 
7747
 
 
7748
function bool needStartupScouts()
 
7749
{
 
7750
        if(GAME_TIME_IN_SECS > SCOUT_BUILD_TIME){
 
7751
                return false;
 
7752
        }
 
7753
 
 
7754
        if(groupSizeCmds(enemyScoutGr,true,false,true) == 0){
 
7755
                return true;
 
7756
        }
 
7757
 
 
7758
        if(groupSizeCmds(scoutGr,true,false,true) == 0){
 
7759
                return true;
 
7760
        }
 
7761
 
 
7762
        return false;
 
7763
}
 
7764
 
 
7765
function bool canBuildTanks()
 
7766
{
 
7767
        // make sure we didn't build too many units already
 
7768
        if(getDroidCount(me) >= unitLimit){
 
7769
                return false;
 
7770
        }
 
7771
 
 
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
 
7776
        {
 
7777
                return true;
 
7778
        }
 
7779
 
 
7780
        return false;
 
7781
}
 
7782
 
 
7783
function void buildTanks()
 
7784
{
 
7785
        local   int                     _numTotalCommanders,_index,_numNeedCmds,
 
7786
                                                _result,_result2,_facNum,_tmplGroup,_numDroidsNoCmd,
 
7787
                                                _needTotalRepairers,_minUnassignedDroids,_needBBs,
 
7788
                                                _maxBodySize;
 
7789
        local   bool            _bStartedBuild;
 
7790
        local   STRUCTURE       _factory;
 
7791
        local   TEMPLATE        _bestTankATTemplate;
 
7792
 
 
7793
        //dbg(" " & me & ")  Executing buildTanks()");
 
7794
 
 
7795
        _facNum = 0;
 
7796
 
 
7797
        /* decide if want to use heavy templates */
 
7798
        _tmplGroup = 0;
 
7799
        // TODO: fix heavy templates
 
7800
        // if((playerPower(me) > muchoPower) and !defendingBase())
 
7801
        // {
 
7802
                // _tmplGroup = 1;
 
7803
        // }
 
7804
 
 
7805
        //Calculate how many commanders we have and how many are being built
 
7806
        _numTotalCommanders = getNumCommanders() + numCommandersInProduction();
 
7807
 
 
7808
        // calc how many repairers we still need
 
7809
        _needTotalRepairers = numNeedRepairers();
 
7810
 
 
7811
 
 
7812
        initEnumStruct(FALSE,fac,me,me);
 
7813
        _factory = enumStruct();
 
7814
        while(_factory != NULLOBJECT)
 
7815
        {
 
7816
                if(structureComplete(_factory))
 
7817
                {
 
7818
                        _facNum = _facNum + 1;          //'id' of fac
 
7819
 
 
7820
                        if(structureIdle(_factory))
 
7821
                        {
 
7822
                                _bStartedBuild = FALSE;
 
7823
 
 
7824
                                /* Build commanders */
 
7825
                                if(!_bStartedBuild and bCanUseCommanders and
 
7826
                                                (_numTotalCommanders < MAX_COMMANDERS))
 
7827
                                {
 
7828
                                        // if( !defendingBase() )
 
7829
                                        // {
 
7830
                                                /* Calculate how many commanders we need */
 
7831
                                                _numDroidsNoCmd = max(0, totalWeapUnits() - getTotalCmdsCapacity(NULLOBJECT, true));    //num of droids without commander or 0
 
7832
 
 
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;
 
7837
                                                }
 
7838
 
 
7839
                                                // calculate how many commanders we need
 
7840
                                                _numNeedCmds = (_numDroidsNoCmd + CMD_INIT_CAPACITY - _minUnassignedDroids) / CMD_INIT_CAPACITY;
 
7841
 
 
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 )
 
7844
                                                // {
 
7845
                                                        // _numNeedCmds++;
 
7846
                                                // }
 
7847
 
 
7848
                                                dbg("need " & _numNeedCmds & " commanders for " & _numDroidsNoCmd & " droids", me);
 
7849
 
 
7850
                                                if((_numNeedCmds > 0) and ( (_numTotalCommanders + _numNeedCmds) < MAX_COMMANDERS))
 
7851
                                                {
 
7852
                                                        //Find best commander template
 
7853
                                                        _result2 = 0;
 
7854
                                                        _result = numCmdTmpl;
 
7855
                                                        while((_result > 0) and (_result2 == 0))
 
7856
                                                        {
 
7857
                                                                _result--;
 
7858
                                                                if(skCanBuildTemplate(me,_factory, tmplCmd[_result]))
 
7859
                                                                {
 
7860
                                                                        tmplOK[_result2] = tmplCmd[_result];
 
7861
                                                                        _result2++;
 
7862
                                                                }
 
7863
                                                        }
 
7864
 
 
7865
                                                        if(_result2 > 0)                //found a template to build
 
7866
                                                        {
 
7867
                                                                _bStartedBuild = TRUE;
 
7868
                                                                buildDroid(tmplOK[0], _factory, me, 1);
 
7869
                                                                _numTotalCommanders++;
 
7870
                                                        }
 
7871
                                                }
 
7872
                                        // }
 
7873
                                }
 
7874
 
 
7875
                                //Build BBs
 
7876
                                //------------------
 
7877
                                if(!_bStartedBuild and haveBB and (groupSizeCmds(defendGr,true,false,true)
 
7878
                                        >= (numDefenders + 4)))         //BB researched and not low on tanks
 
7879
                                {
 
7880
                                        if(!lowMilitary and !alert and !defendingBase())
 
7881
                                        {
 
7882
                                                _result = numBBsInProduction(me);       //how many already building
 
7883
                                                if(_result < 1)         //not too many already
 
7884
                                                {
 
7885
                                                        _result = _result + numDroidsByComponent(weaponBB, me, me);     //num BBs
 
7886
 
 
7887
                                                        _needBBs = min(numBB, numAvailableAttackers() / 9 - _result);   //1 bb for 9 droids
 
7888
 
 
7889
                                                        if(_needBBs > 0)        //not too many
 
7890
                                                        {
 
7891
                                                                //Find best BB template
 
7892
                                                                _result2 = 0;
 
7893
                                                                _result = numBBTempl;
 
7894
                                                                while((_result > 0) and (_result2 == 0))
 
7895
                                                                {
 
7896
                                                                        _result--;
 
7897
                                                                        if(skCanBuildTemplate(me, _factory, tmplBB[_result]))
 
7898
                                                                        {
 
7899
                                                                                tmplOK[_result2] = tmplBB[_result];
 
7900
                                                                                _result2++;
 
7901
                                                                        }
 
7902
                                                                }
 
7903
 
 
7904
                                                                if(_result2 > 0)                //found a template to build
 
7905
                                                                {
 
7906
                                                                        _bStartedBuild = TRUE;
 
7907
                                                                        buildDroid(tmplOK[0], _factory, me, 1);
 
7908
                                                                }
 
7909
 
 
7910
                                                        }
 
7911
                                                }
 
7912
                                        }
 
7913
                                }
 
7914
 
 
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
 
7918
                                {
 
7919
                                        // make facs pump tanks to prevent rush at the beginning of the game
 
7920
                                        if(!legoPhase())
 
7921
                                        {
 
7922
                                                // if need repairers,  build one at a time
 
7923
                                                if((_needTotalRepairers > 0) and (numNonCybRepairsInProd() == 0))
 
7924
                                                {
 
7925
                                                        _result = numRepairTmpl - 1;
 
7926
                                                        while(!_bStartedBuild and (_result >= 0))
 
7927
                                                        {
 
7928
                                                                if(skCanBuildTemplate(me, _factory, tmplRep[_result]))
 
7929
                                                                {
 
7930
                                                                        _bStartedBuild = true;
 
7931
                                                                        _needTotalRepairers--;
 
7932
                                                                        buildDroid(tmplRep[_result], _factory, me, 1);
 
7933
                                                                }
 
7934
                                                                _result--;
 
7935
                                                        }
 
7936
                                                }
 
7937
                                        }
 
7938
                                }
 
7939
 
 
7940
 
 
7941
                                //Build attack units
 
7942
                                //--------------------
 
7943
                                if(not _bStartedBuild)          //didn't start building BB or repair unit
 
7944
                                {
 
7945
                                        // get max template size a factory cab build
 
7946
                                        _maxBodySize = skGetFactoryCapacity(_factory);
 
7947
                                        
 
7948
                                        // find best anti-tank template
 
7949
                                        _bestTankATTemplate = getBestTankATTemplate(_maxBodySize);
 
7950
 
 
7951
                                        if(_bestTankATTemplate != NULLTEMPLATE)
 
7952
                                        {
 
7953
                                                if(skCanBuildTemplate(me, _factory, _bestTankATTemplate))
 
7954
                                                {
 
7955
                                                        _bStartedBuild = TRUE;
 
7956
                                                        buildDroid(_bestTankATTemplate, _factory, me, 1);
 
7957
                                                }
 
7958
                                                else
 
7959
                                                {
 
7960
                                                        ASSERT(false, "buildTanks(): factory with size " &
 
7961
                                                                _maxBodySize & " can't build template", me);
 
7962
                                                }
 
7963
                                        }
 
7964
                                        else
 
7965
                                        {
 
7966
                                                dbg("found no tank template to build", me);
 
7967
                                        }
 
7968
                                }
 
7969
                        }
 
7970
 
 
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)))
 
7974
                        {
 
7975
                                exit;
 
7976
                        }
 
7977
                }
 
7978
                _factory = enumStruct();
 
7979
        }
 
7980
 
 
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))
 
7985
        {
 
7986
                if(structureComplete(_factory))
 
7987
                {
 
7988
                        if(structureIdle(_factory))
 
7989
                        {
 
7990
                                //Try to build a mechanic
 
7991
                                if( skCanBuildTemplate(me,_factory, cybMechanic) )
 
7992
                                {
 
7993
                                        buildDroid(cybMechanic, _factory, me, 1);
 
7994
                                        _needTotalRepairers++;
 
7995
                                }
 
7996
                        }
 
7997
                }
 
7998
                _factory = enumStruct();
 
7999
        }
 
8000
        
 
8001
        // Build cyborgs
 
8002
        initEnumStruct(false,cybfac,me,me);
 
8003
        _factory = enumStruct();
 
8004
        while(_factory != NULLOBJECT)
 
8005
        {
 
8006
                // make sure we won't build too many of them
 
8007
                if( (numDroidsByType(me, DROID_CYBORG) + numDroidsByType(me, DROID_CYBORG_SUPER)) < maxAttackCyborgs)
 
8008
                {
 
8009
                        if( structureIdle(_factory) )
 
8010
                        {
 
8011
                                cybFactorBuildCyborg(_factory);
 
8012
                        }
 
8013
                }
 
8014
                _factory = enumStruct();
 
8015
        }
 
8016
 
 
8017
        //dbg(" " & me & ")  End buildTanks()");
 
8018
}
 
8019
 
 
8020
function int numDroidsByType(int _player, int _droidType)
 
8021
{
 
8022
        local   int             _numDroids;
 
8023
        local   DROID   _droid;
 
8024
 
 
8025
        InitEnumDroids(_player,me);
 
8026
        _droid = EnumDroid();
 
8027
        while(_droid != NULLOBJECT)
 
8028
        {
 
8029
                if(_droid.droidType == _droidType)
 
8030
                {
 
8031
                        _numDroids++;
 
8032
                }
 
8033
                _droid = EnumDroid();
 
8034
        }
 
8035
        
 
8036
        return _numDroids;
 
8037
}
 
8038
 
 
8039
function void cybFactorBuildCyborg(STRUCTURE _factory)
 
8040
{
 
8041
        local   int             _tmplIndex,_tmplChosenIndex;
 
8042
 
 
8043
        if(_factory == NULLOBJECT){
 
8044
                dbg("cybFactorBuildCyborg: factory is NULLOBJECT", me);
 
8045
                return;
 
8046
        }
 
8047
 
 
8048
        _tmplIndex = numLightCyborgs - 1;
 
8049
        _tmplChosenIndex = 0;
 
8050
        while( (_tmplIndex >= 0) and (_tmplChosenIndex < MAX_CHOICE_LIGHT_CYB) )
 
8051
        {
 
8052
                if( skCanBuildTemplate(me,_factory, cybTempl[_tmplIndex]) )
 
8053
                {
 
8054
                        tmplOK[_tmplChosenIndex] = cybTempl[_tmplIndex];
 
8055
                        _tmplChosenIndex++;
 
8056
                }
 
8057
                _tmplIndex--;
 
8058
        }
 
8059
        if(_tmplChosenIndex > 0)
 
8060
        {
 
8061
                buildDroid(tmplOK[random(_tmplChosenIndex)], _factory, me, 1);
 
8062
        }
 
8063
 
 
8064
}
 
8065
 
 
8066
// calculate how many repairers we still need
 
8067
function int numNeedRepairers()
 
8068
{
 
8069
        local           int             _needCmdRepairers,_numDefendRepairers,_needDefendRepairers,
 
8070
                                                _numRepInProd,_needTotalRepairers;
 
8071
 
 
8072
 
 
8073
        _needCmdRepairers = 0;
 
8074
        if(bCanUseCommanders){
 
8075
                _needCmdRepairers = numMissingCmdRepairers(-1, false);
 
8076
        }
 
8077
 
 
8078
        _numDefendRepairers = groupSizeCmds(defendRepairGr,true,false,true);
 
8079
 
 
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);
 
8084
 
 
8085
        if(_needDefendRepairers < 0){
 
8086
                _needDefendRepairers = 0;
 
8087
        }
 
8088
 
 
8089
        _numRepInProd = totalRepairersInProduction();
 
8090
 
 
8091
        // calc how many we still need
 
8092
        _needTotalRepairers = _needCmdRepairers + _needDefendRepairers - _numRepInProd;
 
8093
 
 
8094
        return _needTotalRepairers;
 
8095
}
 
8096
 
 
8097
function void buildVTOLs()
 
8098
{
 
8099
        if(getDroidCount(me) >= unitLimit)
 
8100
        {
 
8101
                exit;}
 
8102
 
 
8103
        count = 0;
 
8104
 
 
8105
        /* decide if want to use heavy templates */
 
8106
        count3 = 0;
 
8107
        //if((playerPower(me) > muchoPower) and (state != stDefendingBase))
 
8108
        //{
 
8109
        //      count3 = 1;
 
8110
        //}
 
8111
 
 
8112
        initEnumStruct(FALSE,vtolfac,me,me);
 
8113
        structure = enumStruct();
 
8114
        while(structure != NULLOBJECT)
 
8115
        {
 
8116
                if(structureComplete(structure))
 
8117
                {
 
8118
                        count = count + 1;              //'id' of fac
 
8119
 
 
8120
                        if(structureIdle(structure))
 
8121
                        {
 
8122
 
 
8123
                                //Build attack units
 
8124
                                //-------------------
 
8125
                                //if(not bResult)               //didn't start building BB or repair unit
 
8126
                                //{
 
8127
                                        //Find best available templates
 
8128
                                        result = numVtolTemplates;
 
8129
                                        result2 = 0;
 
8130
                                        while((result > 0) and (result2 < 2))   //2 best tmplates
 
8131
                                        {
 
8132
                                                result = result - 1;
 
8133
                                                if(skCanBuildTemplate(me,structure, vtoltmpl[count3][result]))
 
8134
                                                {
 
8135
                                                        tmplOK[result2] = vtoltmpl[count3][result];
 
8136
                                                        result2 = result2 + 1;
 
8137
                                                }
 
8138
                                        }
 
8139
 
 
8140
                                        if(result2 > 0)         //found a template to build
 
8141
                                        {
 
8142
                                                buildDroid(tmplOK[random(result2)], structure, me, 1);
 
8143
                                        }
 
8144
                                //}
 
8145
                        }
 
8146
 
 
8147
                        /* build vtols only in first 3 factories, if alert of non-military type */
 
8148
                        if((count >= 3) and (alert and (not lowMilitary)))
 
8149
                        {
 
8150
                                exit;
 
8151
                        }
 
8152
                }
 
8153
                structure = enumStruct();
 
8154
        }
 
8155
}
 
8156
 
 
8157
 
 
8158
//����������������������������������������������������������������������������������������������
 
8159
//
 
8160
//����������������������������������������������������������������������������������������������
 
8161
 
 
8162
function int totalRepairersInProduction()
 
8163
{
 
8164
        local   int             _numRepairers;
 
8165
 
 
8166
        // total repairs
 
8167
        _numRepairers = numNonCybRepairsInProd() + numCybRepairsInProd();
 
8168
 
 
8169
        return _numRepairers;
 
8170
}
 
8171
 
 
8172
function int numCybRepairsInProd()
 
8173
{
 
8174
        local   int             _numRepairers;
 
8175
 
 
8176
        _numRepairers = 0;
 
8177
 
 
8178
        // cyborg mechanics
 
8179
        _numRepairers = numTemplatesInProduction(cybMechanic,me);       //mechanics
 
8180
 
 
8181
        return _numRepairers;
 
8182
}
 
8183
 
 
8184
function int numNonCybRepairsInProd()
 
8185
{
 
8186
        local   int             _repTmplIndex,_numRepairers;
 
8187
 
 
8188
        _numRepairers = 0;
 
8189
        _repTmplIndex = 0;
 
8190
 
 
8191
        // wheeled, tracked repairs
 
8192
        while(_repTmplIndex < numRepairTmpl)
 
8193
        {
 
8194
                _numRepairers = _numRepairers + numTemplatesInProduction(tmplRep[_repTmplIndex],me);
 
8195
                _repTmplIndex++;
 
8196
        }
 
8197
 
 
8198
        return _numRepairers;
 
8199
}
 
8200
 
 
8201
//how many trucks are building defenses
 
8202
function int numBuildingDefenses()
 
8203
{
 
8204
        //return        - number of busy trucks
 
8205
 
 
8206
        temp2 = 0;              //How many are ordered to build a defense
 
8207
        temp = 0;
 
8208
        while(temp < numDef)
 
8209
        {
 
8210
                if(isStructureAvailable(def[temp],me))
 
8211
                {
 
8212
                        temp3 = numStatBusy(def[temp], TRUE);   //How many going to build it
 
8213
                        temp2 = temp2 + temp3;
 
8214
                }
 
8215
 
 
8216
                temp = temp + 1;
 
8217
        }
 
8218
 
 
8219
        return(temp2);
 
8220
}
 
8221
 
 
8222
function int numBuildingBaseDefenses()
 
8223
{
 
8224
        local   int     _bucket;
 
8225
 
 
8226
        //return        - number of busy trucks
 
8227
 
 
8228
        temp2 = 0;              //How many are ordered to build a defense
 
8229
        temp = 0;
 
8230
        while(temp < numDef)
 
8231
        {
 
8232
                if(isStructureAvailable(def[temp],me))
 
8233
                {
 
8234
                        temp3 = 0;
 
8235
                        _bucket = initIterateGroupCmd(buildGr,true,false,true);
 
8236
                        tempDroid = iterateGroupCmd(buildGr,_bucket);
 
8237
                        while(tempDroid != NULLOBJECT)
 
8238
                        {
 
8239
                                if(tempDroid.order == DORDER_BUILD)
 
8240
                                {
 
8241
                                        if(tempDroid.stat == def[temp]) //going to build it
 
8242
                                        {
 
8243
                                                if(distBetweenTwoPoints(tempDroid.orderx, tempDroid.ordery, baseX, baseY) <= (baseRange + defendCorridor))      //within base
 
8244
                                                {
 
8245
                                                        temp3 = temp3 + 1;
 
8246
                                                }
 
8247
                                        }
 
8248
                                }
 
8249
                                tempDroid = iterateGroupCmd(buildGr,_bucket);
 
8250
                        }
 
8251
 
 
8252
 
 
8253
                        temp2 = temp2 + temp3;
 
8254
                }
 
8255
 
 
8256
                temp = temp + 1;
 
8257
        }
 
8258
 
 
8259
        return(temp2);
 
8260
}
 
8261
 
 
8262
function int numBuildingNoBaseDefenses()
 
8263
{
 
8264
        local   int     _bucket,_numBuildingDef,_defTypeIndex,_nonBaseDef;
 
8265
        local   DROID   _truck;
 
8266
 
 
8267
        //return        - number of busy trucks
 
8268
 
 
8269
        _numBuildingDef = 0;            //How many are ordered to build a defense
 
8270
        _defTypeIndex = 0;
 
8271
        while(_defTypeIndex < numDef)
 
8272
        {
 
8273
                if(isStructureAvailable(def[_defTypeIndex],me))
 
8274
                {
 
8275
                        _nonBaseDef = 0;
 
8276
                        _bucket = initIterateGroupCmd(buildGr,true,false,true);
 
8277
                        _truck = iterateGroupCmd(buildGr,_bucket);
 
8278
                        while(_truck != NULLOBJECT)
 
8279
                        {
 
8280
                                if(_truck.order == DORDER_BUILD)
 
8281
                                {
 
8282
                                        if(_truck.stat == def[_defTypeIndex])   //going to build it
 
8283
                                        {
 
8284
                                                if(distBetweenTwoPoints(_truck.orderx, _truck.ordery, baseX, baseY) > (baseRange + defendCorridor))     //not within base
 
8285
                                                {
 
8286
                                                        _nonBaseDef++;
 
8287
                                                }
 
8288
                                        }
 
8289
                                }
 
8290
                                _truck = iterateGroupCmd(buildGr,_bucket);
 
8291
                        }
 
8292
 
 
8293
 
 
8294
                        _numBuildingDef = _numBuildingDef + _nonBaseDef;
 
8295
                }
 
8296
 
 
8297
                _defTypeIndex++;
 
8298
        }
 
8299
 
 
8300
        return(_numBuildingDef);
 
8301
}
 
8302
 
 
8303
function DROID closestIdleTruck(int _x, int _y)
 
8304
{
 
8305
        local DROID _closestTruck,_tempTruck;
 
8306
        local int       _closestDist,_tempDist,_bucket;
 
8307
 
 
8308
        _closestTruck = NULLOBJECT;
 
8309
        _closestDist = 99999;
 
8310
 
 
8311
        _bucket = initIterateGroupCmd(buildGr,true,false,true);
 
8312
        _tempTruck = iterateGroupCmd(buildGr,_bucket);
 
8313
        while(_tempTruck != NULLOBJECT)
 
8314
        {
 
8315
                if(droidOrderIdle(_tempTruck))
 
8316
                {
 
8317
                        _tempDist = distBetweenTwoPoints(_x, _y, _tempTruck.x, _tempTruck.y);
 
8318
                        if(_tempDist < _closestDist)
 
8319
                        {
 
8320
                                _closestDist = _tempDist;
 
8321
                                _closestTruck = _tempTruck;
 
8322
                        }
 
8323
                }
 
8324
                _tempTruck = iterateGroupCmd(buildGr,_bucket);
 
8325
        }
 
8326
 
 
8327
        return _closestTruck;
 
8328
}
 
8329
 
 
8330
//------------------------------------------------
 
8331
//Build some defenses on startup to prevent rushes
 
8332
//------------------------------------------------
 
8333
function void buildInitialDefenses(bool _bForceBuild)   //returns TRUE if finished
 
8334
{
 
8335
        //_bForceBuild - if returned from callback, truck order is not reste to DORDER_NONE yet, but it's idle
 
8336
 
 
8337
        if(not bLearn){return;}         //only uses learn data so far
 
8338
        if(defendingBase()){return;}            //don't waste power
 
8339
 
 
8340
        /* if no builder, find one */
 
8341
        if(initialDefensesTruck == NULLOBJECT)
 
8342
        {
 
8343
                if(groupSizeCmds(buildGr,true,false,true) >= 5) //don't take away any trucks if low on them
 
8344
                {
 
8345
                        initialDefensesTruck = closestIdleTruck(baseX, baseY);
 
8346
                }
 
8347
        }
 
8348
 
 
8349
        if(initialDefensesTruck == NULLOBJECT)
 
8350
        {
 
8351
                //dbg("buildInitialDefenses() - no truck", me);
 
8352
                return;         //try again later
 
8353
        }
 
8354
 
 
8355
        if((initialDefensesTruck.order != DORDER_NONE) and (not _bForceBuild))
 
8356
        {
 
8357
                //dbg("buildInitialDefenses() - truck busy", me);
 
8358
                return;         //try again later
 
8359
        }
 
8360
 
 
8361
        range = BASE_DEFENSES_RANGE;            //"too-many-built-in-range" range
 
8362
        best = none;            //Best defense
 
8363
 
 
8364
        /* find best defense */
 
8365
        best = findBestDefense();
 
8366
        if(best == none){return;}       //No defenses researched
 
8367
 
 
8368
        //Now iterate through the stored locations
 
8369
        //----------------------------------------
 
8370
        result2 = getBaseDefendLocCount();              //how many locations there are stored (max)
 
8371
 
 
8372
        while(curInitialBaseDef <= maxInitialBaseDef)
 
8373
        {
 
8374
                count = 0;      //start from the first stored location again
 
8375
 
 
8376
                while((count < result2) and (count < maxInitialDefSites))               //don't build at more than maxInitialDefSites in total
 
8377
                {
 
8378
                        if(recallBaseDefendLoc(me, count, ref x, ref y, ref result3))   //TRUE if stored
 
8379
                        {
 
8380
                                if(result3 > 0)         //attacked atleast 1 time (highest priority is always at the top)
 
8381
                                {
 
8382
                                        //move coords closer to base
 
8383
                                        circlePerimPoint(baseX, baseY, ref  x, ref y, (baseRange + defendCorridor / 2));        //move locations to the base perimeter
 
8384
 
 
8385
                                        buildX = x;     //remember coords before using pickStructLocation() to check if corrected coords too far away
 
8386
                                        buildY = y;
 
8387
 
 
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
 
8390
                                        {
 
8391
                                                if(pickStructLocation(def[best], ref buildX, ref buildY, me))
 
8392
                                                {
 
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
 
8395
                                                        {
 
8396
                                                                orderDroidStatsLoc(initialDefensesTruck, DORDER_BUILD, def[best], buildX, buildY);
 
8397
 
 
8398
                                                                //dbg("buildInitialDefenses() - started", me);
 
8399
 
 
8400
                                                                return; /* this one successfull, try again next time */
 
8401
                                                        }
 
8402
                                                }
 
8403
                                        }
 
8404
                                }
 
8405
                        }
 
8406
                        count = count + 1;
 
8407
                }
 
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);
 
8410
        }
 
8411
 
 
8412
 
 
8413
        //stopInitialDefenses();
 
8414
        return;
 
8415
}
 
8416
 
 
8417
function void stopInitialDefenses()
 
8418
{
 
8419
        /* finished for real: no open sites with no defenses left, stop the whole process */
 
8420
        initialDefensesFinished = true;
 
8421
        dbg("buildInitialDefenses() - FINISHED", me);
 
8422
 
 
8423
        /* add builder back to the buildGr if finished */
 
8424
        if(initialDefensesTruck != NULLOBJECT)
 
8425
        {
 
8426
                dbg("buildInitialDefenses() - ADDED BACK THE TRUCK", me);
 
8427
                groupAddDroid(buildGr, initialDefensesTruck);
 
8428
                initialDefensesTruck = NULLOBJECT;
 
8429
        }
 
8430
}
 
8431
 
 
8432
function void buildBaseDefenses()
 
8433
{
 
8434
        local bool _buildStarted;
 
8435
 
 
8436
        //dbg(" " & me & ")  buildBaseDefenses()");
 
8437
 
 
8438
        if(not bLearn){exit;}
 
8439
        if(idleGroupCmd(buildGr,true,false) == 0){exit;}
 
8440
 
 
8441
        //MsgBox("buildBaseDefenses()");
 
8442
 
 
8443
        best = none;            //Best defense
 
8444
 
 
8445
        //How many are ordered to build a defense?
 
8446
        result = numBuildingBaseDefenses();
 
8447
        if(result >= maxBaseDefenseTrucks){exit;}               //Not too many busy with defenses already
 
8448
 
 
8449
        /* find best defense */
 
8450
        best = findBestDefense();
 
8451
        if(best == none){exit;} //No defenses researched
 
8452
 
 
8453
        bResult = FALSE;        //started to build anything?
 
8454
 
 
8455
        //Now iterate through the stored locations
 
8456
        //---------------------------------------
 
8457
        result2 = getBaseDefendLocCount();              //how many locations there are stored (max)
 
8458
        count = 0;
 
8459
 
 
8460
        //look at maxBaseDefenseLoc defend locs nad pick MAX_BASE_DEFENSE_LOCATIONS best ones
 
8461
        count4 = 0;
 
8462
        while((count < result2) and (count4 < MAX_BASE_DEFENSE_LOCATIONS) and
 
8463
                (count < maxBaseDefenseLoc))
 
8464
        {
 
8465
                if(recallBaseDefendLoc(me, count, ref x, ref y, ref result3))   //TRUE if stored
 
8466
                {
 
8467
                        if(result3 > MIN_BASE_RECALL_PRIORITY)  //at least priority of MIN_BASE_RECALL_PRIORITY + 1
 
8468
                        {
 
8469
                                //move coords closer to base
 
8470
                                circlePerimPoint(baseX, baseY, ref  x, ref y, (baseRange + defendCorridor / 2));        //move locations to the base perimeter
 
8471
 
 
8472
                                buildX = x;     //remember coords before using pickStructLocation() to check if corrected coords too far away
 
8473
                                buildY = y;
 
8474
 
 
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)
 
8478
                                {
 
8479
                                        if(pickStructLocation(def[best], ref buildX, ref buildY, me))
 
8480
                                        {
 
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
 
8483
                                                {
 
8484
                                                        //Make sure not too many building already
 
8485
                                                        //--------------------------------------------
 
8486
                                                        retInt = numTrucksOrderInRange(buildX, buildY, BASE_DEFENSES_RANGE, DORDER_BUILD);
 
8487
 
 
8488
                                                        if(retInt < maxBaseDefendDefLocTrucks)
 
8489
                                                        {
 
8490
                                                                intOK[count4] = count;
 
8491
                                                                count4 = count4 + 1;            //picked another one
 
8492
                                                        }
 
8493
                                                }
 
8494
                                        }
 
8495
                                }
 
8496
                        }
 
8497
                }
 
8498
                count = count + 1;
 
8499
        }
 
8500
 
 
8501
        if(count4 == 0){exit;}          //couldn't recall any locations
 
8502
 
 
8503
        //Choose a random site
 
8504
        //--------------------------------------------
 
8505
        result = intOK[random(count4 - 1)];
 
8506
 
 
8507
        //dbg(" " & me & ")  defendDefenses() - building defense at location #" & result & " !!!!!!!!!!!!");
 
8508
 
 
8509
        recallBaseDefendLoc(me, result, ref x, ref y, ref temp2);
 
8510
 
 
8511
        //move coords closer to base
 
8512
        circlePerimPoint(baseX, baseY, ref x, ref y, (baseRange + defendCorridor / 2));
 
8513
 
 
8514
        buildX = x;     //remember coords before using pickStructLocation() to check if corrected coords too far away
 
8515
        buildY = y;
 
8516
 
 
8517
        if(pickStructLocation(def[best], ref buildX, ref buildY, me))
 
8518
        {
 
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
 
8521
                {
 
8522
                        _buildStarted = buildUsingClosestTruck(def[best], buildX, buildY, 1);
 
8523
 
 
8524
                        if(_buildStarted)
 
8525
                        {
 
8526
                                bResult = TRUE; //Build successfull
 
8527
 
 
8528
                                tLastBaseDefense = GAME_TIME_IN_SECS;
 
8529
 
 
8530
                                //dbg(" " & me & ")   building on base defense location # " & result & " !!!!!");
 
8531
                                //if((result + count3) >= 5){exit;}             //Not too many busy with defenses already
 
8532
                        }
 
8533
                }
 
8534
        }
 
8535
 
 
8536
        //dbg(" " & me & ")  * buildBaseDefenses()");
 
8537
}
 
8538
 
 
8539
function int numDefenses()
 
8540
{
 
8541
        retInt = 0;
 
8542
        temp = 0;
 
8543
        while(temp < numDef)
 
8544
        {
 
8545
                retInt = retInt + getNumStructures(def[temp],me);
 
8546
                temp = temp + 1;
 
8547
        }
 
8548
 
 
8549
        return(retInt);
 
8550
}
 
8551
 
 
8552
function int numBaseDefenses()
 
8553
{
 
8554
        retInt = 0;
 
8555
        temp = 0;
 
8556
        while(temp < numDef)
 
8557
        {
 
8558
                initEnumStruct(FALSE,def[temp],me,me);
 
8559
                tempStruct = enumStruct();
 
8560
                while(tempStruct != NULLOBJECT)
 
8561
                {
 
8562
                        if((tempStruct.x < maxx) and (tempStruct.x > minx))
 
8563
                        {
 
8564
                                if((tempStruct.y < maxy) and (tempStruct.y > miny))
 
8565
                                {
 
8566
                                        retInt = retInt + 1;
 
8567
                                }
 
8568
                        }
 
8569
                        tempStruct = enumStruct();
 
8570
                }
 
8571
                temp = temp + 1;
 
8572
        }
 
8573
 
 
8574
        return(retInt);
 
8575
}
 
8576
 
 
8577
 
 
8578
 
 
8579
event objectAttacked(inactive)
 
8580
{
 
8581
        local   int             _bucket,_defendersWeaponRange,_maxReachRange;
 
8582
        local   bool            _bVtol;
 
8583
        
 
8584
        if(obj == NULLOBJECT){exit;}
 
8585
        if(obj2 == NULLOBJECT){exit;}
 
8586
 
 
8587
        if(obj.player == obj2.player){exit;}
 
8588
 
 
8589
        attacked[obj2.player] = attacked[obj2.player] + 1;      //remember how many times attacked by him
 
8590
 
 
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
 
8594
        {
 
8595
                // if this weapon has a big range
 
8596
                //if(objectHasIndirectWeapon(obj2) and (obj2.longRange > (TILE * 9)))
 
8597
                
 
8598
                // check if attacked by a vtol
 
8599
                _bVtol = false;
 
8600
                if(obj2.type == OBJ_DROID)
 
8601
                {
 
8602
                        if(isVtol(objToDroid(obj2)))
 
8603
                        {
 
8604
                                _bVtol = true;
 
8605
                        }
 
8606
                }
 
8607
                
 
8608
                // ignore VTOLs
 
8609
                if(!_bVtol)
 
8610
                {
 
8611
                        _defendersWeaponRange = TILE * 10;      //longer than lancer
 
8612
                        _maxReachRange = baseRange + defendCorridor + _defendersWeaponRange;
 
8613
                        
 
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)
 
8617
                        {
 
8618
                                dbg("attacked by long-range weapon in the base", me);
 
8619
 
 
8620
                                if(!isNearEnemyBase(obj2.x, obj2.y))    // enemy arty could be too heavily defended
 
8621
                                {
 
8622
                                        if(canStartArtyCouterAttack(obj2.player, obj2.x, obj2.y))
 
8623
                                        {
 
8624
                                                // make sure not doing anything important
 
8625
                                                if(!defendingBase() and !counteringArty())
 
8626
                                                {
 
8627
                                                        // stop what we were doing, if anything
 
8628
                                                        if(!idling()){
 
8629
                                                                cancelState();
 
8630
                                                        }
 
8631
                                                        
 
8632
                                                        //TODO: take out arty sensors with VTOLs
 
8633
 
 
8634
                                                        startArtyCounterAttack(obj2.player, obj2.x, obj2.y);
 
8635
                                                        
 
8636
                                                        dbg("attacking arty", me);
 
8637
                                                }
 
8638
                                        }
 
8639
 
 
8640
                                        // request help if for some reason we couldn't defend ourself against arty
 
8641
                                        if(!counteringArty())
 
8642
                                        {
 
8643
                                                // stop what we were doing, if anything unimportant
 
8644
                                                if(!idling() and !defendingBase())
 
8645
                                                {
 
8646
                                                        cancelState();
 
8647
                                                }
 
8648
 
 
8649
                                                if(canRequestHelp())
 
8650
                                                {
 
8651
                                                        // we have not enough firepower, request help
 
8652
                                                        requestHelp(obj2.x, obj2.y);
 
8653
                                                        
 
8654
                                                        dbg("requested help because of arty", me);
 
8655
                                                }
 
8656
                                        }
 
8657
                                }
 
8658
                                else
 
8659
                                {
 
8660
                                        // start attacking attacker's base if can
 
8661
                                        if(idling())
 
8662
                                        {
 
8663
                                                if(canStartAttack(obj2.player))
 
8664
                                                {
 
8665
                                                        startEnemyBaseAttack(obj2.player);
 
8666
                                                        requestStartAttack(obj2.player, curBase[obj2.player][0], curBase[obj2.player][1]);
 
8667
                                                }
 
8668
                                        }
 
8669
                                }
 
8670
                        }
 
8671
                }
 
8672
 
 
8673
 
 
8674
                if(obj2.type == OBJ_DROID)                              //attacker is a droid
 
8675
                {
 
8676
                        if(!_bVtol)                                             //not vtol
 
8677
                        {
 
8678
                                if(bLearn)
 
8679
                                {
 
8680
                                        storeBaseDefLocEv();
 
8681
                                }
 
8682
                        }
 
8683
                        else    /* check if we have to build some AAs asap */
 
8684
                        {
 
8685
                                if(knowBase[obj2.player])
 
8686
                                {
 
8687
                                        exit;           //other routine does it in this case
 
8688
                                }
 
8689
 
 
8690
                                x = obj.x;
 
8691
                                y = obj.y;
 
8692
                                range = INBASE_AA_DEF_MAX_RANGE;        //too many on spot range
 
8693
 
 
8694
                                if(numAAinRange(me, me, x, y, range) >= MAX_INBASE_AA_DEF)
 
8695
                                {
 
8696
                                        exit;
 
8697
                                }
 
8698
 
 
8699
                                best = findBestAA();
 
8700
                                if(best == none){exit;}
 
8701
 
 
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))
 
8705
                                {
 
8706
                                        exit;
 
8707
                                }
 
8708
 
 
8709
                                if(distBetweenTwoPoints(buildX, buildY, x, y) > range)  //build loc moved too far away
 
8710
                                {
 
8711
                                        exit;   //original site was probably blocked, don't build too far away from orig site
 
8712
                                }
 
8713
 
 
8714
                                dbg("building AA defense, since don't see attacker's base", me);
 
8715
 
 
8716
                                /* build AA */
 
8717
                                buildOnMap(AA[best], buildX, buildY, 2);
 
8718
                        }
 
8719
                }
 
8720
        }
 
8721
        else    //outside of the base
 
8722
        {
 
8723
                /* learn oil defense location */
 
8724
                //result = isNearOil(obj.x, obj.y);
 
8725
 
 
8726
                if(isNearOil(obj.x, obj.y))
 
8727
                {
 
8728
                        if(bLearn)
 
8729
                        {
 
8730
                                storeOilDefLocEv();
 
8731
                        }
 
8732
 
 
8733
                        // decide if we have to defend oil derrick
 
8734
                        dealWithOilAttacked(obj.x, obj.y);
 
8735
                }
 
8736
        }
 
8737
 
 
8738
        /* check if we can take them down easily, even outside of the base */
 
8739
        if(obj2.type == OBJ_DROID)              //attacker is a droid
 
8740
        {
 
8741
                if(isVtol(objToDroid(obj2)))            //vtol
 
8742
                {
 
8743
                        exit;
 
8744
                }
 
8745
        }
 
8746
 
 
8747
        range = baseRange * 3 / 2;      //1.5
 
8748
        if(objectHasIndirectWeapon(obj2))
 
8749
        {
 
8750
                range = baseRange * 2;          //can be further away
 
8751
        }
 
8752
 
 
8753
        // if(distBetweenTwoPoints(baseX, baseY, obj2.x, obj2.y) < range)       //not too far
 
8754
        // {
 
8755
                // if(numEnemyWeapObjInRange(me, obj2.x, obj2.y, (6 * 128), false, true) < (groupSizeCmds(defendGr,true,false,true) - 1))       //safe
 
8756
                // {
 
8757
 
 
8758
                        // baseDefendObj = obj2;
 
8759
 
 
8760
                        // /* attack with idle defenders */
 
8761
                        // _bucket = initIterateGroupCmd(defendGr,true,true,true);
 
8762
                        // droid = iterateGroupCmd(defendGr,_bucket);
 
8763
                        // while(droid != NULLOBJECT)
 
8764
                        // {
 
8765
                                // if((droid.order != DORDER_ATTACK) and (droid.order != DORDER_EMBARK))
 
8766
                                // {
 
8767
                                        // orderDroidObj(droid, DORDER_ATTACK, baseDefendObj);  //attack enemy
 
8768
                                // }
 
8769
                                // droid = iterateGroupCmd(defendGr,_bucket);
 
8770
                        // }
 
8771
                // }
 
8772
        // }
 
8773
}
 
8774
 
 
8775
event droidAttacked(inactive)
 
8776
{
 
8777
        if(droid.player != me)
 
8778
                exit;
 
8779
 
 
8780
        /* Make defenders retreat if heavily damaged to save units */
 
8781
        if(groupMember(defendGr, droid))
 
8782
        {
 
8783
                if(droid.health < 45)
 
8784
                {
 
8785
                        if(distBetweenTwoPoints(baseX, baseY, droid.x, droid.y) > baseRange)
 
8786
                        {
 
8787
                                if(defendGr.health > 50)                //wouldn't make sense if all half-dead
 
8788
                                {
 
8789
                                        x = droid.x;
 
8790
                                        y = droid.y;
 
8791
                                        circlePerimPoint(baseX, baseY, ref x, ref y, baseRange - (2 * 128));            //retreat behind defense lines
 
8792
                                        orderDroidLoc(droid, DORDER_MOVE, x, y);
 
8793
                                }
 
8794
                        }
 
8795
                }
 
8796
        }
 
8797
}
 
8798
 
 
8799
//-----------------------------------------------------------
 
8800
//Structure attacked CALLBACK
 
8801
//-----------------------------------------------------------
 
8802
event structureAttacked(inactive)
 
8803
{
 
8804
        local   int             _maxRepairers;
 
8805
        local   DROID   _truck;
 
8806
        local   bool    _bOK;
 
8807
 
 
8808
        if(structure != NULLOBJECT)
 
8809
        {
 
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
 
8812
                {
 
8813
                        /* See if any track is working on this structure */
 
8814
                        _truck = getTruckByTarget(structure);
 
8815
                        if(_truck != NULLOBJECT)
 
8816
                        {
 
8817
                                /* Order to recycle */
 
8818
                                dbg("demolishing structure", me);
 
8819
                                orderDroidObj(_truck, DORDER_DEMOLISH, structure);
 
8820
                        }
 
8821
                }
 
8822
                else
 
8823
                {
 
8824
                        /* Repair damaged structure */
 
8825
                        _maxRepairers = 1;
 
8826
 
 
8827
                        //close to base?
 
8828
                        if(distBetweenTwoPoints(baseX, baseY, structure.x, structure.y) < (baseRange + (8 * 128)))
 
8829
                        {
 
8830
                                bResult = TRUE;
 
8831
 
 
8832
                                _maxRepairers = 2;      //use more trucks for base structures
 
8833
                        }
 
8834
 
 
8835
                        if(not((not bResult) and (alert)))      //don't repair if low on power and not a base structure
 
8836
                        {
 
8837
                                retInt = repairStructure(structure, _maxRepairers);
 
8838
                        }
 
8839
                }
 
8840
        }
 
8841
}
 
8842
 
 
8843
/* returns TRUE if we don't have much spare ower */
 
8844
function bool lowOnPower()
 
8845
{
 
8846
        if(playerPower(me) < highPower)
 
8847
                return TRUE;
 
8848
 
 
8849
        return FALSE;
 
8850
}
 
8851
 
 
8852
//---------------------------------------------------------
 
8853
//      Returns true if location is near a derrick or oil resource
 
8854
//---------------------------------------------------------
 
8855
function bool isNearOil(int _x, int _y)
 
8856
{
 
8857
        local   int                     _range;
 
8858
        local   STRUCTURE       _derrick;
 
8859
        local   FEATURE         _oil;
 
8860
 
 
8861
        _range = (6 * 128);             //near oil range
 
8862
 
 
8863
        // check derricks
 
8864
        initEnumStruct(false,derrick,me,me);
 
8865
        _derrick = enumStruct();
 
8866
        while(_derrick != NULLOBJECT)
 
8867
        {
 
8868
                if(distBetweenTwoPoints(_x, _y, _derrick.x, _derrick.y) < _range)               //close to a derrick
 
8869
                {
 
8870
                        return true;
 
8871
                }
 
8872
 
 
8873
                _derrick = enumStruct();
 
8874
        }
 
8875
 
 
8876
        // check oil resources
 
8877
        initGetFeature(oilRes,me,me);
 
8878
        _oil = getFeatureB(me);
 
8879
        while(_oil != NULLOBJECT)
 
8880
        {
 
8881
                if(distBetweenTwoPoints(_x, _y, _oil.x, _oil.y) < _range)               //close to a derrick
 
8882
                {
 
8883
                        return true;
 
8884
                }
 
8885
                _oil = getFeatureB(me);
 
8886
        }
 
8887
 
 
8888
        return false;
 
8889
}
 
8890
 
 
8891
//-----------------------------------------------------------
 
8892
//Check all damaged structures and repair them
 
8893
//-----------------------------------------------------------
 
8894
function void repairStructures()
 
8895
{
 
8896
        if(idleGroupCmd(buildGr,true,false) == 0)
 
8897
                exit;
 
8898
 
 
8899
        //How many already repairing
 
8900
        result = numTrucksSameOrder(DORDER_REPAIR);
 
8901
 
 
8902
        result3 = 5;            //max repairers
 
8903
 
 
8904
        if(result >= result3)
 
8905
                exit;
 
8906
 
 
8907
 
 
8908
        structure2 = NULLOBJECT;
 
8909
        range = 90;                     //repair if below
 
8910
 
 
8911
        //check base structures first
 
8912
        //----------------------------
 
8913
        count = 0;
 
8914
        while(count < numBaseStructs)
 
8915
        {
 
8916
                initEnumStruct(FALSE,baseStructs[count],me,me);
 
8917
                structure = enumStruct();
 
8918
                while(structure != NULLOBJECT)
 
8919
                {
 
8920
                        if(structure.health < range)
 
8921
                        {
 
8922
                                result2 = repairStructure(structure, 3);        //use 3 trucks max
 
8923
 
 
8924
                                result = result + result2;              //one more busy?
 
8925
 
 
8926
                                if(result >= result3){exit;}            //exit if too many busy
 
8927
                        }
 
8928
                        structure = enumStruct();
 
8929
                }
 
8930
                count = count + 1;
 
8931
        }
 
8932
 
 
8933
        //now check all other structures
 
8934
        //---------------------------------
 
8935
        initEnumStruct(TRUE,fac,me,me);
 
8936
        structure = enumStruct();
 
8937
        while(structure != NULLOBJECT)
 
8938
        {
 
8939
                if(structure.health < range)
 
8940
                {
 
8941
                        result2 = repairStructure(structure, 1);        //use 1 truck max
 
8942
 
 
8943
                        result = result + result2;              //one more busy?
 
8944
 
 
8945
                        if(result >= result3){exit;}            //exit if too many busy
 
8946
                }
 
8947
                structure = enumStruct();
 
8948
        }
 
8949
}
 
8950
 
 
8951
function int repairStructure(STRUCTURE _damagedStruct, int _maxRepairers)
 
8952
{
 
8953
        //Make sure not too many repairing already
 
8954
        //----------------------------------------
 
8955
        temp2 = numTrucksSameOrderLoc(_damagedStruct.x, _damagedStruct.y, DORDER_REPAIR);
 
8956
 
 
8957
        if(temp2 < _maxRepairers)       //not too many already
 
8958
        {
 
8959
                //Find closest idle truck
 
8960
                //---------------------------------------
 
8961
                tempDroid = closestIdleTruck(_damagedStruct.x, _damagedStruct.y);
 
8962
 
 
8963
                if(tempDroid != NULLOBJECT)
 
8964
                {
 
8965
                        if(distBetweenTwoPoints(tempDroid.x, tempDroid.y, _damagedStruct.x, _damagedStruct.y) < (25 * 128))     //not too far
 
8966
                        {
 
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)) ) )
 
8969
                                {
 
8970
                                        orderDroidObj(tempDroid, DORDER_REPAIR, _damagedStruct);
 
8971
                                        return(1);
 
8972
                                }
 
8973
                        }
 
8974
                }
 
8975
        }
 
8976
 
 
8977
        return(0);
 
8978
}
 
8979
 
 
8980
//����������������������������������������������������������������������������������������������
 
8981
//      Scout
 
8982
//����������������������������������������������������������������������������������������������
 
8983
event doScout(inactive)
 
8984
{
 
8985
        local   int     _bucket;
 
8986
 
 
8987
        //dbg(" " & me & ")  doScout()");
 
8988
        if(idleGroupCmd(scoutGr,true,true) == 0){exit;}
 
8989
 
 
8990
        _bucket = initIterateGroupCmd(scoutGr,true,true,false);                         // find all units in scout group.
 
8991
        droid = iterateGroupCmd(scoutGr,_bucket);
 
8992
        while(droid != NULLOBJECT)
 
8993
        {
 
8994
                //dbg(" " & me & ")  doScout() - droid.orderx: " & droid.orderx & ", droid.ordery: " & droid.ordery);
 
8995
 
 
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
 
8997
                {
 
8998
                        //dbg(" " & me & ")  doScout() - setting new scouting destination (**********)");
 
8999
 
 
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);
 
9003
 
 
9004
                        //bResult = fogTileInRange(ref buildX, ref buildY, 33, 44, 55, 66, 77, 88);
 
9005
 
 
9006
 
 
9007
                        if(not bResult)
 
9008
                        {
 
9009
                                //dbg(" " & me & ")  doScout() - failed to find scout loc (**********)");
 
9010
 
 
9011
                                //scoutRange = scoutRange + scoutStep;  //and try next time
 
9012
 
 
9013
                                //see if whole map revealed
 
9014
                                //if( ((scoutRange / 128) > mapWidth) and ((scoutRange / 128) > mapHeight))
 
9015
                                //{
 
9016
                                        dbg("doScout() - STOP SCOUTING, MAP REVEALED (!!!!!!!!!!!!!)", me);
 
9017
 
 
9018
                                        //fMapRevealFactor = MAP_REVEAL_FAC_UBOUND;
 
9019
 
 
9020
                                        groupAddGroupCmd(defendGr, scoutGr);
 
9021
                                        setEventTrigger(doScout, inactive);     //stop scouting
 
9022
                                //}
 
9023
                        }
 
9024
                        else
 
9025
                        {
 
9026
                                //dbg(" " & me & ")  doScout() x: " & (droid.x/128) & ", y: " & (droid.x/128) & "newx: " & (buildX/128) & "newy :" & (buildY/128));
 
9027
 
 
9028
                                scoutX = buildX;
 
9029
                                scoutY = buildY;
 
9030
 
 
9031
                                orderDroidLoc(droid, DORDER_MOVE, scoutX, scoutY);
 
9032
                        }
 
9033
                }
 
9034
 
 
9035
                droid = iterateGroupCmd(scoutGr,_bucket);
 
9036
        }
 
9037
 
 
9038
        //dbg(" " & me & ")  * doScout()");
 
9039
}
 
9040
 
 
9041
event scoutForEnemy(inactive)
 
9042
{
 
9043
        local   int     _bucket;
 
9044
 
 
9045
        //dbg(" " & me & ")  scoutForEnemy()");
 
9046
 
 
9047
        // only scout if the group is full, otherwise will lose units too quickly
 
9048
/*      if(groupSizeCmds(enemyScoutGr,true,false,true) < maxEnemyScouts){
 
9049
                exit;
 
9050
        } */
 
9051
 
 
9052
        bResult = FALSE;        //no idle scouts
 
9053
 
 
9054
        // most of the group is idle
 
9055
        if(idleGroupCmd(enemyScoutGr,true,false) > (groupSizeCmds(enemyScoutGr,true,false,true)) / 2){
 
9056
                bResult = TRUE;
 
9057
        }
 
9058
 
 
9059
        // see if reached destination already
 
9060
        if(!bResult){
 
9061
 
 
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)
 
9066
                {
 
9067
                        if((distBetweenTwoPoints(droid.x, droid.y, droid.orderx, droid.ordery) < 384))  //Some of them reached destination
 
9068
                        {
 
9069
                                //dbg(" " & me & ")  scout reached");
 
9070
                                bResult = TRUE;
 
9071
                        }
 
9072
                        droid = iterateGroupCmd(enemyScoutGr,_bucket);
 
9073
                }
 
9074
        }
 
9075
 
 
9076
        if(not bResult){exit;}
 
9077
 
 
9078
 
 
9079
        if((enemyScoutX > 0) and (enemyScoutY > 0))
 
9080
        {
 
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));
 
9085
 
 
9086
                if(not bResult)
 
9087
                {
 
9088
                        dbg("couldn't send enemy scouts to " & enemyScoutX & ", " & enemyScoutY, me);
 
9089
                        minEnemyScouts = 0;
 
9090
                        maxEnemyScouts = 0;
 
9091
                        numEnemyScouts = 0;
 
9092
                        realEnemyScoutX = 0;
 
9093
                        realEnemyScoutY = 0;
 
9094
 
 
9095
                        //fMapRevealFactor = MAP_REVEAL_FAC_UBOUND;
 
9096
 
 
9097
                        groupAddGroupCmd(defendGr, enemyScoutGr);
 
9098
                        setEventTrigger(scoutForEnemy, inactive);       //deactivate
 
9099
                }
 
9100
                else
 
9101
                {
 
9102
                        orderGroupLocCmd(enemyScoutGr, DORDER_MOVE, realEnemyScoutX, realEnemyScoutY);
 
9103
                        //dbg(" " & me & ")  sending enemy scout to: " & x & ", " & y);
 
9104
                }
 
9105
 
 
9106
        }
 
9107
        else
 
9108
        {
 
9109
                dbg("scoutForEnemy() - no valid coords", me);
 
9110
                //exit;
 
9111
        }
 
9112
 
 
9113
        //find coords for the next time
 
9114
        //--------------------------------------
 
9115
        count = 0;              //times tried
 
9116
 
 
9117
        if((enemyScoutX > 0) and (enemyScoutY > 0))
 
9118
        {
 
9119
                realEnemyScoutX = enemyScoutX;
 
9120
                realEnemyScoutY = enemyScoutY;
 
9121
        }
 
9122
        else
 
9123
        {
 
9124
                realEnemyScoutX = baseX;
 
9125
                realEnemyScoutY = baseY;
 
9126
        }
 
9127
 
 
9128
        bResult = TRUE;         //revealed
 
9129
        while(bResult and (count < 200))                //until finds a not revealed loc
 
9130
        {
 
9131
                getNextScoutCoord(realEnemyScoutX, realEnemyScoutY);    //Sets enemyScoutX and Y vars
 
9132
                realEnemyScoutX = enemyScoutX;
 
9133
                realEnemyScoutY = enemyScoutY;
 
9134
 
 
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);
 
9139
 
 
9140
                count = count + 1;
 
9141
        }
 
9142
 
 
9143
        if(bResult)             //no new coords found
 
9144
        {
 
9145
                dbg("couldn't find next spot after: " & enemyScoutX & ", " & enemyScoutY, me);
 
9146
                minEnemyScouts = 0;
 
9147
                maxEnemyScouts = 0;
 
9148
                numEnemyScouts = 0;
 
9149
                groupAddGroupCmd(defendGr, enemyScoutGr);
 
9150
                setEventTrigger(scoutForEnemy, inactive);               //deactivate
 
9151
        }
 
9152
        //else
 
9153
        //{
 
9154
        //      dbg(" " & me & ")  found new enemy scout coords");
 
9155
        //}
 
9156
}
 
9157
 
 
9158
function void getNextScoutCoord(int _lastX, int _lastY)
 
9159
{
 
9160
        temp = (9 * 128);               //border offset
 
9161
 
 
9162
        tempX = _lastX;
 
9163
        tempY = _lastY;
 
9164
 
 
9165
        if(bEnemyScoutHor)              //horizontal - main direction
 
9166
        {
 
9167
                if(bEnemyScoutToRight)
 
9168
                {
 
9169
                        tempX = tempX + enemyScoutStep;
 
9170
 
 
9171
                        //check if unit too close to hor edge already
 
9172
                        if(tempX > ((mapWidth * 128) - temp))           //too close to edge
 
9173
                        {
 
9174
                                //dbg(" " & me & ")  ----reached right edge");
 
9175
 
 
9176
                                tempX = ((mapWidth * 128) - temp);
 
9177
                                bEnemyScoutToRight = FALSE;
 
9178
 
 
9179
                                //have to skip a vert line now
 
9180
 
 
9181
                                if(not bEnemyScoutToBottom)     //going to top
 
9182
                                {
 
9183
                                        tempY = tempY - enemyScoutStep;
 
9184
 
 
9185
                                        //check vertical edge now
 
9186
                                        if(tempY < temp)        //reached top
 
9187
                                        {
 
9188
                                                //dbg(" " & me & ")  ----reached top edge");
 
9189
                                                tempY = temp;
 
9190
                                                bEnemyScoutToBottom = TRUE;
 
9191
                                        }
 
9192
                                }
 
9193
                                else            //going to bottom
 
9194
                                {
 
9195
                                        tempY = tempY + enemyScoutStep;
 
9196
                                        //check vertical edge now
 
9197
                                        if(tempY > ((mapHeight * 128) - temp))  //reached bottom
 
9198
                                        {
 
9199
                                                //dbg(" " & me & ")  ----reached bottom edge");
 
9200
                                                tempY = ((mapHeight * 128) - temp);
 
9201
                                                bEnemyScoutToBottom = FALSE;
 
9202
                                        }
 
9203
                                }
 
9204
                        }
 
9205
 
 
9206
 
 
9207
                }
 
9208
                else            //to left
 
9209
                {
 
9210
                        tempX = tempX - enemyScoutStep;
 
9211
 
 
9212
                        //check if unit too close to hor edge already
 
9213
                        if(tempX < temp)                //too close to edge
 
9214
                        {
 
9215
                                //dbg(" " & me & ")  ----reached left edge");
 
9216
                                tempX = temp;
 
9217
                                bEnemyScoutToRight = TRUE;      //change dir next time
 
9218
 
 
9219
                                //have to skip a vert line now
 
9220
 
 
9221
                                if(not bEnemyScoutToBottom)     //going to top
 
9222
                                {
 
9223
                                        tempY = tempY - enemyScoutStep;
 
9224
 
 
9225
                                        //check vertical edge now
 
9226
                                        if(tempY < temp)        //reached top
 
9227
                                        {
 
9228
                                                //dbg(" " & me & ")  ----reached top edge");
 
9229
                                                tempY = temp;
 
9230
                                                bEnemyScoutToBottom = TRUE;
 
9231
                                        }
 
9232
                                }
 
9233
                                else                            //going to bottom
 
9234
                                {
 
9235
                                        tempY = tempY + enemyScoutStep;
 
9236
                                        //check vertical edge now
 
9237
                                        if(tempY > ((mapHeight * 128) - temp))  //reached bottom
 
9238
                                        {
 
9239
                                                //dbg(" " & me & ")  ----reached bottom edge");
 
9240
                                                tempY = (mapHeight * 128) - temp;
 
9241
                                                bEnemyScoutToBottom = FALSE;
 
9242
                                        }
 
9243
                                }
 
9244
                        }
 
9245
                }
 
9246
        }
 
9247
        else    //main dir = vert
 
9248
        {
 
9249
                if(bEnemyScoutToBottom)
 
9250
                {
 
9251
                        tempY = tempY + enemyScoutStep;
 
9252
 
 
9253
                        //check if unit too close to ver edge already
 
9254
                        if(tempY > ((mapHeight * 128) - temp))          //too close to edge
 
9255
                        {
 
9256
                                //dbg(" " & me & ")  ----reached bottom edge");
 
9257
                                tempY = (mapHeight * 128) - temp;
 
9258
                                bEnemyScoutToBottom = FALSE;            //change dir
 
9259
 
 
9260
                                //have to skip a hor line now
 
9261
 
 
9262
                                if(not bEnemyScoutToRight)      //going left
 
9263
                                {
 
9264
                                        tempX = tempX - enemyScoutStep;
 
9265
 
 
9266
                                        //check hor edge now
 
9267
                                        if(tempX < temp)        //reached left
 
9268
                                        {
 
9269
                                                //dbg(" " & me & ")  ----reached left edge");
 
9270
                                                tempX = temp;
 
9271
                                                bEnemyScoutToRight = TRUE;
 
9272
                                        }
 
9273
                                }
 
9274
                                else    //to right
 
9275
                                {
 
9276
                                        tempX = tempX + enemyScoutStep;
 
9277
                                        //check hor edge now
 
9278
                                        if(tempX > ((mapWidth * 128) - temp))   //reached right
 
9279
                                        {
 
9280
                                                //dbg(" " & me & ")  ----reached right edge");
 
9281
                                                tempX = (mapWidth * 128) - temp;
 
9282
                                                bEnemyScoutToRight = FALSE;
 
9283
                                        }
 
9284
                                }
 
9285
                        }
 
9286
 
 
9287
 
 
9288
                }
 
9289
                else            //to top
 
9290
                {
 
9291
                        tempY = tempY - enemyScoutStep;
 
9292
 
 
9293
                        //check if unit too close to ver edge already
 
9294
                        if(tempY < temp)                //too close to edge
 
9295
                        {
 
9296
                                tempY = temp;
 
9297
                                bEnemyScoutToBottom = TRUE;             //change dir
 
9298
 
 
9299
                                //have to skip a hor line now
 
9300
 
 
9301
                                if(not bEnemyScoutToRight)      //going left
 
9302
                                {
 
9303
                                        tempX = tempX - enemyScoutStep;
 
9304
 
 
9305
                                        //check hor edge now
 
9306
                                        if(tempX < temp)        //reached left
 
9307
                                        {
 
9308
                                                //dbg(" " & me & ")  ----reached left edge");
 
9309
                                                tempX = temp;
 
9310
                                                bEnemyScoutToRight = TRUE;
 
9311
                                        }
 
9312
                                }
 
9313
                                else    //to right
 
9314
                                {
 
9315
                                        tempX = tempX + enemyScoutStep;
 
9316
                                        //check hor edge now
 
9317
                                        if(tempX > ((mapWidth * 128) - temp))   //reached right
 
9318
                                        {
 
9319
                                                //dbg(" " & me & ")  ----reached right edge");
 
9320
                                                tempX = (mapWidth * 128) - temp;
 
9321
                                                bEnemyScoutToRight = FALSE;
 
9322
                                        }
 
9323
                                }
 
9324
                        }
 
9325
                }
 
9326
        }
 
9327
 
 
9328
        enemyScoutX = tempX;
 
9329
        enemyScoutY = tempY;
 
9330
}
 
9331
 
 
9332
//---------------------------------------------------------------
 
9333
//      Returns closest corner based on arguments
 
9334
//---------------------------------------------------------------
 
9335
function void getClosestCorner(int _x, int _y)
 
9336
{
 
9337
        temp = (12 * 128);      //border offset
 
9338
 
 
9339
        //horizontal
 
9340
        retInt = temp;                                  //left
 
9341
        if(_x > ((mapWidth * 128) / 2))
 
9342
        {
 
9343
                retInt = (mapWidth * 128) - temp;       //right
 
9344
        }
 
9345
 
 
9346
 
 
9347
        //vertical
 
9348
        retInt2 = temp;                                 //top
 
9349
        if(_y > ((mapHeight * 128) / 2))
 
9350
        {
 
9351
                retInt2 = (mapHeight * 128) - temp;     //bottom
 
9352
        }
 
9353
}
 
9354
 
 
9355
//Calculate number of defenders to leave in the base when going out with the main force to attack stuff
 
9356
function void updateNumDefenders()
 
9357
{
 
9358
        local   int             _attackDistance,_numActiveEnemies,_numActiveAllies,_player,
 
9359
                                        _numBaseDefenses;
 
9360
        local   float   _enemyFactor;
 
9361
 
 
9362
 
 
9363
 
 
9364
        /* If we are not using additional base defenders, leave minimum in the base */
 
9365
        if(NO_BASE_DEFENDERS)
 
9366
        {
 
9367
                numDefenders = minDefenders;
 
9368
                return;
 
9369
        }
 
9370
        else if(PROGRESSIVE_DEFENDERS)
 
9371
        {
 
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
 
9376
                }
 
9377
 
 
9378
                // leave 9 defenders for 40 and 18 for total 80 units
 
9379
                numDefenders = max(minDefenders, (int)((float)numAvailableAttackers() / 5.44));
 
9380
                return;
 
9381
        }
 
9382
 
 
9383
        // make sure we have all the necessary values
 
9384
        if(sendForceX <= 0 or baseX <= 0){
 
9385
                return;
 
9386
        }
 
9387
 
 
9388
        if( !(state == stAttacking or state == stHelpingAlly) ){
 
9389
                return;
 
9390
        }
 
9391
 
 
9392
        //Count all our base defenses
 
9393
        _numBaseDefenses = numFriendlyWeapStructsInRange(me, baseX, baseY, COUNT_BASE_OBJECTS_RANGE, true) / STR_UNIT_DEFENSE_FACTOR;
 
9394
 
 
9395
        //Count active allies and enemies
 
9396
        _player = 0;
 
9397
        _numActiveEnemies = 0;
 
9398
        while(_player < MAX_PLAYERS)
 
9399
        {
 
9400
                if(_player != me)
 
9401
                {
 
9402
                        //make sure this player is still alive
 
9403
                        if(not dead[_player])
 
9404
                        {
 
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)) )
 
9408
                                {
 
9409
                                        if(not allianceExistsBetween(me, _player))
 
9410
                                        {
 
9411
                                                _numActiveEnemies++;
 
9412
                                        }
 
9413
                                        else
 
9414
                                        {
 
9415
                                                //Our ally can't help us if he's defending its base
 
9416
                                                if(allyState[_player] != stDefendingBase)
 
9417
                                                {
 
9418
                                                        _numActiveAllies++;
 
9419
                                                }
 
9420
                                        }
 
9421
                                }
 
9422
                        }
 
9423
                }
 
9424
                _player++;
 
9425
        }
 
9426
 
 
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
 
9429
 
 
9430
        //find out how far we are going with our main force
 
9431
        _attackDistance = distBetweenTwoPoints(sendForceX, sendForceY, baseX, baseY) / TILE;
 
9432
 
 
9433
 
 
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;
 
9437
}
 
9438
 
 
9439
function void updateMilitaryStatus()
 
9440
{
 
9441
        noBaseTargets = TRUE;   //reset here, set by checkBase()
 
9442
 
 
9443
        count = 0;
 
9444
        while(count < multiPlayerMaxPlayers)
 
9445
        {
 
9446
                if(count != me)
 
9447
                {
 
9448
                        ally[count] = FALSE;
 
9449
 
 
9450
                        if(allianceExistsBetween(count ,me) )
 
9451
                        {
 
9452
                                ally[count] = TRUE;
 
9453
                        }
 
9454
 
 
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
 
9457
                        if(not dead[count])
 
9458
                        {
 
9459
                                /* check if dead */
 
9460
                                //count2 = checkPlayerDead(count);
 
9461
                                if(checkPlayerDead(count))
 
9462
                                {
 
9463
                                        dead[count] = TRUE;
 
9464
 
 
9465
                                        dbg(getPlayerName(count) & " IS DEAD !!!!!!!!!!!!!!!!++++", me);
 
9466
 
 
9467
                                        notifyPlayerDead(count);
 
9468
                                }
 
9469
                        }
 
9470
 
 
9471
                        /* find base */
 
9472
                        if(not dead[count])
 
9473
                        {
 
9474
                                checkBase(count);
 
9475
                        }
 
9476
                }
 
9477
                count = count + 1;
 
9478
        }
 
9479
}
 
9480
 
 
9481
/* Some military checks */
 
9482
function void militarySelftest()
 
9483
{
 
9484
        if(researchFinished(resBB, me)) //BB
 
9485
        {
 
9486
                haveBB = TRUE;
 
9487
        }
 
9488
 
 
9489
        bCanUseCommanders = canUseCommanders();
 
9490
 
 
9491
        // how much of the map do we have revealed?
 
9492
/*      if(fMapRevealFactor < MAP_REVEAL_FAC_UBOUND)
 
9493
        {
 
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);
 
9497
                // trim
 
9498
                fMapRevealFactor = fmax(MAP_REVEAL_FAC_LBOUND, fMapRevealFactor);
 
9499
                fMapRevealFactor = fmin(MAP_REVEAL_FAC_UBOUND, fMapRevealFactor);
 
9500
        } */
 
9501
}
 
9502
 
 
9503
function void findAlternateTarget()
 
9504
{
 
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
        //------------------------------------------------------------------------------
 
9508
 
 
9509
        //find any other structure left
 
9510
        structure = getClosestEnemyStructByType(baseX, baseY, -1, REF_DEFENSE, me);
 
9511
        if(structure == NULLOBJECT)
 
9512
        {
 
9513
                structure = getClosestEnemyStructByType(baseX, baseY, -1, REF_RESOURCE_EXTRACTOR, me);
 
9514
        }
 
9515
 
 
9516
        //if found
 
9517
        if(structure != NULLOBJECT)
 
9518
        {
 
9519
                //centreView(structure);
 
9520
 
 
9521
                result = structure.player;
 
9522
                dbg("no valid base targets, found an alternative target for " & getPlayerName(result), me);
 
9523
 
 
9524
                seeBase[result] = TRUE;
 
9525
                knowBase[result] = TRUE;
 
9526
 
 
9527
                //dead[result] = FALSE;
 
9528
                //killedBase[result] = FALSE;
 
9529
 
 
9530
                curBase[result][0] = structure.x;
 
9531
                curBase[result][1] = structure.y;
 
9532
 
 
9533
                if(curHelpX[result] <= 0)
 
9534
                {
 
9535
                        curHelpX[result] = curBase[result][0];
 
9536
                        curHelpY[result] = curBase[result][1];
 
9537
                }
 
9538
 
 
9539
                //if((base[result][0] <= 0) or (base[result][1] <= 0))
 
9540
                //{
 
9541
                //      base[result][0] = structure.x;
 
9542
                //      base[result][1] = structure.y;
 
9543
                //}
 
9544
 
 
9545
                noBaseTargets = FALSE;
 
9546
        }
 
9547
}
 
9548
 
 
9549
function bool canStartAttack(int _enemy)
 
9550
{
 
9551
        if(numAvailableAttackers() < numPlayerAttackers[_enemy])
 
9552
        {
 
9553
                return(FALSE);
 
9554
        }
 
9555
 
 
9556
        // make sure we found enemy base
 
9557
        if(curBase[_enemy][0] < 0 or curBase[_enemy][1] < 0)
 
9558
        {
 
9559
                return false;
 
9560
        }
 
9561
 
 
9562
        return(TRUE);
 
9563
}
 
9564
 
 
9565
function bool canStartArtyCouterAttack(int _enemy, int _x, int _y)
 
9566
{
 
9567
        if(!haveTheoreticallyMinAttackers(false))
 
9568
        {
 
9569
                return false;
 
9570
        }
 
9571
 
 
9572
        if(numEnemyWeapObjInRange(me, _x, _y, (TILE * 7), false, true) > numAvailableAttackers())
 
9573
        {
 
9574
                return false;
 
9575
        }
 
9576
 
 
9577
        return true;
 
9578
}
 
9579
 
 
9580
//count current attackers as well
 
9581
function bool canTheoreticallyStartAttack()
 
9582
{
 
9583
        if(numAvailableAttackers() >= numAttackers)
 
9584
        {
 
9585
                return(TRUE);
 
9586
        }
 
9587
 
 
9588
        return(FALSE);
 
9589
}
 
9590
 
 
9591
// have *any* attackers? (count current attackers as well)
 
9592
function bool haveTheoreticallyMinAttackers(bool _bSafeToSendLittleAttackers)
 
9593
{
 
9594
        if(_bSafeToSendLittleAttackers)         //it's ok to send little attackers, for example if joining forces with other players
 
9595
        {
 
9596
                if((totalWeapUnits() - minDefenders) >= minAttackers)
 
9597
                {
 
9598
                        return TRUE;
 
9599
                }
 
9600
        }
 
9601
        else    //too dangerous to send little attackers, wait until we get more units
 
9602
        {
 
9603
                if(numAvailableAttackers() >= minAttackers)
 
9604
                {
 
9605
                        return TRUE;
 
9606
                }
 
9607
        }
 
9608
 
 
9609
 
 
9610
        return FALSE;
 
9611
}
 
9612
 
 
9613
/* All units - number of required defenders */
 
9614
function int numAvailableAttackers()
 
9615
{
 
9616
        return max(totalWeapUnits() - numDefenders, 0);
 
9617
}
 
9618
 
 
9619
/* Total units that can attack, including defenders */
 
9620
function int totalWeapUnits()
 
9621
{
 
9622
        return groupSizeCmds(attackGr,true,false,true) +
 
9623
                   groupSizeCmds(sendAttackGr,true,false,true) +
 
9624
                   groupSizeCmds(defendGr,true,false,true);
 
9625
}
 
9626
 
 
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)
 
9630
{
 
9631
        local   int             _index,_numDroids;
 
9632
        local   bool    _bCMDsOnly;
 
9633
        
 
9634
        // Optimization: equivalent to _groupToCount.members
 
9635
        if(_bIncludeUnassigned and !_bIncludeCmds and !_bInclDroidsAssignedToCmds){
 
9636
                return _groupToCount.members;
 
9637
        }
 
9638
 
 
9639
        //_groupToCount can only be NULL if we are counting commanders only
 
9640
        if((_groupToCount == NULLOBJECT) and
 
9641
                (_bIncludeCmds == TRUE && _bInclDroidsAssignedToCmds == FALSE))
 
9642
        {
 
9643
                _bCMDsOnly = TRUE;
 
9644
        }
 
9645
 
 
9646
        if(!_bCMDsOnly and _bIncludeUnassigned){
 
9647
                _numDroids = _groupToCount.members;     //count droids not assigned to a comamdner
 
9648
        }
 
9649
 
 
9650
        while(_index < MAX_COMMANDERS)
 
9651
        {
 
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) )
 
9655
                {
 
9656
                        //Include units assigned to this commander
 
9657
                        if(_bInclDroidsAssignedToCmds)
 
9658
                        {
 
9659
                                if(cmds[_index].group == NULLOBJECT)
 
9660
                                {
 
9661
                                        debug("commander " & _index & " group is null");
 
9662
                                }
 
9663
                                _numDroids = _numDroids + cmds[_index].group.members;   //count droids in the commander group
 
9664
                        }
 
9665
 
 
9666
                        //Count the commander
 
9667
                        if(_bIncludeCmds)
 
9668
                        {
 
9669
                                _numDroids++;
 
9670
                        }
 
9671
                }
 
9672
                _index++;
 
9673
        }
 
9674
 
 
9675
        return _numDroids;
 
9676
}
 
9677
 
 
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)
 
9680
{
 
9681
        local   int             _cmdIndex;
 
9682
 
 
9683
        //Order droids without commander
 
9684
        orderGroupLoc(_groupToOrder, _order, _x, _y);
 
9685
 
 
9686
        //Order commanders belonging to this group
 
9687
        _cmdIndex = 0;
 
9688
        while(_cmdIndex < MAX_COMMANDERS)
 
9689
        {
 
9690
                if(cmds[_cmdIndex] != NULLOBJECT)
 
9691
                {
 
9692
                        if(cmdGr[_cmdIndex] == _groupToOrder)
 
9693
                        {
 
9694
                                orderDroidLoc(cmds[_cmdIndex], _order, _x, _y);
 
9695
                        }
 
9696
                }
 
9697
                _cmdIndex++;
 
9698
        }
 
9699
}
 
9700
 
 
9701
/* Add Commander to some group */
 
9702
function void groupAddCmd(GROUP _group, DROID _commander)
 
9703
{
 
9704
        ASSERT(_commander != NULLOBJECT,
 
9705
                "groupAddCmd: commander is NULL", me);
 
9706
 
 
9707
        //set group for a commander
 
9708
        cmdGr[cmdToIndex(_commander)] = _group;
 
9709
}
 
9710
 
 
9711
/* Returns index of a commander */
 
9712
function int cmdToIndex(DROID _commander)
 
9713
{
 
9714
        local int               _index;
 
9715
 
 
9716
        ASSERT(_commander != NULLOBJECT,
 
9717
                "cmdToIndex: commander is NULL", me);
 
9718
 
 
9719
        _index = 0;
 
9720
        while(_index< MAX_COMMANDERS)
 
9721
        {
 
9722
                if(_commander == cmds[_index])
 
9723
                {
 
9724
                        return _index;
 
9725
                }
 
9726
                _index++;
 
9727
        }
 
9728
 
 
9729
        ASSERT(_index >= 0, "cmdToIndex: couldn't find commander", me);
 
9730
 
 
9731
        return -1;      //not found
 
9732
}
 
9733
 
 
9734
//Move droids and all commanders belonging to a certain group to another group
 
9735
function void groupAddGroupCmd(GROUP _groupTo, GROUP _groupFrom)
 
9736
{
 
9737
        local   int             _cmdIndex;
 
9738
 
 
9739
        groupAddGroup(_groupTo, _groupFrom);
 
9740
 
 
9741
        //Move all commanders to a new group
 
9742
        _cmdIndex = 0;
 
9743
        while(_cmdIndex < MAX_COMMANDERS)
 
9744
        {
 
9745
                if(cmds[_cmdIndex] != NULLOBJECT)
 
9746
                {
 
9747
                        if(cmdGr[_cmdIndex] == _groupFrom)
 
9748
                        {
 
9749
                                cmdGr[_cmdIndex] = _groupTo;
 
9750
                        }
 
9751
                }
 
9752
                _cmdIndex++;
 
9753
        }
 
9754
}
 
9755
 
 
9756
// Returns x coordinate of the group, takes commanders into account
 
9757
function int groupCMD_x(GROUP _group)
 
9758
{
 
9759
        local   int             _x,_numUnits,_cmdIndex;
 
9760
 
 
9761
        _x = _group.x;
 
9762
        _numUnits = _group.members;
 
9763
 
 
9764
        _cmdIndex = 0;
 
9765
        while(_cmdIndex < MAX_COMMANDERS)
 
9766
        {
 
9767
                if(cmds[_cmdIndex] != NULLOBJECT)
 
9768
                {
 
9769
                        if(cmdGr[_cmdIndex] == _group)
 
9770
                        {
 
9771
                                // commander unit
 
9772
                                _x = _x + cmds[_cmdIndex].x;
 
9773
                                _numUnits++;
 
9774
 
 
9775
                                // count units assigned to commander
 
9776
                                _x = _x + cmds[_cmdIndex].group.x;
 
9777
                                _numUnits = _numUnits + cmds[_cmdIndex].group.members;
 
9778
                        }
 
9779
                }
 
9780
                _cmdIndex++;
 
9781
        }
 
9782
 
 
9783
        if(_numUnits <= 0){
 
9784
                return -1;
 
9785
        }
 
9786
 
 
9787
        return (_x / _numUnits);
 
9788
}
 
9789
 
 
9790
// Returns y coordinate of the group, takes commanders into account
 
9791
function int groupCMD_y(GROUP _group)
 
9792
{
 
9793
        local   int             _y,_numUnits,_cmdIndex;
 
9794
 
 
9795
        _y = _group.y;
 
9796
        _numUnits = _group.members;
 
9797
 
 
9798
        _cmdIndex = 0;
 
9799
        while(_cmdIndex < MAX_COMMANDERS)
 
9800
        {
 
9801
                if(cmds[_cmdIndex] != NULLOBJECT)
 
9802
                {
 
9803
                        if(cmdGr[_cmdIndex] == _group)
 
9804
                        {
 
9805
                                // commander unit
 
9806
                                _y = _y + cmds[_cmdIndex].y;
 
9807
                                _numUnits++;
 
9808
 
 
9809
                                // count units assigned to commander
 
9810
                                _y = _y + cmds[_cmdIndex].group.y;
 
9811
                                _numUnits = _numUnits + cmds[_cmdIndex].group.members;
 
9812
                        }
 
9813
                }
 
9814
                _cmdIndex++;
 
9815
        }
 
9816
 
 
9817
        if(_numUnits <= 0){
 
9818
                return -1;
 
9819
        }
 
9820
 
 
9821
        return (_y / _numUnits);
 
9822
}
 
9823
 
 
9824
function int idleGroupCmd(GROUP _idleGroup, bool _bIncludeNonCmds, bool _bIncludeCmds)
 
9825
{
 
9826
        local   int             _cmdIndex,_numIdle;
 
9827
 
 
9828
        _numIdle = idleGroup(_idleGroup);
 
9829
 
 
9830
        // if(_bIncludeCmds)
 
9831
        // {
 
9832
                _cmdIndex = 0;
 
9833
                while(_cmdIndex < MAX_COMMANDERS)
 
9834
                {
 
9835
                        if(cmds[_cmdIndex] != NULLOBJECT)
 
9836
                        {
 
9837
                                if(cmdGr[_cmdIndex] == _idleGroup)
 
9838
                                {
 
9839
                                        // commander
 
9840
                                        if(_bIncludeCmds)
 
9841
                                        {
 
9842
                                                if((cmds[_cmdIndex].order == DORDER_NONE) ||
 
9843
                                                        (cmds[_cmdIndex].order == DORDER_GUARD and cmds[_cmdIndex].target == NULLOBJECT))
 
9844
                                                {
 
9845
                                                        _numIdle++;
 
9846
                                                }
 
9847
                                        }
 
9848
 
 
9849
                                        // units attached to a commander
 
9850
                                        if(_bIncludeNonCmds)
 
9851
                                        {
 
9852
                                                _numIdle = _numIdle + idleGroup(cmds[_cmdIndex].group);
 
9853
                                        }
 
9854
                                }
 
9855
                        }
 
9856
                        _cmdIndex++;
 
9857
                }
 
9858
        // }
 
9859
 
 
9860
        return _numIdle;
 
9861
}
 
9862
 
 
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)
 
9866
{
 
9867
        local   int             _cmdIndex;
 
9868
 
 
9869
/*      dbg("initIterateGroupCmd: " & _bReturnNonCmds & "," &
 
9870
                _bReturnCmds & "," & _bReturnCmdAssignedDroids , me); */
 
9871
 
 
9872
        ASSERT(_bReturnNonCmds or _bReturnCmds or _bReturnCmdAssignedDroids,
 
9873
                "initIterateGroupCmd: no units to return", me);
 
9874
 
 
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);
 
9879
 
 
9880
        //dbg("New groupIterateBucket = " & groupIterateBucket, me);
 
9881
 
 
9882
        ASSERT(groupIterateBucket < MAX_GROUP_ITERATE_BUCKET,
 
9883
                "initIterateGroupCmd: can't start any more iterations (" &
 
9884
                groupIterateBucket & ")", me);
 
9885
 
 
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
 
9893
 
 
9894
        iterateGroupDroid[groupIterateBucket] = NULLOBJECT;
 
9895
 
 
9896
        iterateStage[groupIterateBucket] = 3;   //nothing left
 
9897
 
 
9898
        //Prepare first non-commander droid
 
9899
        if(bIterateNonCommanders[groupIterateBucket])
 
9900
        {
 
9901
                iterateStage[groupIterateBucket] = 0;   //iterating over main group
 
9902
                initIterateGroup(groupToIterate[groupIterateBucket]);
 
9903
                iterateGroupDroid[groupIterateBucket] = iterateGroup(groupToIterate[groupIterateBucket]);
 
9904
        }
 
9905
 
 
9906
        if(iterateGroupDroid[groupIterateBucket] == NULLOBJECT)
 
9907
        {
 
9908
                if(bIterateCommanders[groupIterateBucket])
 
9909
                {
 
9910
                        iterateStage[groupIterateBucket] = 1;
 
9911
 
 
9912
                        //Iterate through all commanders
 
9913
                        _cmdIndex = 0;
 
9914
                        while((_cmdIndex < MAX_COMMANDERS) and (iterateGroupDroid[groupIterateBucket] == NULLOBJECT))
 
9915
                        {
 
9916
                                if(cmds[_cmdIndex] != NULLOBJECT)
 
9917
                                {
 
9918
                                        if(cmdGr[_cmdIndex] == groupToIterate[groupIterateBucket])
 
9919
                                        {
 
9920
                                                //return this commander
 
9921
                                                iterateGroupDroid[groupIterateBucket] = cmds[_cmdIndex];
 
9922
                                                iterateCommanderIndex[groupIterateBucket] = _cmdIndex + 1;      //access next commander next time
 
9923
                                        }
 
9924
                                }
 
9925
                                _cmdIndex++;
 
9926
                        }
 
9927
                }
 
9928
        }
 
9929
 
 
9930
        if(iterateGroupDroid[groupIterateBucket] == NULLOBJECT)
 
9931
        {
 
9932
                if(bIterateCmdAssignedDroids[groupIterateBucket])
 
9933
                {
 
9934
                        iterateStage[groupIterateBucket] = 2;
 
9935
 
 
9936
                        //Iterate through all droids assigned to commanders
 
9937
                        _cmdIndex = 0;
 
9938
                        while((_cmdIndex < MAX_COMMANDERS) and (iterateGroupDroid[groupIterateBucket] == NULLOBJECT))
 
9939
                        {
 
9940
                                if(cmds[_cmdIndex] != NULLOBJECT)
 
9941
                                {
 
9942
                                        if(cmdGr[_cmdIndex] == groupToIterate[groupIterateBucket])
 
9943
                                        {
 
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]);
 
9948
 
 
9949
                                                iterateCommanderIndex[groupIterateBucket] = _cmdIndex;  //access this commander again next time
 
9950
                                        }
 
9951
                                }
 
9952
                                _cmdIndex++;
 
9953
                        }
 
9954
                }
 
9955
        }
 
9956
 
 
9957
        if(iterateGroupDroid[groupIterateBucket] == NULLOBJECT)
 
9958
        {
 
9959
                iterateStage[groupIterateBucket] = 3;
 
9960
        }
 
9961
 
 
9962
        return groupIterateBucket;
 
9963
}
 
9964
 
 
9965
//Same as iterateGroup() but also returns commanders
 
9966
function DROID iterateGroupCmd(GROUP _groupToIterate, int _bucket)
 
9967
{
 
9968
        local   DROID   _preparedDroid;
 
9969
        local   int             _cmdIndex;
 
9970
        local   bool    _bStop;
 
9971
 
 
9972
        // ASSERT(_bucket <= groupIterateBucket,
 
9973
                // "iterateGroupCmd: wrong bucket: " & _bucket & "/" & groupIterateBucket, me);
 
9974
 
 
9975
        ASSERT(_groupToIterate == groupToIterate[_bucket],
 
9976
                "iterateGroupCmd: wrong group passed", me);
 
9977
 
 
9978
        ASSERT(bIterateNonCommanders[_bucket] or bIterateCommanders[_bucket] or
 
9979
                   bIterateCmdAssignedDroids[_bucket],
 
9980
                "iterateGroupCmd: no units to return", me);
 
9981
 
 
9982
        // decrease bucket, since we are done now
 
9983
        if(iterateStage[_bucket] == 3)
 
9984
        {
 
9985
                //dbg("Decreasing groupIterateBucket from " & groupIterateBucket, me);
 
9986
 
 
9987
                // ASSERT(_preparedDroid != NULLOBJECT,
 
9988
                        // "iterateGroupCmd: _preparedDroid is NULL, called this function after it returned NULL?", me);
 
9989
 
 
9990
                groupToIterate[_bucket] = NULLOBJECT;   // mark this iteration as finished
 
9991
 
 
9992
                // reset some values
 
9993
                bIterateNonCommanders[_bucket] = false;
 
9994
                bIterateCommanders[_bucket] = false;
 
9995
                bIterateCmdAssignedDroids[_bucket] = false;
 
9996
 
 
9997
                // groupIterateBucket--;        // will only get once to this part, since values are reseat and checked before this place
 
9998
 
 
9999
                ASSERT(groupIterateBucket >= 0,
 
10000
                        "iterateGroupCmd: groupIterateBucket = " & groupIterateBucket, me);
 
10001
 
 
10002
                _preparedDroid = NULLOBJECT;
 
10003
 
 
10004
                return _preparedDroid;
 
10005
        }
 
10006
 
 
10007
        //store prepared droid
 
10008
        _preparedDroid = iterateGroupDroid[_bucket];
 
10009
        iterateGroupDroid[_bucket] = NULLOBJECT;
 
10010
 
 
10011
        //Get next droid from the main group
 
10012
        if(iterateStage[_bucket] == 0)
 
10013
        {
 
10014
                iterateGroupDroid[_bucket] = iterateGroup(groupToIterate[_bucket]);
 
10015
 
 
10016
                if(iterateGroupDroid[_bucket] == NULLOBJECT)
 
10017
                {
 
10018
                        iterateStage[_bucket] = 1;
 
10019
                }
 
10020
        }
 
10021
 
 
10022
        if(iterateStage[_bucket] == 1)
 
10023
        {
 
10024
                if(bIterateCommanders[_bucket])
 
10025
                {
 
10026
                        //Iterate through all commanders
 
10027
                        _cmdIndex = iterateCommanderIndex[_bucket];
 
10028
                        while((_cmdIndex < MAX_COMMANDERS) and (iterateGroupDroid[_bucket] == NULLOBJECT))
 
10029
                        {
 
10030
                                if(cmds[_cmdIndex] != NULLOBJECT)
 
10031
                                {
 
10032
                                        if(cmdGr[_cmdIndex] == groupToIterate[_bucket])
 
10033
                                        {
 
10034
                                                iterateGroupDroid[_bucket] = cmds[_cmdIndex];
 
10035
                                                iterateCommanderIndex[_bucket] = _cmdIndex + 1; //access next commander next time
 
10036
                                        }
 
10037
                                }
 
10038
                                _cmdIndex++;
 
10039
                        }
 
10040
 
 
10041
                        //Check if no commanders left
 
10042
                        if(iterateGroupDroid[_bucket] == NULLOBJECT)
 
10043
                        {
 
10044
                                iterateStage[_bucket] = 2;
 
10045
                                iterateCommanderIndex[_bucket] = 0;
 
10046
                                iterateCmdGroup[_bucket] = NULLOBJECT;
 
10047
                        }
 
10048
                }
 
10049
                else
 
10050
                {
 
10051
                        iterateStage[_bucket] = 2;      //start iterating droids assigned to commanders if needed
 
10052
                        iterateCommanderIndex[_bucket] = 0;
 
10053
                        iterateCmdGroup[_bucket] = NULLOBJECT;
 
10054
                }
 
10055
        }
 
10056
 
 
10057
        if(iterateStage[_bucket] == 2)
 
10058
        {
 
10059
                if(bIterateCmdAssignedDroids[_bucket])
 
10060
                {
 
10061
                        _bStop = false;
 
10062
                        _cmdIndex = iterateCommanderIndex[_bucket];
 
10063
                        while(!_bStop and (iterateCommanderIndex[_bucket] < MAX_COMMANDERS) and (iterateGroupDroid[_bucket] == NULLOBJECT))
 
10064
                        {
 
10065
                                //Find next commander that belongs to the right group
 
10066
                                _cmdIndex = iterateCommanderIndex[_bucket];
 
10067
                                while((iterateCmdGroup[_bucket] == NULLOBJECT) and (_cmdIndex < MAX_COMMANDERS))
 
10068
                                {
 
10069
                                        if(cmds[_cmdIndex] != NULLOBJECT)
 
10070
                                        {
 
10071
                                                if(cmdGr[_cmdIndex] == groupToIterate[_bucket])
 
10072
                                                {
 
10073
                                                        iterateCmdGroup[_bucket] = cmds[_cmdIndex].group;
 
10074
                                                        initIterateGroup(iterateCmdGroup[_bucket]);
 
10075
                                                        iterateCommanderIndex[_bucket] = _cmdIndex;
 
10076
                                                }
 
10077
                                        }
 
10078
                                        _cmdIndex++;
 
10079
                                }
 
10080
 
 
10081
                                //Get next droid of this commander
 
10082
                                if(iterateCmdGroup[_bucket] != NULLOBJECT)      //any suitable commander left?
 
10083
                                {
 
10084
                                        iterateGroupDroid[_bucket] = iterateGroup(iterateCmdGroup[_bucket]);
 
10085
 
 
10086
                                        //It was the last droid of this commander, try next commander
 
10087
                                        if(iterateGroupDroid[_bucket] == NULLOBJECT)
 
10088
                                        {
 
10089
                                                iterateCmdGroup[_bucket] = NULLOBJECT;
 
10090
                                                iterateCommanderIndex[_bucket] = iterateCommanderIndex[_bucket] + 1;
 
10091
 
 
10092
                                                if(iterateCommanderIndex[_bucket] >= MAX_COMMANDERS)
 
10093
                                                {
 
10094
                                                        _bStop = true;
 
10095
                                                        iterateStage[_bucket] = 3;
 
10096
                                                }
 
10097
                                        }
 
10098
                                }
 
10099
                                else
 
10100
                                {
 
10101
                                        _bStop = true;
 
10102
                                        iterateStage[_bucket] = 3;
 
10103
                                }
 
10104
                        }
 
10105
                }
 
10106
                else
 
10107
                {
 
10108
                        iterateStage[_bucket] = 3;
 
10109
                }
 
10110
        }
 
10111
 
 
10112
        return _preparedDroid;
 
10113
}
 
10114
 
 
10115
//---------------------------------------------------------------
 
10116
//      Check base coords are valid for a certain player
 
10117
//---------------------------------------------------------------
 
10118
function void checkBase(int _player)
 
10119
{
 
10120
        local bool _bCanSeeBase;
 
10121
 
 
10122
        ASSERT(_player >= 0, "checkBase - _player < 0", me);
 
10123
 
 
10124
        if(bCheckBaseDebug)dbg("--checkBase--", me);
 
10125
        
 
10126
        if(knowBase[_player])
 
10127
        {
 
10128
                if(bCheckBaseDebug)dbg("checkBase: know base for " & _player, me);
 
10129
 
 
10130
                if((curBase[_player][0] <= 0) or (curBase[_player][1] <= 0))
 
10131
                        MsgBox("checkBase() - curBase <= 0");
 
10132
 
 
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)
 
10134
                {
 
10135
                        if(bCheckBaseDebug)dbg("checkBase: for revealed for " & _player, me);
 
10136
                        
 
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]);
 
10140
                        }
 
10141
                        
 
10142
                        if(bCheckBaseDebug && _bCanSeeBase)dbg("checkBase: can see loc for player " & _player, me);
 
10143
                        
 
10144
                        if(_bCanSeeBase and !enemyTargetInRange(_player, curBase[_player][0], curBase[_player][1], (2 * 128)) )
 
10145
                        {
 
10146
                                if(bCheckBaseDebug)dbg("checkBase: have no targets for " & _player, me);
 
10147
                                
 
10148
                                //if((curBase[_player][0] == base[_player][0]) and (curBase[_player][1] == base[_player][1]))
 
10149
                                //{
 
10150
                                //      dbg(" " & me & ")  recalled location is empty for " & _player & " !!!!!!!!!!!!!!!!!!!!!!!");
 
10151
                                //}
 
10152
 
 
10153
                                //find new base
 
10154
                                //temp = findBase(_player);
 
10155
 
 
10156
                                if(findBase(_player))   //found new location of the base for this player
 
10157
                                {
 
10158
                                        dbg("Corrected base coords for player" & _player, me);
 
10159
 
 
10160
                                        curBase[_player][0] = retInt;
 
10161
                                        curBase[_player][1] = retInt2;
 
10162
 
 
10163
                                        if(curHelpX[_player] <= 0)
 
10164
                                        {
 
10165
                                                curHelpX[_player] = curBase[_player][0];
 
10166
                                                curHelpY[_player] = curBase[_player][1];
 
10167
                                        }
 
10168
 
 
10169
                                        /* update destination coords if going to this player */
 
10170
                                        if(attackingEnemyBase(_player))
 
10171
                                        {
 
10172
                                                dbg("Enemy cords updated", me);
 
10173
 
 
10174
                                                updateStateCoord(curBase[_player][0], curBase[_player][1]);
 
10175
                                        }
 
10176
 
 
10177
                                        seeBase[_player] = TRUE;        //found base
 
10178
 
 
10179
                                        if(not ally[_player])
 
10180
                                                noBaseTargets = FALSE;
 
10181
 
 
10182
                                        dbg("found a different enemy base location for " & _player, me);
 
10183
 
 
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))
 
10186
                                        {
 
10187
                                                base[_player][0] = retInt;
 
10188
                                                base[_player][1] = retInt2;
 
10189
                                        }
 
10190
 
 
10191
                                        //learn this location
 
10192
                                        if(bLearn)
 
10193
                                        {
 
10194
                                                if(not canRememberPlayerBaseLoc(me, _player))           //not already in memory
 
10195
                                                {
 
10196
                                                        learnPlayerBaseLoc(me, _player, retInt, retInt2);
 
10197
                                                }
 
10198
                                        }
 
10199
                                }
 
10200
                                else    //couldn't find anything
 
10201
                                {
 
10202
                                        if(_player == enemy)    //attacking this one right now
 
10203
                                        {
 
10204
                                                if(canSeePlayerBase(_player))           //warn only once, when just lost the base
 
10205
                                                {
 
10206
                                                        dbg("lost current enemy " & getPlayerName(_player) & " !!!!!!!!!!!!!!!!!!!!!", me);
 
10207
                                                }
 
10208
 
 
10209
                                        }
 
10210
                                        else if(canSeePlayerBase(_player))      //lost it now
 
10211
                                        {
 
10212
                                                dbg("lost base loc for enemy " & getPlayerName(_player), me);
 
10213
                                        }
 
10214
 
 
10215
                                        seeBase[_player] = FALSE;       //lost
 
10216
                                        //knowBase[_player] = FALSE;    //disabled 15.05.05 because of phSearchingForBase was skipped because of this
 
10217
                                }
 
10218
 
 
10219
                        }
 
10220
                        else            //enemy base still there
 
10221
                        {
 
10222
                                if(bCheckBaseDebug)dbg("checkBase: still have targets for " & _player, me);
 
10223
        
 
10224
                                if(not allianceExistsBetween(me , _player))     //this player is not our ally
 
10225
                                        noBaseTargets = FALSE;
 
10226
 
 
10227
                                /* make sure allies see newly found enemy base */
 
10228
                                if(not canSeePlayerBase(_player))       //just found
 
10229
                                        refreshAllyRadar();
 
10230
 
 
10231
                                seeBase[_player] = TRUE;        //can see base
 
10232
                        }
 
10233
                }
 
10234
                else    //enemy base still there (probably recalled it)
 
10235
                {
 
10236
                        if(not ally[_player])
 
10237
                                noBaseTargets = FALSE;
 
10238
                }
 
10239
        }
 
10240
        else    //don't have enemy base loc
 
10241
        {
 
10242
                //find new base
 
10243
                //temp = findBase(_player);
 
10244
 
 
10245
                if(findBase(_player))   //found new location of the base for this player
 
10246
                {
 
10247
                        curBase[_player][0] = retInt;
 
10248
                        curBase[_player][1] = retInt2;
 
10249
 
 
10250
                        if(curHelpX[_player] <=0)
 
10251
                        {
 
10252
                                curHelpX[_player] = curBase[_player][0];
 
10253
                                curHelpY[_player] = curBase[_player][1];
 
10254
                        }
 
10255
 
 
10256
                        knowBase[_player] = TRUE;
 
10257
                        seeBase[_player] = TRUE;        //found base
 
10258
 
 
10259
                        if(not ally[_player])
 
10260
                        {
 
10261
                                noBaseTargets = FALSE;
 
10262
                        }
 
10263
 
 
10264
                        dbg("found new enemy base for " & getPlayerName(_player) & " at " & (curBase[_player][0] / 128) & " - " & (curBase[_player][1] / 128) & " !!!!!!!!!", me);
 
10265
 
 
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))
 
10268
                        {
 
10269
                                base[_player][0] = retInt;
 
10270
                                base[_player][1] = retInt2;
 
10271
                        }
 
10272
 
 
10273
                        //learn this location
 
10274
                        if(bLearn)
 
10275
                        {
 
10276
                                if(not canRememberPlayerBaseLoc(me, _player))           //not already in memory
 
10277
                                {
 
10278
                                        learnPlayerBaseLoc(me, _player, retInt, retInt2);
 
10279
                                }
 
10280
                        }
 
10281
 
 
10282
                        refreshAllyRadar();
 
10283
                }
 
10284
                //else
 
10285
                //{
 
10286
                //      dead[_player] = TRUE;
 
10287
                //}
 
10288
        }
 
10289
}
 
10290
 
 
10291
function bool checkPlayerDead(int _player)
 
10292
{
 
10293
        if(knowBase[_player] and (not canSeePlayerBase(_player)))               //know location, but don't see it
 
10294
        {
 
10295
                if(mapRevealedInRange(curBase[_player][0],curBase[_player][1], (2 * 128), me))  //make sure can see the location where the base should be
 
10296
                {
 
10297
                        //_temp = canSeePlayer(_player);                //can see any other objects?
 
10298
 
 
10299
                        if(not canSeePlayer(_player))
 
10300
                        {
 
10301
                                return(TRUE);           //dead
 
10302
                        }
 
10303
                }
 
10304
        }
 
10305
 
 
10306
        return(FALSE);
 
10307
}
 
10308
 
 
10309
function bool canSeePlayer(int _player)
 
10310
{
 
10311
        _bResult = FALSE;       //not found
 
10312
 
 
10313
        initEnumStruct(TRUE,wall,_player,me);
 
10314
        _structure = enumStruct();
 
10315
        while((_structure != NULLOBJECT) and (not _bResult))
 
10316
        {
 
10317
                _temp = getStructureType(_structure);
 
10318
                if((_temp != 7) and (_temp != 8) and (_temp != 6) and (_temp != 6))     //wall, cornerwall, defense, rearm
 
10319
                {
 
10320
                        _bResult = TRUE;
 
10321
                }
 
10322
                _structure = enumStruct();
 
10323
        }
 
10324
 
 
10325
        if(not _bResult)        //no structures
 
10326
        {
 
10327
                InitEnumDroids(_player,me);
 
10328
                _droid = EnumDroid();
 
10329
                if(_droid == NULLOBJECT)
 
10330
                {
 
10331
                        return(FALSE);
 
10332
                }
 
10333
        }
 
10334
 
 
10335
        return(TRUE);
 
10336
}
 
10337
 
 
10338
function bool findBase(int _targetPlayer)
 
10339
{
 
10340
        local int _structType;
 
10341
 
 
10342
        ASSERT(_targetPlayer >= 0, "findBase - _targetPlayer < 0", me);
 
10343
 
 
10344
        _structType = 0;
 
10345
        while(_structType < numBaseStructs)
 
10346
        {
 
10347
                tempStruct = getStructureVis(baseStructs[_structType], _targetPlayer, me);
 
10348
                if(tempStruct !=NULLOBJECT)
 
10349
                {
 
10350
                        retInt = tempStruct.x;
 
10351
                        retInt2 = tempStruct.y;
 
10352
                        return(TRUE);
 
10353
                }
 
10354
                _structType = _structType + 1;
 
10355
        }
 
10356
 
 
10357
        return(FALSE);
 
10358
}
 
10359
 
 
10360
function int chooseEnemyToDrop()
 
10361
{
 
10362
        //choose the most annoying one
 
10363
 
 
10364
        temp5 = none;
 
10365
        temp4 = (-1);   //num times attacked by an enemy
 
10366
 
 
10367
        temp = 0;
 
10368
        while(temp < multiPlayerMaxPlayers)
 
10369
        {
 
10370
                if((not allianceExistsBetween(temp, me)) and (temp != me))
 
10371
                {
 
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
 
10373
                        {
 
10374
                                temp2 = numAlliesDroppingPlayer(temp);
 
10375
 
 
10376
                                temp3 = numActiveEnemyDrop(temp);
 
10377
 
 
10378
                                if((temp3 == 0) and (temp2 < maxAllyDroppers))  //not too many and not already dropping
 
10379
                                {
 
10380
                                        if(attacked[temp] > temp4)
 
10381
                                        {
 
10382
                                                temp4 = attacked[temp];
 
10383
                                                temp5 = temp;
 
10384
                                        }
 
10385
                                }
 
10386
                        }
 
10387
                }
 
10388
                temp = temp + 1;
 
10389
        }
 
10390
 
 
10391
        return(temp5);
 
10392
}
 
10393
 
 
10394
function int chooseEnemy()
 
10395
{
 
10396
        local   int             _bestEnemy,_enemy,_tileDist;
 
10397
        local   int             _bestWeight,_tempWeight;
 
10398
        //return - suited enemy to attack
 
10399
 
 
10400
        _bestEnemy = none;
 
10401
        _bestWeight = -99999;
 
10402
 
 
10403
        if(offeredEnemy != none)                //anyone already attacking someone?
 
10404
        {
 
10405
                if((not ally[offeredEnemy]) and (not dead[offeredEnemy]) and (knowBase[offeredEnemy]) and (offeredEnemy != me))
 
10406
                {
 
10407
                        dbg("choosing offered enemy", me);
 
10408
                        _bestEnemy = offeredEnemy;
 
10409
                        offeredEnemy = none;            //don't choose it again after destroying it
 
10410
                }
 
10411
        }
 
10412
 
 
10413
        if(_bestEnemy == none)          //didn't set offeredEnemy as the enemy
 
10414
        {
 
10415
                // now look for bases that were not yet destroyed and which we can see
 
10416
                _enemy = 0;
 
10417
                while(_enemy < multiPlayerMaxPlayers)
 
10418
                {
 
10419
                        if((not ally[_enemy]) and (_enemy != me))
 
10420
                        {
 
10421
                                if(knowBase[_enemy] and (not dead[_enemy]) and
 
10422
                                        (not killedBase[_enemy]) and canSeePlayerBase(_enemy))  //found player's base
 
10423
                                {
 
10424
                                        _tileDist = distBetweenTwoPoints(baseX, baseY, curBase[_enemy][0], curBase[_enemy][1]) / 128;
 
10425
 
 
10426
                                        // Now calculate enemy weight
 
10427
                                        _tempWeight = (int)(W_LOST_UNITS * (float)lostDroids[_enemy] -
 
10428
                                                W_BASE_DISTANCE * (float)_tileDist * TILE_TRAVEL_COST);
 
10429
 
 
10430
                                        if(_tempWeight > _bestWeight)
 
10431
                                        {
 
10432
                                                _bestWeight = _tempWeight;
 
10433
                                                _bestEnemy = _enemy;    //enemy so far
 
10434
                                        }
 
10435
                                }
 
10436
                        }
 
10437
                        _enemy++;
 
10438
                }
 
10439
 
 
10440
                // now also include those bases we can't see
 
10441
                if(_bestEnemy == none)
 
10442
                {
 
10443
                        _enemy = 0;
 
10444
                        while(_enemy < multiPlayerMaxPlayers)
 
10445
                        {
 
10446
                                if((not ally[_enemy]) and (_enemy != me))
 
10447
                                {
 
10448
                                        if(knowBase[_enemy] and (not dead[_enemy]) and
 
10449
                                                (not killedBase[_enemy]))       //found player's base
 
10450
                                        {
 
10451
                                                _tileDist = distBetweenTwoPoints(baseX, baseY, curBase[_enemy][0], curBase[_enemy][1]) / 128;
 
10452
 
 
10453
                                                // Now calculate enemy weight
 
10454
                                                _tempWeight = (int)(W_LOST_UNITS * (float)lostDroids[_enemy] -
 
10455
                                                        W_BASE_DISTANCE * (float)_tileDist * TILE_TRAVEL_COST);
 
10456
 
 
10457
                                                if(_tempWeight > _bestWeight)
 
10458
                                                {
 
10459
                                                        _bestWeight = _tempWeight;
 
10460
                                                        _bestEnemy = _enemy;    //enemy so far
 
10461
                                                }
 
10462
                                        }
 
10463
                                }
 
10464
                                _enemy++;
 
10465
                        }
 
10466
                }
 
10467
 
 
10468
                // now also include those bases that were already destroyed
 
10469
                if(_bestEnemy == none)
 
10470
                {
 
10471
                        _enemy = 0;
 
10472
                        while(_enemy < multiPlayerMaxPlayers)
 
10473
                        {
 
10474
                                if((not ally[_enemy]) and (_enemy != me))
 
10475
                                {
 
10476
                                        //if(knowBase[_enemy] and (not dead[_enemy]))   //found player's base
 
10477
                                        if(knowBase[_enemy])    //found player's base
 
10478
                                        {
 
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;
 
10481
 
 
10482
                                                // Now calculate enemy weight
 
10483
                                                _tempWeight = (int)(W_LOST_UNITS * (float)lostDroids[_enemy] -
 
10484
                                                        W_BASE_DISTANCE * (float)_tileDist * TILE_TRAVEL_COST);
 
10485
 
 
10486
                                                if(_tempWeight > _bestWeight)
 
10487
                                                {
 
10488
                                                        _bestWeight = _tempWeight;
 
10489
                                                        _bestEnemy = _enemy;    //enemy so far
 
10490
                                                }
 
10491
                                        }
 
10492
                                }
 
10493
                                _enemy++;
 
10494
                        }
 
10495
                }
 
10496
        }
 
10497
 
 
10498
        return(_bestEnemy);
 
10499
}
 
10500
 
 
10501
/* function int chooseEnemy()
 
10502
{
 
10503
        local   int             _bestEnemy,_bestDistance,_enemy,_tempDistance;
 
10504
        local   int             _bestWeight;
 
10505
        //return - suited enemy to attack
 
10506
 
 
10507
        _bestDistance = 99999;
 
10508
        _bestEnemy = none;
 
10509
 
 
10510
        if(offeredEnemy != none)                //anyone already attacking someone?
 
10511
        {
 
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))
 
10514
                {
 
10515
                        dbg("choosing offered enemy", me);
 
10516
                        _bestEnemy = offeredEnemy;
 
10517
                        offeredEnemy = none;            //don't choose it again after destroying it
 
10518
                }
 
10519
        }
 
10520
 
 
10521
        if(_bestEnemy == none)          //didn't set offeredEnemy as the enemy
 
10522
        {
 
10523
                // now look for bases that were not yet destroyed and which we can see
 
10524
                _enemy = 0;
 
10525
                while(_enemy < multiPlayerMaxPlayers)
 
10526
                {
 
10527
                        if((not ally[_enemy]) and (_enemy != me))
 
10528
                        {
 
10529
                                if(knowBase[_enemy] and (not dead[_enemy]) and (not killedBase[_enemy]) and seeBase[_enemy])    //found player's base
 
10530
                                {
 
10531
                                        _tempDistance = distBetweenTwoPoints(baseX, baseY, curBase[_enemy][0], curBase[_enemy][1]);
 
10532
                                        if(_tempDistance < _bestDistance)
 
10533
                                        {
 
10534
                                                _bestDistance = _tempDistance;
 
10535
                                                _bestEnemy = _enemy;    //enemy so far
 
10536
                                        }
 
10537
                                }
 
10538
                        }
 
10539
                        _enemy++;
 
10540
                }
 
10541
 
 
10542
                // now also include those bases we can't see
 
10543
                if(_bestEnemy == none)
 
10544
                {
 
10545
                        _enemy = 0;
 
10546
                        while(_enemy < multiPlayerMaxPlayers)
 
10547
                        {
 
10548
                                if((not ally[_enemy]) and (_enemy != me))
 
10549
                                {
 
10550
                                        if(knowBase[_enemy] and (not dead[_enemy]) and (not killedBase[_enemy]))        //found player's base
 
10551
                                        {
 
10552
                                                _tempDistance = distBetweenTwoPoints(baseX, baseY, curBase[_enemy][0], curBase[_enemy][1]);
 
10553
                                                if(_tempDistance < _bestDistance)
 
10554
                                                {
 
10555
                                                        _bestDistance = _tempDistance;
 
10556
                                                        _bestEnemy = _enemy;    //enemy so far
 
10557
                                                }
 
10558
                                        }
 
10559
                                }
 
10560
                                _enemy++;
 
10561
                        }
 
10562
                }
 
10563
 
 
10564
                // now also include those bases that were already destroyed
 
10565
                if(_bestEnemy == none)
 
10566
                {
 
10567
                        _enemy = 0;
 
10568
                        while(_enemy < multiPlayerMaxPlayers)
 
10569
                        {
 
10570
                                if((not ally[_enemy]) and (_enemy != me))
 
10571
                                {
 
10572
                                        //if(knowBase[_enemy] and (not dead[_enemy]))   //found player's base
 
10573
                                        if(knowBase[_enemy])    //found player's base
 
10574
                                        {
 
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)
 
10578
                                                {
 
10579
                                                        _bestDistance = _tempDistance;
 
10580
                                                        _bestEnemy = _enemy;    //enemy so far
 
10581
                                                }
 
10582
                                        }
 
10583
                                }
 
10584
                                _enemy++;
 
10585
                        }
 
10586
                }
 
10587
        }
 
10588
 
 
10589
        return(_bestEnemy);
 
10590
} */
 
10591
 
 
10592
function void checkBaseThreat()
 
10593
{
 
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;
 
10598
 
 
10599
        //if(not bigMap)
 
10600
        //      _range = (29 * 128);
 
10601
 
 
10602
        _range = COUNT_BASE_OBJECTS_RANGE;
 
10603
 
 
10604
        //showRangeAtPos(baseX, baseY, _range);
 
10605
 
 
10606
        /* Check if base is in danger */
 
10607
        // _totalEnemies enemy units and structures
 
10608
        _enemyUnits = 0;
 
10609
        _enemyStructures = 0;
 
10610
 
 
10611
        // don't reset counterenemy if we are defending
 
10612
        if(!defendingBase()) {
 
10613
                _counterEnemy = -1;
 
10614
        }
 
10615
 
 
10616
        _bestEnemyForce = 0;
 
10617
        _attacker = 0;
 
10618
        while(_attacker < MAX_PLAYERS)
 
10619
        {
 
10620
                if((not allianceExistsBetween(_attacker, me)) and (_attacker != me))
 
10621
                {
 
10622
                        _attackerUnitForce = numPlayerWeapDroidsInRange(_attacker, me, baseX, baseY, _range, FALSE);
 
10623
                        _enemyUnits = _enemyUnits + _attackerUnitForce;
 
10624
 
 
10625
                        _attackerStructureForce = numPlayerWeapStructsInRange(_attacker, me, baseX, baseY, _range, true);
 
10626
                        _enemyStructures = _enemyStructures + _attackerStructureForce;
 
10627
 
 
10628
 
 
10629
                        //console(_attacker & " " & _attackerUnitForce & "/" & _attackerStructureForce);
 
10630
 
 
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))
 
10633
                        {
 
10634
                                _bestEnemyForce = _attackerUnitForce + _attackerStructureForce / STR_UNIT_DEFENSE_FACTOR;
 
10635
 
 
10636
                                // don't reset counterenemy if we are defending
 
10637
                                if(!defendingBase()) {
 
10638
                                        _counterEnemy = _attacker;
 
10639
                                }
 
10640
                        }
 
10641
                }
 
10642
                _attacker++;
 
10643
        }
 
10644
        _enemyStructures = _enemyStructures / STR_UNIT_DEFENSE_FACTOR;
 
10645
 
 
10646
        //_enemyUnits = numEnemyWeapDroidsInRange(me, baseX, baseY, _range, FALSE);
 
10647
        //_enemyStructures = numEnemyWeapStructsInRange(me, baseX, baseY, _range) / 3;
 
10648
 
 
10649
        _allyUnits = numFriendlyWeapDroidsInRange(me, baseX, baseY, _range, FALSE);
 
10650
        _allyStructures = numFriendlyWeapStructsInRange(me, baseX, baseY, _range, true) / STR_UNIT_DEFENSE_FACTOR;
 
10651
 
 
10652
        _totalEnemies = _enemyUnits + _enemyStructures; //total enemies
 
10653
        _totalAllies = _allyUnits + _allyStructures;    //total allies
 
10654
 
 
10655
        if(_enemyUnits > 0)
 
10656
                dbg("Num enemies = " & _enemyUnits & "/" & _enemyStructures & " (" & _allyUnits & "/" & _allyStructures & ") - " & (_range / TILE), me);
 
10657
 
 
10658
        /* pre-warn allies (only units _totalEnemies) */
 
10659
        if(_enemyUnits >= 7)
 
10660
        {
 
10661
                if(!defendingBase())    //do only once/attack
 
10662
                {
 
10663
                        if(timeNotifyEnemyInBase <= 0)
 
10664
                        {
 
10665
                                notifyEnemyAtBase();
 
10666
 
 
10667
                                attackedCount++;        //remember how many times we were attacked
 
10668
                        }
 
10669
                }
 
10670
        }
 
10671
 
 
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)
 
10675
        {
 
10676
                if(gameTime > 2800)
 
10677
                {
 
10678
                        dbg("BASE: too many enemies in the base             !!!!!!", me);
 
10679
 
 
10680
                        if(!defendingBase())
 
10681
                        {
 
10682
                                if(state != stNone)
 
10683
                                {
 
10684
                                        cancelState();
 
10685
                                }
 
10686
 
 
10687
                                //TODO: with _attacker = playerDominanceInArea() find out if attacker's base is closer than our own base
 
10688
                                //and attack enemy base instead
 
10689
 
 
10690
                                taunt(_counterEnemy, TAUNT_BASE_DEFENSE, 50);
 
10691
 
 
10692
                                startDefending(_counterEnemy);
 
10693
                                requestHelp(baseX, baseY);
 
10694
                        }
 
10695
                }
 
10696
 
 
10697
        }
 
10698
        /* check if can stop defending */
 
10699
        else if(defendingBase() and (_enemyUnits == 0))         //all enemies are gone
 
10700
        {
 
10701
                if(groupSizeCmds(defendGr,true,false,true) >= minDefenders)             //make sure can defend on our own
 
10702
                {
 
10703
                        dbg("base is safe again", me);
 
10704
 
 
10705
                        _counterEnemy = counterEnemy;
 
10706
                        stopDefendingBase();
 
10707
 
 
10708
                        taunt(_counterEnemy, TAUNT_BASE_OK, 55);
 
10709
 
 
10710
                        notifyAllies("i'm ok", FALSE);          //tell allies we are ok now
 
10711
 
 
10712
                        /* See if we can counterattack */
 
10713
                        if((state == stNone) and (_counterEnemy != none))
 
10714
                        {
 
10715
                                if(not allianceExistsBetween(_counterEnemy, me))
 
10716
                                {
 
10717
                                        if(totalWeapUnits() >= MIN_COUNTERATTACKERS)
 
10718
                                        {
 
10719
                                                if(knowBase[_counterEnemy])
 
10720
                                                {
 
10721
                                                        _enemyX = curBase[_counterEnemy][0];
 
10722
                                                        _enemyY = curBase[_counterEnemy][1];
 
10723
                                                        _range = (20 * TILE);
 
10724
 
 
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;
 
10728
 
 
10729
                                                        if(totalWeapUnits() > _counterEnemyForce)
 
10730
                                                        {
 
10731
                                                                dbg("counterattacking", me);
 
10732
                                                                startEnemyBaseAttack(_counterEnemy);
 
10733
                                                                requestStartAttack(_counterEnemy, _enemyX, _enemyY);
 
10734
                                                        }
 
10735
                                                        else{
 
10736
                                                                dbg("counterattack: too dangerous: " & totalWeapUnits() & "/" & _counterEnemyForce, me);
 
10737
                                                        }
 
10738
                                                }
 
10739
                                                else{
 
10740
                                                        dbg("counterattack: don't have base of " & _counterEnemy, me);
 
10741
                                                }
 
10742
                                        }
 
10743
                                        else{
 
10744
                                                dbg("counterattack: not enough attackers " & totalWeapUnits(), me);
 
10745
                                        }
 
10746
                                }
 
10747
                                else{
 
10748
                                        dbg("counterattack: counterEnemy is ally: " & _counterEnemy, me);
 
10749
                                }
 
10750
                        }
 
10751
                        else{
 
10752
                                dbg("counterattack: busy: " & state & " : " & _counterEnemy, me);
 
10753
                        }
 
10754
 
 
10755
                }
 
10756
        }
 
10757
}
 
10758
 
 
10759
function bool canRequestHelp()
 
10760
{
 
10761
        if(requestHelpTime <= 0)
 
10762
        {
 
10763
                return true;
 
10764
        }
 
10765
        
 
10766
        return false;
 
10767
}
 
10768
 
 
10769
function void requestHelp(int _x, int _y)
 
10770
{
 
10771
        _temp = 0;
 
10772
        while(_temp < multiPlayerMaxPlayers)
 
10773
        {
 
10774
                if(allianceExistsBetween(me , _temp))
 
10775
                {
 
10776
                        giftRadar(me, _temp, FALSE);
 
10777
                        dropBeacon("help", _temp, me, _x, _y, 0);
 
10778
                        msg("help", me, _temp);
 
10779
                }
 
10780
                _temp = _temp + 1;
 
10781
        }
 
10782
 
 
10783
        requestHelpTime = maxRequestHelpTime;
 
10784
}
 
10785
 
 
10786
/* Request status from allies */
 
10787
function void checkRequestStatus()
 
10788
{
 
10789
        _temp = 0;
 
10790
        while(_temp < multiPlayerMaxPlayers)
 
10791
        {
 
10792
                if(allianceExistsBetween(me , _temp) and (tRequestStatus[_temp] <= 0))
 
10793
                {
 
10794
                        requestStatus(_temp);
 
10795
                }
 
10796
                _temp = _temp + 1;
 
10797
        }
 
10798
}
 
10799
 
 
10800
function void requestStatus(int _player)
 
10801
{
 
10802
        msg("status?" ,me ,  _player);
 
10803
 
 
10804
        tRequestStatus[ _player] = tMaxRequestStatus + random(700);
 
10805
}
 
10806
 
 
10807
function void requestEnemy(int _toAskPlayer)
 
10808
{
 
10809
        msg("who's your target?" ,me , _toAskPlayer);
 
10810
 
 
10811
        tWaitPlayerReply[_toAskPlayer] = tMaxWaitPlayerReply;   //start timer
 
10812
}
 
10813
 
 
10814
 
 
10815
function void notifyPlayerDead(int deadPlayer)
 
10816
{
 
10817
        exit;
 
10818
 
 
10819
        _temp = 0;
 
10820
        while(_temp < multiPlayerMaxPlayers)
 
10821
        {
 
10822
                if(allianceExistsBetween(me , _temp))
 
10823
                {
 
10824
                        if(deadPlayer == me)
 
10825
                        {
 
10826
                                msg("ok, i'm dead, cya" ,me , _temp);
 
10827
                        }
 
10828
                        else
 
10829
                        {
 
10830
                                msg(getPlayerName(deadPlayer) & " is dead" ,me , _temp);
 
10831
                        }
 
10832
                }
 
10833
                _temp = _temp + 1;
 
10834
        }
 
10835
}
 
10836
 
 
10837
function void notifyPlayerAlive(int _alivePlayer)
 
10838
{
 
10839
        exit;
 
10840
 
 
10841
        if(gameTime < 200)
 
10842
                exit;   //engine bugs at startup
 
10843
 
 
10844
        _temp = 0;
 
10845
        while(_temp < multiPlayerMaxPlayers)
 
10846
        {
 
10847
                if(allianceExistsBetween(me , _temp))
 
10848
                {
 
10849
                        msg(getPlayerName(_alivePlayer) & " is alive" ,me , _temp);
 
10850
                }
 
10851
                _temp = _temp + 1;
 
10852
        }
 
10853
}
 
10854
 
 
10855
function void notifyPlayerBaseDestroyed(int _destroyedPlayer)
 
10856
{
 
10857
        notifyAllies("destroyed " & getPlayerName(_destroyedPlayer) & "'s base", FALSE);
 
10858
}
 
10859
 
 
10860
function void notifyLost()
 
10861
{
 
10862
        _temp = 0;
 
10863
        while(_temp < multiPlayerMaxPlayers)
 
10864
        {
 
10865
                if(allianceExistsBetween(me , _temp))
 
10866
                {
 
10867
                        msg("cya" ,me , _temp);
 
10868
                }
 
10869
                _temp = _temp + 1;
 
10870
        }
 
10871
}
 
10872
 
 
10873
/* Notify we are idle, if failed to take over enemy derrick or if attack failed */
 
10874
function void notifyIdle(bool bAfterFailure)
 
10875
{
 
10876
        if(bAfterFailure)
 
10877
        {
 
10878
                notifyAllies("building more units", false);             //make sure allies are aware of our current state
 
10879
        }
 
10880
        else
 
10881
        {
 
10882
                dice = random(10);
 
10883
                if(dice > 5){
 
10884
                        notifyAllies("getting units", false);
 
10885
                }else{
 
10886
                        notifyAllies("building an army", false);
 
10887
                }
 
10888
        }
 
10889
}
 
10890
 
 
10891
function void taunt(int targetPlayer, int type, int tauntProbability)
 
10892
{
 
10893
        local   string          sTarget,sPlayer;
 
10894
 
 
10895
        if(random(100) >= tauntProbability)
 
10896
        {
 
10897
                return;
 
10898
        }
 
10899
 
 
10900
        // see if we are refering to some player
 
10901
        if(targetPlayer != NONE)
 
10902
        {
 
10903
                sPlayer = getPlayerName(targetPlayer);
 
10904
                sTarget = getPlayerName(targetPlayer) &  ", ";
 
10905
        }
 
10906
 
 
10907
        dice = random(10);
 
10908
 
 
10909
        if(type == TAUNT_SUCCESS)
 
10910
        {
 
10911
                if(dice < 3)
 
10912
                {
 
10913
                        notifyAll(sTarget & "you suck.");
 
10914
                }
 
10915
                else if(dice < 7)
 
10916
                {
 
10917
                        notifyAll("too easy");
 
10918
                }
 
10919
                else
 
10920
                {
 
10921
                        notifyAll("I get what I want");
 
10922
                }
 
10923
        }
 
10924
        else if(type == TAUNT_FAILURE)  // state failed
 
10925
        {
 
10926
                if(dice < 5){
 
10927
                        notifyAll(sTarget & "screw you!!");
 
10928
                }else{
 
10929
                        notifyAll(sTarget & "stop turtling");
 
10930
                }
 
10931
        }
 
10932
        else if(type == TAUNT_POSSESSION_LOSS)          // lost a derrick etc
 
10933
        {
 
10934
                if(dice < 5){
 
10935
                        notifyAll(sTarget & "I didn't need it anyway");
 
10936
                }else if(dice < 8){
 
10937
                        notifyAll(sTarget & "next time i'll kick your ass!");
 
10938
                }else{
 
10939
                        notifyAll(sTarget & "i'll get it back");
 
10940
                }
 
10941
        }
 
10942
        else if(type == TAUNT_GAME_LOSS)
 
10943
        {
 
10944
                if(dice < 6){
 
10945
                        notifyAll("gg");
 
10946
                }else if(dice < 8){
 
10947
                        notifyAll("rematch?");
 
10948
                }else if(dice < 9){
 
10949
                        notifyAll("I can do better");
 
10950
                }else{
 
10951
                        notifyAll("it's not my day..");
 
10952
                }
 
10953
        }
 
10954
        else if(type == TAUNT_BASE_DEFENSE)
 
10955
        {
 
10956
                if(dice < 7){
 
10957
                        notifyAll(sTarget & "bring it on!");
 
10958
                }else{
 
10959
                        notifyAll(sTarget & "I've been waiting for you");
 
10960
                }
 
10961
        }
 
10962
        else if(type == TAUNT_BASE_OK)
 
10963
        {
 
10964
                if(dice < 4){
 
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?");
 
10972
                }else{
 
10973
                        notifyAll(sTarget & "is that all you got?");
 
10974
                }
 
10975
        }
 
10976
        else if(type == TAUNT_REDISCOVERED_BASE)
 
10977
        {
 
10978
                if(dice < 4){
 
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?");
 
10986
                }else{
 
10987
                        notifyAll(sTarget & "you can run but you can't hide");
 
10988
                }
 
10989
        }
 
10990
        else if(type == TAUNT_LOST_BASE)
 
10991
        {
 
10992
                if(dice < 4){
 
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");
 
10998
                }else{
 
10999
                        notifyAll("like a knife through butter");
 
11000
                }
 
11001
        }
 
11002
}
 
11003
 
 
11004
function void notifyReadyAttack()
 
11005
{
 
11006
        dice = random(10);
 
11007
 
 
11008
        if(dice > 5){
 
11009
                notifyAllies("go?", FALSE);
 
11010
        }else if(dice == 0){
 
11011
                notifyAllies("ready", FALSE);
 
11012
        }else{
 
11013
                notifyAllies("I'm ready", FALSE);
 
11014
        }
 
11015
 
 
11016
        notifyReadyAttackTime = maxNotifyReadyAttackTime;
 
11017
 
 
11018
        bNotifiedReadyAttack = FALSE;   //remember not notified yet
 
11019
 
 
11020
        dbg("ATTACK: allies notified", me);
 
11021
}
 
11022
 
 
11023
function void notifyReadyToDrop()
 
11024
{
 
11025
        _temp = 0;
 
11026
        while(_temp < multiPlayerMaxPlayers)
 
11027
        {
 
11028
                if(allianceExistsBetween(me , _temp))
 
11029
                {
 
11030
                        //if(allyEnemy[_temp] == enemy)         //only if he's attacking the same enemy
 
11031
                        //{
 
11032
                                msg("ready to drop" ,me , _temp);
 
11033
                        //}
 
11034
                }
 
11035
                _temp = _temp + 1;
 
11036
        }
 
11037
 
 
11038
        dbg("ATTACK: allies notified of drop", me);
 
11039
}
 
11040
 
 
11041
function void refreshAllyRadar()
 
11042
{
 
11043
        _temp = 0;
 
11044
        while(_temp < multiPlayerMaxPlayers)
 
11045
        {
 
11046
                if(allianceExistsBetween(me , _temp))
 
11047
                {
 
11048
                        giftRadar(me, _temp, FALSE);
 
11049
                }
 
11050
                _temp = _temp + 1;
 
11051
        }
 
11052
}
 
11053
 
 
11054
// one function for all notifications
 
11055
function void notifyAllies(STRING _cstr, bool _bUpdateRadar)
 
11056
{
 
11057
        local int i;
 
11058
 
 
11059
        i = 0;
 
11060
        while(i < multiPlayerMaxPlayers)
 
11061
        {
 
11062
                if(allianceExistsBetween(me, i))
 
11063
                {
 
11064
                        if(_bUpdateRadar)
 
11065
                        {
 
11066
                                giftRadar(me, i, FALSE);
 
11067
                        }
 
11068
                        msg(_cstr, me, i);
 
11069
                }
 
11070
                i = i + 1;
 
11071
        }
 
11072
}
 
11073
 
 
11074
/* Send a message to all players */
 
11075
function void notifyAll(STRING _cstr)
 
11076
{
 
11077
        local int player;
 
11078
 
 
11079
        player = 0;
 
11080
        while(player < multiPlayerMaxPlayers)
 
11081
        {
 
11082
                msg(_cstr, me, player);
 
11083
                player++;
 
11084
        }
 
11085
}
 
11086
 
 
11087
function void notifyTakeOil(int _enemy, int _x, int _y)
 
11088
{
 
11089
        dropAllyBeacon("gonna get " & getPlayerName(_enemy) & "'s derrick", _x, _y);
 
11090
        notifyAllies("gonna get " & getPlayerName(_enemy) & "'s derrick", TRUE);
 
11091
}
 
11092
 
 
11093
function void dropAllyBeacon(STRING _cstr, int _x, int _y)
 
11094
{
 
11095
        local int i;
 
11096
 
 
11097
        // for me
 
11098
        dropBeacon(_cstr, me, me, _x, _y, 0);
 
11099
 
 
11100
        i = 0;
 
11101
        while(i < multiPlayerMaxPlayers)
 
11102
        {
 
11103
                if((allianceExistsBetween(me, i)) and (i != me))
 
11104
                {
 
11105
                        dropBeacon(_cstr, i, me, _x, _y, 0);
 
11106
                }
 
11107
                i = i + 1;
 
11108
        }
 
11109
}
 
11110
 
 
11111
function void requestPrepareDrop()
 
11112
{
 
11113
        if(enemy == none){MsgBox("requestPrepareDrop() - enemy == none"); exit;}
 
11114
 
 
11115
        _temp = 0;
 
11116
        while(_temp < multiPlayerMaxPlayers)
 
11117
        {
 
11118
                if(allianceExistsBetween(me , _temp))
 
11119
                {
 
11120
                        giftRadar(me, _temp, FALSE);
 
11121
                        msg("drop " & enemy, me , _temp);
 
11122
                }
 
11123
                _temp = _temp + 1;
 
11124
        }
 
11125
}
 
11126
 
 
11127
function void notifyPrepareDrop()
 
11128
{
 
11129
        if(enemy == none){MsgBox("notifyPrepareDrop() - enemy == none"); exit;}
 
11130
 
 
11131
        _temp = 0;
 
11132
        while(_temp < multiPlayerMaxPlayers)
 
11133
        {
 
11134
                if(allianceExistsBetween(me , _temp))
 
11135
                {
 
11136
                        giftRadar(me, _temp, FALSE);
 
11137
                        msg("dropping " & enemy, me , _temp);
 
11138
                        msg("preparing drop", me , _temp);
 
11139
                }
 
11140
                _temp = _temp + 1;
 
11141
        }
 
11142
}
 
11143
 
 
11144
function void notifyStartDrop()
 
11145
{
 
11146
        _temp = 0;
 
11147
        while(_temp < multiPlayerMaxPlayers)
 
11148
        {
 
11149
                if(allianceExistsBetween(me , _temp))
 
11150
                {
 
11151
                        msg("transporting units", me , _temp);
 
11152
                }
 
11153
                _temp = _temp + 1;
 
11154
        }
 
11155
}
 
11156
 
 
11157
function void notifyCantDrop()
 
11158
{
 
11159
        _temp = 0;
 
11160
        while(_temp < multiPlayerMaxPlayers)
 
11161
        {
 
11162
                if(allianceExistsBetween(me , _temp))
 
11163
                {
 
11164
                        if(allyEnemy[_temp] == enemy)
 
11165
                        {
 
11166
                                msg("can't drop", me , _temp);
 
11167
                        }
 
11168
                }
 
11169
                _temp = _temp + 1;
 
11170
        }
 
11171
}
 
11172
 
 
11173
function void notifyLoadedTransporters()
 
11174
{
 
11175
        _temp = 0;
 
11176
        while(_temp < multiPlayerMaxPlayers)
 
11177
        {
 
11178
                if(allianceExistsBetween(me , _temp))
 
11179
                {
 
11180
                        if(allyEnemy[_temp] == enemy)
 
11181
                        {
 
11182
                                msg("loaded transporters", me , _temp);
 
11183
                        }
 
11184
                }
 
11185
                _temp = _temp + 1;
 
11186
        }
 
11187
}
 
11188
 
 
11189
function void requestStartAttack(int _enemy, int _x, int _y)
 
11190
{
 
11191
        if(_enemy == none){MsgBox("requestStartAttack() - _enemy == none"); exit;}
 
11192
 
 
11193
        _temp = 0;
 
11194
        while(_temp < multiPlayerMaxPlayers)
 
11195
        {
 
11196
                if(allianceExistsBetween(me , _temp))
 
11197
                {
 
11198
                        giftRadar(me, _temp, FALSE);
 
11199
                        msg("go " & getPlayerName(_enemy), me , _temp);
 
11200
                        //dropBeacon("go " & getPlayerName(_enemy), _temp, me, _x, _y, 0);
 
11201
                }
 
11202
                _temp = _temp + 1;
 
11203
        }
 
11204
 
 
11205
        dropAllyBeacon("go " & getPlayerName(_enemy), _x, _y);
 
11206
}
 
11207
 
 
11208
function void notifyPlayerHasVTOLs(int _playerWithVTOLs)
 
11209
{
 
11210
        notifyAllies(getPlayerName(_playerWithVTOLs) & " got vtols", FALSE);
 
11211
}
 
11212
 
 
11213
function void notifyStatusAll()
 
11214
{
 
11215
        local int i;
 
11216
 
 
11217
        i = 0;
 
11218
        while(i < multiPlayerMaxPlayers)
 
11219
        {
 
11220
                if(allianceExistsBetween(me , i))
 
11221
                {
 
11222
                        notifyStatus(i);
 
11223
                }
 
11224
                i = i + 1;
 
11225
        }
 
11226
}
 
11227
 
 
11228
function void notifyStatus(int _playerToNotify)
 
11229
{
 
11230
        if(state == stDefendingBase)
 
11231
        {
 
11232
                notifyAllies(getPlayerName(_playerToNotify) & ": help" , false);
 
11233
        }
 
11234
        if(defendingOil())
 
11235
        {
 
11236
                notifyAllies(getPlayerName(_playerToNotify) & ": defending oil" , false);
 
11237
                dropAllyBeacon("defending oil", sendForceX, sendForceY);
 
11238
        }
 
11239
        else if(state == stAttacking)
 
11240
        {
 
11241
                notifyAllies(getPlayerName(_playerToNotify) & ": attacking " & getPlayerName(enemy), false);
 
11242
        }
 
11243
        else if(state == stHelpingAlly)
 
11244
        {
 
11245
                notifyAllies(getPlayerName(_playerToNotify) & ": helping " & getPlayerName(enemy), false);
 
11246
        }
 
11247
        else if(state == stTakingOil)
 
11248
        {
 
11249
                notifyAllies(getPlayerName(_playerToNotify) & ": hunting " & getPlayerName(enemy) & "'s oil" , false);
 
11250
                dropAllyBeacon("hunting " & getPlayerName(enemy) & "'s oil", sendForceX, sendForceY);
 
11251
        }
 
11252
        else if(((state == stDrop) or (state == stTransporting)) and (enemy != none))
 
11253
        {
 
11254
                notifyAllies(getPlayerName(_playerToNotify) & ": dropping " & getPlayerName(enemy), false);
 
11255
 
 
11256
                if(phase <= phGettingUnits)
 
11257
                {
 
11258
                        notifyAllies(getPlayerName(_playerToNotify) & ": preparing drop", false);
 
11259
                }
 
11260
                else if(phase == phWaitAllies)
 
11261
                {
 
11262
                        notifyAllies(getPlayerName(_playerToNotify) & ": ready to drop", false);
 
11263
                }
 
11264
                else if(phase == phLoadingTransport)
 
11265
                {
 
11266
                        notifyAllies(getPlayerName(_playerToNotify) & ": loading transport", false);
 
11267
                }
 
11268
                else if(phase == phSendDrop)
 
11269
                {
 
11270
                        notifyAllies(getPlayerName(_playerToNotify) & ": transporting units", false);
 
11271
                }
 
11272
        }
 
11273
}
 
11274
 
 
11275
function void notifyPower(int _targetPlayer)
 
11276
{
 
11277
        if(playerPower(me) <= noPower)
 
11278
        {
 
11279
                msg("nope", me , _targetPlayer);
 
11280
        }
 
11281
        else if(playerPower(me) <= lowPower)
 
11282
        {
 
11283
                msg("not much", me , _targetPlayer);
 
11284
        }
 
11285
        else    //high power
 
11286
        {
 
11287
                msg("yeah", me , _targetPlayer);
 
11288
        }
 
11289
}
 
11290
 
 
11291
function void notifyEnemyAtBase()
 
11292
{
 
11293
        _temp = 0;
 
11294
        while(_temp < multiPlayerMaxPlayers)
 
11295
        {
 
11296
                if(ally[_temp])
 
11297
                {
 
11298
                        if(attackedCount == 0)          //first time
 
11299
                        {
 
11300
                                _temp2 = random(3);     //100%
 
11301
                                if(_temp2 == 0)
 
11302
                                {
 
11303
                                        msg("oh no, here we go..." ,me , _temp);
 
11304
                                }
 
11305
                                else if(_temp2 == 1)
 
11306
                                {
 
11307
                                        msg("it started" ,me , _temp);
 
11308
                                }
 
11309
                                else if(_temp2 == 2)
 
11310
                                {
 
11311
                                        msg("they are at my base" ,me , _temp);
 
11312
                                }
 
11313
                        }
 
11314
                        else if((attackedCount > 0) and (attackedCount < 4))
 
11315
                        {
 
11316
                                _temp2 = random(5);
 
11317
                                if(_temp2 == 0)
 
11318
                                {
 
11319
                                        msg("not again..." ,me , _temp);
 
11320
                                }
 
11321
                                else if(_temp2 == 1)
 
11322
                                {
 
11323
                                        msg("they're after my base" ,me , _temp);
 
11324
                                }
 
11325
                                else if(_temp2 == 2)
 
11326
                                {
 
11327
                                        msg("incoming" ,me , _temp);
 
11328
                                }
 
11329
                        }
 
11330
                        else if((attackedCount >= 4) and (attackedCount < 10))
 
11331
                        {
 
11332
                                _temp2 = random(6);
 
11333
                                if(_temp2 == 0)
 
11334
                                {
 
11335
                                        msg("this is getting annoying..." ,me , _temp);
 
11336
                                }
 
11337
                                else if(_temp2 == 1)
 
11338
                                {
 
11339
                                        msg("this sucks!" ,me , _temp);
 
11340
                                }
 
11341
                                else if(_temp2 == 2)
 
11342
                                {
 
11343
                                        msg("duh..." ,me , _temp);
 
11344
                                }
 
11345
                                else if(_temp2 == 3)
 
11346
                                {
 
11347
                                        msg("thery're after my base again" ,me , _temp);
 
11348
                                }
 
11349
                        }
 
11350
                        else
 
11351
                        {
 
11352
                                _temp2 = random(8);
 
11353
                                if(_temp2 == 0)
 
11354
                                {
 
11355
                                        msg("why is it always my base???" ,me , _temp);
 
11356
                                }
 
11357
                                else if(_temp2 == 1)
 
11358
                                {
 
11359
                                        msg("this sucks..." ,me , _temp);
 
11360
                                }
 
11361
                                else if(_temp2 == 2)
 
11362
                                {
 
11363
                                        msg("duh..." ,me , _temp);
 
11364
                                }
 
11365
                                else if(_temp2 == 3)
 
11366
                                {
 
11367
                                        msg("sooner or later they're gonna get me" ,me , _temp);
 
11368
                                }
 
11369
                                else if(_temp2 == 4)
 
11370
                                {
 
11371
                                        msg("today is not my day..." ,me , _temp);
 
11372
                                }
 
11373
                                else if((_temp2 == 5) or (_temp2 == 6))
 
11374
                                {
 
11375
                                        msg("they already attacked me " & attackedCount & " times!!! ... yes, I count!" ,me , _temp);
 
11376
                                }
 
11377
 
 
11378
                        }
 
11379
                }
 
11380
                _temp = _temp + 1;
 
11381
        }
 
11382
 
 
11383
        timeNotifyEnemyInBase = maxTimeNotifyEnemyInBase;
 
11384
}
 
11385
 
 
11386
event defendBase(inactive)
 
11387
{
 
11388
        local   int             _cmdIndex,_edgeX,_edgeY,_numAttacked,_x,_y,_bucket;
 
11389
 
 
11390
        // if attacking en enemy, check if it's still safe to do so otherwise retreat
 
11391
        /* if(baseDefendObj != NULLOBJECT)
 
11392
        {
 
11393
                if(numEnemyWeapObjInRange(me, baseDefendObj.x, baseDefendObj.y, (6 * 128), false, true) >=
 
11394
                        (groupSizeCmds(defendGr,true,false,true) - 1))
 
11395
                {
 
11396
                        //dbg("NOT SAFE TO FOLLOW ATTACKER ANYMORE", me);
 
11397
 
 
11398
                        //calc perim coords
 
11399
                        x = baseDefendObj.x;
 
11400
                        y = baseDefendObj.y;
 
11401
 
 
11402
                        circlePerimPoint(baseX, baseY, ref x, ref y, (baseRange + defendCorridor / 2)); //move defense locations to the base perimeter
 
11403
 
 
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)
 
11408
                        {
 
11409
                                if((droid.target != NULLOBJECT) and (droid.target == baseDefendObj))
 
11410
                                {
 
11411
                                        orderDroidLoc(droid, DORDER_MOVE, x, y);                //don't SCOUT
 
11412
                                }
 
11413
                                droid = iterateGroupCmd(defendGr,_bucket);
 
11414
                        }
 
11415
 
 
11416
                }
 
11417
        } */
 
11418
 
 
11419
        /* Attack any base intruders */
 
11420
        defendArea(defendGr, baseRange, baseX, baseY, defendCorridor, minDefenders);
 
11421
 
 
11422
        /* Make newly built droids leave the center of the base */
 
11423
        _edgeX = defendX;
 
11424
        _edgeY = defendY;
 
11425
 
 
11426
        // we were not attacked during this game so far, recall a location from past experience
 
11427
        if(_edgeX <= 0)
 
11428
        {
 
11429
                if(getBaseDefendLocCount() > 0)         //any locations stored?
 
11430
                {
 
11431
                        // highest priority location is always at the top
 
11432
                        if(recallBaseDefendLoc(me, 0, ref _x, ref _y, ref _numAttacked))
 
11433
                        {
 
11434
                                // did we really get attacked at this location?
 
11435
                                if(_numAttacked > 0 and _x > 0 and _y > 0)
 
11436
                                {
 
11437
                                        // make defenders go to this location when they get built
 
11438
                                        _edgeX = _x;
 
11439
                                        _edgeY = _y;
 
11440
                                }
 
11441
                        }
 
11442
                }
 
11443
        }
 
11444
 
 
11445
        // now move defenders to this location
 
11446
        if(_edgeX > 0 and _edgeY > 0){
 
11447
                cleanBaseCenter(defendGr, baseRange, baseX, baseY, _edgeX, _edgeY, defendCorridor);
 
11448
        }
 
11449
}
 
11450
 
 
11451
function void cleanBaseCenter(GROUP _group, int _range, int _defendX, int _defendY,
 
11452
                                                                int _edgeX, int _edgeY, int _defendCorridor)
 
11453
{
 
11454
        local   DROID   _droid;
 
11455
        local   int     _bucket;
 
11456
 
 
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)
 
11461
        {
 
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
 
11463
                {
 
11464
                        if( !droidActionAttacking(_droid) )     //retreat even if busy but not directly attacking
 
11465
                        {
 
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
 
11471
                                {
 
11472
                                        // move to base perimeter, just before base defenses
 
11473
                                        goToPerim(_defendX, _defendY, _edgeX, _edgeY,
 
11474
                                                (_range + _defendCorridor / 2 - 128), DORDER_MOVE, _droid);
 
11475
                                }
 
11476
                        }
 
11477
                }
 
11478
                _droid = iterateGroupCmd(_group,_bucket);
 
11479
        }
 
11480
 
 
11481
}
 
11482
 
 
11483
function void defendArea(GROUP _defendGr, int _range, int _defendX, int _defendY, int _defendCorridor, int _minDefenders)
 
11484
{
 
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;
 
11490
 
 
11491
        if(groupSizeCmds(_defendGr,true,false,true) == 0)       //TODO: commanders must retreat
 
11492
        {
 
11493
                exit;
 
11494
        }
 
11495
 
 
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
 
11501
 
 
11502
        /* Check if have to defend anything */
 
11503
 
 
11504
        //look at all visible objects close to base
 
11505
        _target = getClosestEnemy(_defendX, _defendY,  _range + _defendCorridor + _reactToEnemyCorridor, FALSE, FALSE, me);
 
11506
        if(_target != NULLOBJECT)
 
11507
        {
 
11508
                //result = isInMyBase(obj.x, obj.y);            //check in base
 
11509
 
 
11510
                //if(distBetweenTwoPoints(_target.x, _target.y, _defendX, _defendY) <= _range)          //within defend location
 
11511
                //{
 
11512
                        _bHaveTarget = TRUE;
 
11513
                        _targetX = _target.x;
 
11514
                        _targetY = _target.y;
 
11515
                //}
 
11516
        }
 
11517
 
 
11518
        //attack
 
11519
        if(_bHaveTarget)        //found target
 
11520
        {
 
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))
 
11525
                {
 
11526
                        _bEnemyInBase = TRUE;
 
11527
 
 
11528
                        //calc perim coords
 
11529
                        _tempX = _targetX;
 
11530
                        _tempY = _targetY;
 
11531
                        circlePerimPoint(_defendX, _defendY, ref _tempX, ref _tempY, (_range + _defendCorridor / 2));   //move defense locations to the base perimeter
 
11532
 
 
11533
                        /* If for base defenders, then remember defend location for newly built units */
 
11534
                        if(_defendGr == defendGr)
 
11535
                        {
 
11536
                                defendX = _tempX;
 
11537
                                defendY = _tempY;
 
11538
                        }
 
11539
                }
 
11540
 
 
11541
                _result = numFriendlyWeapObjInRange(me, _targetX, _targetY, (10 * 128), false, true);
 
11542
                _result2 = numEnemyWeapObjInRange(me, _targetX, _targetY, (10 * 128), false, true);
 
11543
 
 
11544
                if((groupSizeCmds(_defendGr,true,false,true) >= _minDefenders) or (_result >= _result2))        //don't send one by one or if dangerous
 
11545
                {
 
11546
                        _bucket = initIterateGroupCmd(_defendGr,true,true,true);
 
11547
                        _droid = iterateGroupCmd(_defendGr,_bucket);
 
11548
                        while(_droid != NULLOBJECT)
 
11549
                        {
 
11550
                                _order = DORDER_SCOUT;          //default defend order
 
11551
 
 
11552
                                /* if unit already going to defend loc, check if there's actually an enemy left at that loc */
 
11553
                                _bHaveCloserEnemy = FALSE;
 
11554
 
 
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))
 
11557
                                {
 
11558
                                        _bHaveCloserEnemy = TRUE;
 
11559
                                }
 
11560
 
 
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
 
11563
                                {
 
11564
                                        if(_droid.orderx > 0)
 
11565
                                        {
 
11566
                                                _dist = distBetweenTwoPoints(_defendX, _defendY, _droid.orderx, _droid.ordery) - distBetweenTwoPoints(_defendX, _defendY, _targetX, _targetY);
 
11567
                                                if(_dist > _moveCloserThreshold)                //if much closer
 
11568
                                                {
 
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);
 
11572
                                                }
 
11573
                                        }
 
11574
                                }
 
11575
 
 
11576
                                //nothing or returning to base
 
11577
                                if(droidOrderIdle(_droid) or (_droid.order == DORDER_MOVE) or _bHaveCloserEnemy)
 
11578
                                {
 
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))
 
11581
                                        {
 
11582
                                                orderDroidLoc(_droid, _order, _targetX, _targetY);
 
11583
                                        }
 
11584
                                }
 
11585
 
 
11586
                                _droid = iterateGroupCmd(_defendGr,_bucket);
 
11587
                        }
 
11588
                }
 
11589
        }
 
11590
 
 
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)
 
11595
        {
 
11596
                if( (distBetweenTwoPoints(_droid.x, _droid.y, _defendX, _defendY) >
 
11597
                        (_range + _defendCorridor)))//too far from base
 
11598
                {
 
11599
                        if( _droid.order != DORDER_ATTACK )     //retreat even if busy but not directly attacking
 
11600
                        {
 
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
 
11607
                                {
 
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);
 
11611
 
 
11612
                                }
 
11613
                        }
 
11614
                }
 
11615
                _droid = iterateGroupCmd(_defendGr,_bucket);
 
11616
        }
 
11617
 
 
11618
        //dbg(" " & me & ")  END defendBase");
 
11619
}
 
11620
 
 
11621
function void goToPerim(int _centerX, int _centerY, int _fromX,
 
11622
                                                int _fromY, int _perimRange, int _order, DROID _droid)
 
11623
{
 
11624
        // find a closest point at a base perimeter to retreat to
 
11625
        circlePerimPoint(_centerX, _centerY, ref _fromX, ref _fromY, _perimRange);
 
11626
 
 
11627
        // move
 
11628
        orderDroidLoc(_droid, _order, _fromX, _fromY);
 
11629
}
 
11630
 
 
11631
function void findFreeSpot(int _x, int _y)
 
11632
{
 
11633
        retInt = _x;
 
11634
        retInt2 = _y;
 
11635
 
 
11636
        _temp = _x;
 
11637
        _temp2 = _y;
 
11638
        if(pickStructLocation(fac, ref _temp, ref _temp2, me))
 
11639
        {
 
11640
                retInt = _temp; retInt2 = _temp2;
 
11641
                return;
 
11642
        }
 
11643
 
 
11644
        return;
 
11645
}
 
11646
 
 
11647
function void findFreeSpotMedium(int _x, int _y)
 
11648
{
 
11649
        retInt = _x;
 
11650
        retInt2 = _y;
 
11651
 
 
11652
        _temp = _x;
 
11653
        _temp2 = _y;
 
11654
        if(pickStructLocation(powGen, ref _temp, ref _temp2, me))
 
11655
        {
 
11656
                retInt = _temp; retInt2 = _temp2;
 
11657
                return;
 
11658
        }
 
11659
 
 
11660
        return;
 
11661
}
 
11662
 
 
11663
function void findFreeSpotSmall(int _x, int _y)
 
11664
{
 
11665
        retInt = _x;
 
11666
        retInt2 = _y;
 
11667
 
 
11668
        _temp = _x;
 
11669
        _temp2 = _y;
 
11670
        if(pickStructLocation(wall, ref _temp, ref _temp2, me))
 
11671
        {
 
11672
                retInt = _temp; retInt2 = _temp2;
 
11673
        }
 
11674
}
 
11675
 
 
11676
function void startCollecting()
 
11677
{
 
11678
        setState(stCollecting);
 
11679
 
 
11680
        dbg("COLLECT: started collecting state", me);
 
11681
 
 
11682
        setCollectingLoc();
 
11683
 
 
11684
        startCollectingPhase();
 
11685
 
 
11686
}
 
11687
 
 
11688
function void startCollectingPhase()
 
11689
{
 
11690
        setPhase(phCollecting, NONE);
 
11691
 
 
11692
        orderGroupLocCmd(sendAttackGr, DORDER_MOVE, collectX, collectY);        //use move, cause far away units may keep attacking forever
 
11693
 
 
11694
        collectTime = maxCollectTime;
 
11695
 
 
11696
        dbg("COLLECT: started collecting at " & collectX / 128 & " - " & collectY / 128, me);
 
11697
}
 
11698
 
 
11699
function void setCollectingLoc()
 
11700
{
 
11701
        collectX = groupCMD_x(sendAttackGr); collectY = groupCMD_y(sendAttackGr);
 
11702
 
 
11703
        dbg("setCollectingLoc() - mostOfGroup(): " & collectX / 128 & " - " & collectY / 128, me);
 
11704
 
 
11705
        //result3 = findFreeSpot(collectX, collectY);                   //a lot of free space
 
11706
        //collectX = retInt;    collectY = retInt2;
 
11707
 
 
11708
        dbg("setCollectingLoc() - set collect at " & collectX / 128 & " - " & collectY / 128, me);
 
11709
}
 
11710
 
 
11711
//gathered units or time is up
 
11712
function bool canStopCollecting()
 
11713
{
 
11714
        //return - 0 or 1
 
11715
 
 
11716
        /* time up */
 
11717
        if(collectTime <= 0)
 
11718
        {
 
11719
                return(TRUE);
 
11720
        }
 
11721
 
 
11722
        //temp = finishedCollecting();
 
11723
 
 
11724
        return(finishedCollecting());
 
11725
}
 
11726
 
 
11727
//gathered units
 
11728
function bool finishedCollecting()
 
11729
{
 
11730
        //return - 0 or 1
 
11731
 
 
11732
        /* most of them collected */
 
11733
        if(distBetweenTwoPoints(collectX, collectY, groupCMD_x(sendAttackGr), groupCMD_y(sendAttackGr)) < (5 * 128))
 
11734
        {
 
11735
                return(TRUE);
 
11736
        }
 
11737
 
 
11738
        return(FALSE);
 
11739
}
 
11740
 
 
11741
function bool enoughDroppers()
 
11742
{
 
11743
        if((groupSizeCmds(attackGr,true,false,true) + groupSizeCmds(sendAttackGr,true,false,true) +
 
11744
                groupSizeCmds(defendGr,true,false,true) - numDefenders) >= numDroppers)
 
11745
        {
 
11746
                return(TRUE);
 
11747
        }
 
11748
 
 
11749
        return(FALSE);
 
11750
}
 
11751
 
 
11752
function bool alliesReadyToDrop()
 
11753
{
 
11754
        _temp = 0;
 
11755
        _temp2 = 0;
 
11756
 
 
11757
        while(_temp < multiPlayerMaxPlayers)
 
11758
        {
 
11759
                if(allianceExistsBetween(me , _temp))
 
11760
                {
 
11761
                        if(allyState[_temp] == stDrop)          //gonna drop
 
11762
                        {
 
11763
                                if(allyEnemy[_temp] == enemy)   //dropping the same enemy as me
 
11764
                                {
 
11765
                                        if(allyPhase[_temp] < phWaitAllies)
 
11766
                                        {
 
11767
                                                return(FALSE);          //not ready yet
 
11768
                                        }
 
11769
                                }
 
11770
                        }
 
11771
                }
 
11772
                _temp = _temp + 1;
 
11773
        }
 
11774
 
 
11775
        return(TRUE);           //all ok
 
11776
}
 
11777
 
 
11778
function int getNumTransporters()
 
11779
{
 
11780
        _temp = 0;
 
11781
 
 
11782
        //Iterate through all player droids
 
11783
        InitEnumDroids(me,me);
 
11784
        _droid = EnumDroid();
 
11785
        while(_droid != NULLOBJECT)
 
11786
        {
 
11787
                if(_droid.droidType == DROID_TRANSPORTER)
 
11788
                {
 
11789
                        _temp = _temp + 1;
 
11790
                }
 
11791
 
 
11792
                _droid = EnumDroid();
 
11793
        }
 
11794
 
 
11795
        return(_temp);
 
11796
}
 
11797
 
 
11798
function bool enoughTransporters()
 
11799
{
 
11800
        temp = numTransporters;
 
11801
 
 
11802
        temp2 = getNumTransporters();
 
11803
 
 
11804
        if(temp2 >= temp)
 
11805
        {
 
11806
                return(TRUE);
 
11807
        }
 
11808
 
 
11809
        return(FALSE);
 
11810
}
 
11811
 
 
11812
function void buildTransporters()
 
11813
{
 
11814
        temp = numTransporters;
 
11815
 
 
11816
        /* how many got already */
 
11817
        temp2 = getNumTransporters();
 
11818
        //temp2 = temp2 + numTemplatesInProduction(tmplUnitransporter,me);      //FIXME
 
11819
 
 
11820
        //if(temp2 >= temp){exit;}
 
11821
 
 
11822
        /* build transporters */
 
11823
        initEnumStruct(FALSE,vtolfac,me,me);
 
11824
        tempStruct = enumStruct();
 
11825
        while((tempStruct != NULLOBJECT) and (temp2 < temp))
 
11826
        {
 
11827
                if(structureIdle(tempStruct))
 
11828
                {
 
11829
                        //if(skCanBuildTemplate(me, tempStruct, tmplUnitransporter))
 
11830
                        if(skGetFactoryCapacity(tempStruct) >= 2)               //fully upgraded
 
11831
                        {
 
11832
                                dbg("started to build transporter", me);
 
11833
                                //buildDroid(tmplUnitransporter, tempStruct, me, 1);            //FIXME
 
11834
                                temp2 = temp2 + 1;
 
11835
                        }
 
11836
                }
 
11837
 
 
11838
                tempStruct = enumStruct();
 
11839
        }
 
11840
}
 
11841
 
 
11842
function void fillDroppers()
 
11843
{
 
11844
        local   int     _bucket;
 
11845
 
 
11846
        temp = groupSizeCmds(defendGr,true,true,true) - numDefenders;
 
11847
 
 
11848
        temp2 = 0;
 
11849
 
 
11850
        while((temp > 0) and (temp2 < numDroppers))     //leave 'numDefenders' number of units in the defendGr
 
11851
        {
 
11852
                temp4 = 99999;
 
11853
                tempDroid2 = NULLOBJECT;
 
11854
 
 
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)
 
11859
                {
 
11860
                        temp3 = distBetweenTwoPoints(baseX, baseY, tempDroid.x, tempDroid.y);
 
11861
                        if(temp3 < temp4)
 
11862
                        {
 
11863
                                temp4 = temp3;
 
11864
                                tempDroid2 = tempDroid;
 
11865
                        }
 
11866
                        tempDroid = iterateGroupCmd(defendGr,_bucket);
 
11867
                }
 
11868
 
 
11869
                if(tempDroid2 != NULLOBJECT)    //got closest
 
11870
                {
 
11871
                        groupAddDroid(sendAttackGr, tempDroid2);
 
11872
                }
 
11873
                else
 
11874
                {
 
11875
                        temp2 = numDroppers;    //exit loop
 
11876
                }
 
11877
 
 
11878
                temp = temp - 1;        //one less left in defendGr
 
11879
                temp2 = temp2 + 1;      //one more loaded
 
11880
        }
 
11881
 
 
11882
        selectGroup(sendAttackGr, TRUE);
 
11883
}
 
11884
 
 
11885
function void dropLoadTransport()
 
11886
{
 
11887
        local   int     _bucket;
 
11888
 
 
11889
        //transportGr
 
11890
 
 
11891
        dbg("loading total " & numTransporters & " transporters (" & groupSizeCmds(transportGr,true,true,true) & " units)",me);
 
11892
 
 
11893
        if(groupSizeCmds(transportGr,true,true,true) == 0){exit;}               //include commanders
 
11894
 
 
11895
        /* load transports */
 
11896
        temp = 0;
 
11897
 
 
11898
        while(temp < maxTransporters)
 
11899
        {
 
11900
                if(transporter[temp] != NULLOBJECT)
 
11901
                {
 
11902
                        temp5 = transporterCapacity(transporter[temp]);
 
11903
                        //dbg("transporterCapacity[" & temp & "] = " & temp5, me);
 
11904
 
 
11905
                        while(temp5 > 0)
 
11906
                        {
 
11907
                                temp4 = 99999;
 
11908
                                tempDroid2 = NULLOBJECT;
 
11909
 
 
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)
 
11914
                                {
 
11915
                                        if(tempDroid.order != DORDER_EMBARK)
 
11916
                                        {
 
11917
                                                //dbg("!= DORDER_EMBARK", me);
 
11918
 
 
11919
                                                temp3 = distBetweenTwoPoints(transporter[temp].x, transporter[temp].y, tempDroid.x, tempDroid.y);
 
11920
                                                if(temp3 < temp4)
 
11921
                                                {
 
11922
                                                        temp4 = temp3;
 
11923
                                                        tempDroid2 = tempDroid;
 
11924
                                                }
 
11925
                                        }
 
11926
                                        tempDroid = iterateGroupCmd(transportGr,_bucket);
 
11927
                                }
 
11928
 
 
11929
                                if(tempDroid2 != NULLOBJECT)    //got closest
 
11930
                                {
 
11931
                                        //dbg("Unit embarking", me);
 
11932
                                        orderDroidObj(tempDroid2, DORDER_EMBARK, transporter[temp]);
 
11933
                                }
 
11934
 
 
11935
                                temp5 = temp5 - 1;
 
11936
                        }
 
11937
 
 
11938
                }
 
11939
                temp = temp + 1;
 
11940
        }
 
11941
}
 
11942
 
 
11943
function bool transporterLoaded()
 
11944
{
 
11945
        /* check if anyone is still waiting to be loaded */
 
11946
        if(groupSizeCmds(transportGr,true,true,true) <= numTransporters)        // > 90% loaded
 
11947
        {
 
11948
                dbg("transporter loaded!!!", me);
 
11949
                return(TRUE);
 
11950
        }
 
11951
 
 
11952
        /* check if loaded max number of droids (for example 20 for 2 transporters) */
 
11953
        temp = numDroidsLoaded();
 
11954
        temp2 = getNumTransporters();
 
11955
 
 
11956
        if(temp >= (temp2 * 10))
 
11957
        {
 
11958
                dbg("transporter loaded!!! 2", me);
 
11959
                return(TRUE);
 
11960
        }
 
11961
 
 
11962
        //dbg("transporter not loaded", me);
 
11963
        return(FALSE);
 
11964
}
 
11965
 
 
11966
//returns how many drois were loaded into transporters
 
11967
function int numDroidsLoaded()
 
11968
{
 
11969
        /* load transports */
 
11970
        _temp = 0;
 
11971
        _temp2 = 0;             //how many loaded
 
11972
 
 
11973
        while(_temp < maxTransporters)
 
11974
        {
 
11975
                if(transporter[_temp] != NULLOBJECT)
 
11976
                {
 
11977
                        _temp2 = (10 - transporterCapacity(transporter[_temp])) + _temp2;
 
11978
 
 
11979
                }
 
11980
                _temp = _temp + 1;
 
11981
        }
 
11982
 
 
11983
        return(_temp2);
 
11984
}
 
11985
 
 
11986
function int numActiveEnemyDrop(int _enemyToCheck)
 
11987
{
 
11988
        if(_enemyToCheck < 0){return(maxAllyDroppers);}
 
11989
 
 
11990
        retInt = 0;
 
11991
        _temp = 0;
 
11992
        while(_temp < multiPlayerMaxPlayers)
 
11993
        {
 
11994
                if((_temp != me) and (allianceExistsBetween(me , _temp)))
 
11995
                {
 
11996
                        if((allyState[_temp] == stDrop) and (allyEnemy[_temp] == _enemyToCheck) and (allyPhase[_temp] >= phWaitAllies)) //will drop very soon
 
11997
                        {
 
11998
                                retInt = retInt + 1;
 
11999
                        }
 
12000
                }
 
12001
                _temp = _temp + 1;
 
12002
        }
 
12003
 
 
12004
        return(retInt);
 
12005
}
 
12006
 
 
12007
function int numAlliesDroppingPlayer(int _player)
 
12008
{
 
12009
        if(_player < 0){return(maxAllyDroppers);}
 
12010
 
 
12011
        retInt = 0;
 
12012
        _temp = 0;
 
12013
        while(_temp < multiPlayerMaxPlayers)
 
12014
        {
 
12015
                if((_temp != me) and (allianceExistsBetween(me , _temp)))
 
12016
                {
 
12017
                        if((allyState[_temp] == stDrop) and (allyEnemy[_temp] == _player))
 
12018
                        {
 
12019
                                retInt = retInt + 1;
 
12020
                        }
 
12021
                }
 
12022
                _temp = _temp + 1;
 
12023
        }
 
12024
 
 
12025
        return(retInt);
 
12026
}
 
12027
 
 
12028
function bool timeToDrop()
 
12029
{
 
12030
        //drop if we are further away from the enemy than all allies or if our turn has came
 
12031
 
 
12032
        if((curBase[enemy][0] <= 0) or (curBase[enemy][1] <= 0))
 
12033
        {
 
12034
                MsgBox("timeToDrop - curBase[enemy][x/y] <= 0 (" & me & ")");
 
12035
                return FALSE;}
 
12036
 
 
12037
        if(enemy == none)
 
12038
        {
 
12039
                MsgBox("timeToDrop - no enemy set (" & me & ")");
 
12040
                return FALSE;}
 
12041
 
 
12042
        _temp3 = 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
 
12044
 
 
12045
        _temp = 0;
 
12046
        while(_temp < multiPlayerMaxPlayers)
 
12047
        {
 
12048
                if((_temp != me) and (allianceExistsBetween(me , _temp)))
 
12049
                {
 
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))
 
12052
                        {
 
12053
                                if(allyPhase[_temp] < phSync)   //someone not loaded transporters yet
 
12054
                                {
 
12055
                                        return FALSE;
 
12056
                                }
 
12057
                                else
 
12058
                                {
 
12059
                                        dbg("Ally phase is " & allyPhase[_temp], me);
 
12060
                                }
 
12061
 
 
12062
                                if((curBase[_temp][0] > 0) and (curBase[_temp][1] > 0))         //know where this ally is
 
12063
                                {
 
12064
                                        _temp2 = distBetweenTwoPoints(curBase[_temp][0], curBase[_temp][1], curBase[enemy][0], curBase[enemy][1]);
 
12065
 
 
12066
                                        /* is he farther away than all */
 
12067
                                        if(_temp2 > _range)
 
12068
                                        {
 
12069
                                                _range = _temp2;
 
12070
                                                _temp3 = _temp;         //remember furtherst ally
 
12071
                                        }
 
12072
                                }
 
12073
                        }
 
12074
 
 
12075
                }
 
12076
                _temp = _temp + 1;
 
12077
        }
 
12078
 
 
12079
        if(_temp3 == me)        //no ally is farther than us or we're the only player dropping
 
12080
        {
 
12081
                dbg("timeToDrop - i'm furthest!!!!!", me);
 
12082
                return TRUE;    //we are first
 
12083
        }
 
12084
 
 
12085
        /* check if anyone has started transporting already */
 
12086
        if(dropStartTime == none)
 
12087
        {
 
12088
                return(FALSE);          //wait for the furtherst player to start dropping
 
12089
        }
 
12090
 
 
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)
 
12094
        {
 
12095
                dbg("timeToDrop() - syncing drop!!!!!", me);
 
12096
                return(TRUE);   //now!!
 
12097
        }
 
12098
 
 
12099
        return(FALSE);          //not yet, wait to sync drop
 
12100
}
 
12101
 
 
12102
function void doDrop()
 
12103
{
 
12104
        if((transportX <= 0) or (transportY <= 0))
 
12105
        {
 
12106
                MsgBox("doDrop - transportX <= 0 (" & me & ")");
 
12107
                return;
 
12108
        }
 
12109
 
 
12110
        dbg("doDrop!!!", me);
 
12111
 
 
12112
        notifyStartDrop();              //tell we are starting to drop now
 
12113
 
 
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
 
12116
        {
 
12117
                _temp = groupSizeCmds(transportGr,true,true,true);
 
12118
                groupAddGroupCmd(defendGr, transportGr);
 
12119
                dbg(" " & _temp & " units could not be loaded", me);
 
12120
        }
 
12121
 
 
12122
        temp = 0;
 
12123
        while(temp < numTransporters)
 
12124
        {
 
12125
                if(transporter[temp] != NULLOBJECT)
 
12126
                {
 
12127
                        orderTranspDisembark(transporter[temp], transportX, transportY);
 
12128
                }
 
12129
                temp = temp + 1;
 
12130
        }
 
12131
 
 
12132
        /* return those who were not loaded back to defenders */
 
12133
        groupAddGroupCmd(defendGr, transportGr);
 
12134
}
 
12135
 
 
12136
//---------------------------------------------
 
12137
//      order transporter to send
 
12138
//---------------------------------------------
 
12139
function void orderTranspDisembark(DROID _transporter, int _coordx, int _coordy)
 
12140
{
 
12141
        bTempResult = chooseValidLoc(ref temp2, ref temp3, _coordx, _coordy, me, -1);   //no threat check
 
12142
        if(bTempResult)
 
12143
        {
 
12144
                dbg("ordered to disembark", me);
 
12145
                orderDroidLoc(_transporter, DORDER_DISEMBARK, temp2, temp3);
 
12146
        }
 
12147
        else
 
12148
        {
 
12149
                dbg("couldn't find a valid location for DISEMBARK!!!!!!!!!!!", me);
 
12150
        }
 
12151
}
 
12152
 
 
12153
event transLanded(inactive)
 
12154
{
 
12155
        dbg("Transporter landed", me);
 
12156
 
 
12157
        if(groupSizeCmds(tempGr,true,true,true) == 0){exit;}
 
12158
 
 
12159
        if((state == stNone) or defendingBase())                //not doing anything, so unload to defenders
 
12160
        {
 
12161
                groupAddGroupCmd(defendGr, tempGr);
 
12162
        }
 
12163
        else
 
12164
        {
 
12165
                dbg("Added " & groupSizeCmds(tempGr,true,true,true) & " units to sendAttackGr", me);
 
12166
                groupAddGroupCmd(sendAttackGr, tempGr); //TODO: won't work with commanders?
 
12167
        }
 
12168
 
 
12169
        /* check if have to fly it back to the base */
 
12170
        if(not isInMyBase(droid.x, droid.y))
 
12171
        {
 
12172
                dbg("ordering transporter back to base", me);
 
12173
 
 
12174
                findFreeSpotSmall(baseX, baseY);
 
12175
                temp2 = retInt; temp3 = retInt2;
 
12176
 
 
12177
                orderDroidLoc(droid, DORDER_MOVE, temp2, temp3);
 
12178
        }
 
12179
}
 
12180
 
 
12181
function bool checkTransportersLanded()
 
12182
{
 
12183
        local bool      _bLanded;
 
12184
 
 
12185
        _bLanded = TRUE;        //all landed
 
12186
        temp = 0;
 
12187
 
 
12188
        while(temp < numTransporters)
 
12189
        {
 
12190
                if(transporter[temp] != NULLOBJECT)
 
12191
                {
 
12192
                        if(transporterCapacity(transporter[temp]) < 10) //not all unloaded
 
12193
                        {
 
12194
                                _bLanded = FALSE;
 
12195
                        }
 
12196
                }
 
12197
                temp = temp + 1;
 
12198
        }
 
12199
 
 
12200
        return(_bLanded);
 
12201
}
 
12202
 
 
12203
function int setNumDroppers()
 
12204
{
 
12205
        retInt = maxDroppers;
 
12206
 
 
12207
        /* check how much we will have to invest into this drop */
 
12208
        if(playerPower(me) < highPower)
 
12209
        {
 
12210
                temp = numAvailableAttackers();
 
12211
 
 
12212
                /* attack force*/
 
12213
                if((retInt - temp) > 10)                //can't afford building this many
 
12214
                {
 
12215
                        retInt = medDroppers;
 
12216
                        dbg("Medium droppers", me);
 
12217
                }
 
12218
 
 
12219
                temp = calcNumRequiredTransporters(retInt);
 
12220
 
 
12221
                temp2 = getNumTransporters();
 
12222
 
 
12223
                /* check transporters */
 
12224
                if((temp - temp2) >= 1)         //allow to build only 1 new transp for every drop
 
12225
                {
 
12226
                        retInt = (temp2 + 1) * 10;      //as many as we have transporters already + 1
 
12227
                        //if(temp2 <= 0)                        //no transporters yet
 
12228
                        //{
 
12229
                        //      retInt = minDroppers;   //smallest drop possible
 
12230
                        //      dbg("Min droppers", me);
 
12231
                        //}
 
12232
 
 
12233
                        dbg("Min droppers", me);
 
12234
 
 
12235
                        /* make sure we stay in bounds */
 
12236
                        if(retInt > maxDroppers)
 
12237
                        {
 
12238
                                retInt = maxDroppers;
 
12239
                        }
 
12240
                }
 
12241
        }
 
12242
 
 
12243
        return(retInt);
 
12244
}
 
12245
 
 
12246
function int calcNumRequiredTransporters(int _numUnits)
 
12247
{
 
12248
        /* decide how many transporters we need */
 
12249
        _retInt = _numUnits / 10;
 
12250
        if((_retInt * 10) != _numUnits)         //fix integer div
 
12251
        {
 
12252
                _retInt = _retInt + 1;
 
12253
        }
 
12254
 
 
12255
        if(_retInt > maxTransporters)
 
12256
        {
 
12257
                _retInt = maxTransporters;
 
12258
        }
 
12259
 
 
12260
        return(_retInt);
 
12261
}
 
12262
 
 
12263
function void prepareTransporters()
 
12264
{
 
12265
        temp = 0;
 
12266
 
 
12267
        while(temp < numTransporters)
 
12268
        {
 
12269
                if(transporter[temp] != NULLOBJECT)
 
12270
                {
 
12271
                        if(groupSizeCmds(transportGr,true,true,true) > 0)
 
12272
                        {
 
12273
                                temp2 = groupCMD_x(transportGr);
 
12274
                                temp3 = groupCMD_y(transportGr);
 
12275
 
 
12276
                                circlePerimPoint(baseX, baseY, ref temp2, ref temp3, baseRange);
 
12277
 
 
12278
                                findFreeSpotMedium(temp2, temp3);
 
12279
                                temp2 = retInt; temp3 = retInt2;
 
12280
 
 
12281
                                orderDroidLoc(transporter[temp], DORDER_MOVE, temp2, temp3);
 
12282
                        }
 
12283
                }
 
12284
 
 
12285
                temp = temp + 1;
 
12286
        }
 
12287
}
 
12288
 
 
12289
function void updateDropPhase()
 
12290
{
 
12291
        /* check if already can build transporter */
 
12292
        if(phase == phGettingTech)
 
12293
        {
 
12294
                //if(researchFinished(resUnitTransporter, me))
 
12295
                //{
 
12296
                        setPhase(phGettingUnits, NONE);
 
12297
                //}
 
12298
        }
 
12299
 
 
12300
        if(phase == phGettingUnits)
 
12301
        {
 
12302
                result3 = getNumTransporters();
 
12303
 
 
12304
                /* if we hit unit limit, we'll never be able to build transporters */
 
12305
                if((result3 < numTransporters) and (getDroidCount(me) >= unitLimit))
 
12306
                {
 
12307
                        if(result3 > 0)         //got at least 1 transp
 
12308
                        {
 
12309
                                numTransporters = result3;              //continue with whatever we have
 
12310
                                numDroppers = numTransporters * 10;
 
12311
                        }
 
12312
                }
 
12313
 
 
12314
                /* check if have enough units and transp for drop */
 
12315
                //result = enoughDroppers();
 
12316
                //result2 = enoughTransporters();
 
12317
 
 
12318
                if(enoughDroppers() and enoughTransporters())
 
12319
                {
 
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
 
12324
 
 
12325
                        setPhase(phWaitAllies, NONE);   //wait for others
 
12326
                }
 
12327
        }
 
12328
 
 
12329
        if(phase == phWaitAllies)
 
12330
        {
 
12331
                /* check if other allies are also ready to drop */
 
12332
                if(alliesReadyToDrop() or (tWaitAlliesDrop <= 0))       //all ready or waited for too long
 
12333
                {
 
12334
                        fillDroppers();
 
12335
 
 
12336
                        startTransportState(sendAttackGr, curBase[enemy][0], curBase[enemy][1]);
 
12337
                }
 
12338
        }
 
12339
 
 
12340
        /* we are back from transport state */
 
12341
        if(phase == phTransportDone)
 
12342
        {
 
12343
                stopDropState();                //can stop drop now and resume any paused state (if any)
 
12344
        }
 
12345
}
 
12346
 
 
12347
function void updateTransport()
 
12348
{
 
12349
        if(phase == phLoadingTransport)
 
12350
        {
 
12351
                if(transporterLoaded())                         //loaded
 
12352
                {
 
12353
                        setPhase(phSync, NONE);
 
12354
 
 
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
 
12358
                }
 
12359
                else if((tWaitLoadDrop <= 0) or (dropStartTime != none))                //waited too long, or someone has started drop already!!!, drop now
 
12360
                {
 
12361
                        temp = numDroidsLoaded();
 
12362
 
 
12363
                        temp2 = numAlliesDroppingPlayer(enemy);
 
12364
 
 
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
 
12366
                        {
 
12367
                                setPhase(phSync, NONE);
 
12368
 
 
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
 
12372
                        }
 
12373
                        else
 
12374
                        {
 
12375
                                cancelTransportState(); //couldn't load enough
 
12376
                        }
 
12377
                }
 
12378
                else
 
12379
                {
 
12380
                        dropLoadTransport();
 
12381
                }
 
12382
        }
 
12383
 
 
12384
        /* syncronize drop with allies, wait if needed */
 
12385
        if(phase == phSync)
 
12386
        {
 
12387
                if(timeToDrop() or (tSyncDrop <= 0))            //can drop now or waited too long
 
12388
                {
 
12389
                        if(tSyncDrop <= 0)
 
12390
                        {
 
12391
                                dbg("tSyncDrop timeout - time to drop!!!!", me);
 
12392
                        }
 
12393
                        else
 
12394
                        {
 
12395
                                dbg("timeToDrop() - time to drop!!!!", me);
 
12396
                        }
 
12397
 
 
12398
                        setPhase(phSendDrop, NONE);             //on the way to the enemy
 
12399
 
 
12400
                        doDrop();
 
12401
                }
 
12402
                else
 
12403
                {
 
12404
                        dbg("waiting for my turn to drop", me);
 
12405
                }
 
12406
        }
 
12407
 
 
12408
        /* watch for transporters to arrive */
 
12409
        if(phase == phSendDrop)
 
12410
        {
 
12411
                if( checkTransportersLanded() )         //all unloaded
 
12412
                {
 
12413
                        dbg("Transporter landed!!!!!!!!!!!", me);
 
12414
                        stopTransportState();
 
12415
                }
 
12416
        }
 
12417
 
 
12418
        //dbg("phase = " & phase, me);
 
12419
}
 
12420
 
 
12421
function void startTransportState(GROUP _groupToTransport, int _destinationX, int _destinationY)
 
12422
{
 
12423
        dbg("Starting transport phase!!!!!!", me);
 
12424
 
 
12425
        transportX = _destinationX;
 
12426
        transportY = _destinationY;
 
12427
        transportGr = _groupToTransport;
 
12428
 
 
12429
        temp = getNumTransporters();
 
12430
        if(temp == 0)
 
12431
        {
 
12432
                cancelTransportState();
 
12433
                return;
 
12434
        }
 
12435
 
 
12436
        if(state != stNone)
 
12437
        {
 
12438
                saveCurrentState();
 
12439
        }
 
12440
 
 
12441
        endState();             //init vars of the original state
 
12442
 
 
12443
        setState(stTransporting);
 
12444
        
 
12445
        setPhase(phLoadingTransport, NONE);
 
12446
 
 
12447
        tWaitLoadDrop = tMaxWaitLoadDrop;
 
12448
 
 
12449
        dropLoadTransport();
 
12450
}
 
12451
 
 
12452
function void saveCurrentState()
 
12453
{
 
12454
        savedState = state;
 
12455
        //savedPhase = phase;
 
12456
        //savedEnemy = enemy;
 
12457
}
 
12458
 
 
12459
function void loadSavedState()
 
12460
{
 
12461
        dbg("loading saved state!!!!!!!!", me);
 
12462
 
 
12463
        if(savedState == stDrop)
 
12464
        {
 
12465
                /* after drop complete start attacking enemy */
 
12466
 
 
12467
                dbg("loaded drop state!!!!!!!!", me);
 
12468
 
 
12469
                setState(savedState);
 
12470
        }
 
12471
        else    //?, just init state and phase vars
 
12472
        {
 
12473
                stopTransportState();
 
12474
        }
 
12475
 
 
12476
        /* clear vars */
 
12477
        eraseLoadSavedState();
 
12478
}
 
12479
 
 
12480
function void eraseLoadSavedState()
 
12481
{
 
12482
        savedState = stNone;
 
12483
        savedPhase = phNone;
 
12484
        savedEnemy = none;
 
12485
}
 
12486
 
 
12487
function void resortTransporters()
 
12488
{
 
12489
        temp = 0;
 
12490
        while(temp < maxTransporters)
 
12491
        {
 
12492
                if(transporter[temp] == NULLOBJECT)
 
12493
                {
 
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))
 
12497
                        {
 
12498
                                if(transporter[temp2] != NULLOBJECT)
 
12499
                                {
 
12500
                                        /* swap in array */
 
12501
                                        transporter[temp] = transporter[temp2];
 
12502
                                        transporter[temp2] = NULLOBJECT;
 
12503
                                }
 
12504
 
 
12505
                                temp2 = temp2 + 1;
 
12506
                        }
 
12507
                }
 
12508
 
 
12509
                temp = temp + 1;
 
12510
        }
 
12511
}
 
12512
 
 
12513
 
 
12514
function void startDropPhase()
 
12515
{
 
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;}
 
12519
 
 
12520
        setState(stDrop);
 
12521
        
 
12522
        setPhase(phGettingTech, NONE);
 
12523
 
 
12524
        tempReinfCount[enemy] = 0;              //reset here
 
12525
        dropStartTime = none;
 
12526
        tSyncDrop = 0;
 
12527
 
 
12528
        /* decide how many units we will drop */
 
12529
        numDroppers = setNumDroppers();
 
12530
 
 
12531
        /* decide how many transporters we need */
 
12532
        numTransporters = calcNumRequiredTransporters(numDroppers);
 
12533
 
 
12534
        dbg("Preparing drop at " & getPlayerName(enemy) & " with " & numDroppers & " units and " & numTransporters & " transporters!!", me);
 
12535
 
 
12536
        updateStateCoord(curBase[enemy][0], curBase[enemy][1]);
 
12537
 
 
12538
        resortTransporters();   //resort array
 
12539
 
 
12540
        updateDropPhase();
 
12541
}
 
12542
 
 
12543
function void updateStateCoord(int _newx, int _newy)
 
12544
{
 
12545
        sendForceX = _newx;
 
12546
        sendForceY = _newy;
 
12547
}
 
12548
 
 
12549
/* Fill attackers, prepare commanders etc */
 
12550
function void prepareAttackers(bool _bHighPriorityTask)
 
12551
{
 
12552
        local   int             _numNeedToBeAssigned;
 
12553
 
 
12554
        /* Unassign all units from all commanders in the defendGr  to the defendGr */
 
12555
        unassignAllDroidsFromCMDsFromGroup(defendGr, defendGr);
 
12556
 
 
12557
        /* Add required number of units from defendGr to sendAttackGr (non-commanders only) */
 
12558
        fillAttackers(numAttackersFromPriorty(_bHighPriorityTask));
 
12559
 
 
12560
        /* Make commanders fromattack group take over units without commander from attackGr */
 
12561
        assignDroidsToBestCommandersFromGroup(attackGr,attackGr);
 
12562
 
 
12563
        /* Make commanders fromattack group take over units without commander from sendAttackGr */
 
12564
        assignDroidsToBestCommandersFromGroup(attackGr,sendAttackGr);
 
12565
 
 
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);
 
12571
 
 
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);
 
12575
        }
 
12576
 
 
12577
        dbg("Num new commanders attacking: " &
 
12578
                groupSizeCmds(sendAttackGr, false, true, false), me);
 
12579
 
 
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);
 
12584
 
 
12585
        /* Make commanders left in the defendGr take over the rest of the unassigned droids from group defendGr */
 
12586
        assignDroidsToBestCommandersFromGroup(defendGr, defendGr);
 
12587
 
 
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 */
 
12590
}
 
12591
 
 
12592
/* Start attacking enemy base - a Wrapper for startAttack() */
 
12593
function void startEnemyBaseAttack(int _enemy)
 
12594
{
 
12595
        attackReason = ATTACK_BASE;
 
12596
 
 
12597
        startAttack(_enemy, curBase[_enemy][0], curBase[_enemy][1]);
 
12598
}
 
12599
 
 
12600
/* Start attacking enemy arty - a Wrapper for startAttack() */
 
12601
function void startArtyCounterAttack(int _enemy, int _x, int _y)
 
12602
{
 
12603
        attackReason = ATTACK_COUNTER_ARTY;
 
12604
 
 
12605
        startAttack(_enemy, _x, _y);
 
12606
}
 
12607
 
 
12608
function void startAttack(int _enemy, int _x, int _y)
 
12609
{
 
12610
        if(_enemy < 0)
 
12611
        {
 
12612
                stopAttack();
 
12613
                MsgBox("startAttack - enemy (" & _enemy & ") < 0");
 
12614
                return;
 
12615
        }
 
12616
 
 
12617
        if((_x <= 0) or (_y <= 0)){MsgBox("startAttack - enemy coords < 0"); return;}
 
12618
        //if(not knowBase[enemy]){MsgBox("startAttack - knowBase[enemy] == FALSE"); return;}
 
12619
 
 
12620
        //if(state != stNone){return;}
 
12621
 
 
12622
        dbg("Starting attack at " & getPlayerName(_enemy) & " !!!!!", me);
 
12623
 
 
12624
        setState(stAttacking);
 
12625
 
 
12626
        enemy = _enemy;
 
12627
 
 
12628
        updateStateCoord(_x, _y);
 
12629
 
 
12630
        /* Set minimum number of defenders to leave in the base */
 
12631
        updateNumDefenders();
 
12632
 
 
12633
        /* Assign attackers and commanders to groups */
 
12634
        prepareAttackers(false);
 
12635
 
 
12636
        startMovePhase();
 
12637
 
 
12638
        /* reset notification stuff */
 
12639
        bNotifiedReadyAttack = FALSE;
 
12640
        notifyReadyAttackTime = 0;
 
12641
 
 
12642
        reinfCount[enemy] = reinfCount[enemy] + 1;
 
12643
        tempReinfCount[enemy] = tempReinfCount[enemy] + 1;
 
12644
 
 
12645
        countTakeOil = 0;               //allow hunting oil again
 
12646
}
 
12647
 
 
12648
//Attack enemy base with VTOLs
 
12649
function void vStartAttackBase(int _enemy)
 
12650
{
 
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;}
 
12654
 
 
12655
        //if(state != stNone){return;}
 
12656
 
 
12657
        dbg("Starting attack at " & getPlayerName(_enemy) & " !!!!!", me);
 
12658
 
 
12659
        //vstate = stAttackBase;
 
12660
 
 
12661
        //venemy = _enemy;
 
12662
 
 
12663
        //sendForceX = curBase[venemy][0];
 
12664
        //sendForceY = curBase[venemy][1];
 
12665
 
 
12666
        //VTOLAttackBase(venemy);
 
12667
}
 
12668
 
 
12669
/*
 
12670
function void vAttackBase(int _enemy)
 
12671
{
 
12672
        local BASEOBJ   _newTarget;
 
12673
 
 
12674
        if(vtolGr.members < minVtolAttackers)
 
12675
        {
 
12676
                vstopState();
 
12677
                return;
 
12678
        }
 
12679
 
 
12680
        //check if too well defended
 
12681
        if(not vtolSafe(vsendForceX, vsendForceY))
 
12682
        {
 
12683
                vstopState();
 
12684
                return;
 
12685
        }
 
12686
 
 
12687
        //idle?
 
12688
        if(idleGroupCmd(vtolGr) >= (vtolGr.members / 2))
 
12689
        {
 
12690
                // need new target
 
12691
                _newTarget = vBaseTarget(_enemy);
 
12692
 
 
12693
                if(_newTarget == NULLOBJECT)
 
12694
                {
 
12695
                        vstopState();   //nothing to attack
 
12696
                        return;
 
12697
                }
 
12698
 
 
12699
                vDoAttackObj(vtolGr, _newTarget);
 
12700
        }
 
12701
}
 
12702
*/
 
12703
 
 
12704
function void startMovePhase()
 
12705
{
 
12706
        if((sendForceX <= 0) or (sendForceY <= 0)){MsgBox("startMovePhase() - sendForceXY <= 0"); return;}
 
12707
 
 
12708
        orderGroupLocCmd(sendAttackGr, DORDER_SCOUT, sendForceX, sendForceY);
 
12709
 
 
12710
        reinfTime = maxReinfTime;       //start "cancel attack" countdown
 
12711
 
 
12712
        setPhase(phMoveToLoc, NONE);
 
12713
 
 
12714
        dbg("MOVE PHASE: started", me);
 
12715
}
 
12716
 
 
12717
function void startTakingOil(STRUCTURE _enemyDerrick)
 
12718
{
 
12719
        local   int             _numAttackers;
 
12720
 
 
12721
        if(_enemyDerrick == NULLOBJECT){MsgBox("startTakingOil - derrick == NULLOBJECT"); return;}
 
12722
 
 
12723
        //if(enemy < 0){MsgBox("startTakingOil - enemy < 0"); exit;}
 
12724
        //if((sendForceX <= 0) or (sendForceY <= 0)){MsgBox("startTakingOil - sendForceXY <= 0"); exit;}
 
12725
 
 
12726
        setState(stTakingOil);
 
12727
 
 
12728
        enemy = _enemyDerrick.player;
 
12729
        tempReinfCount[enemy] = 0;              //reset
 
12730
 
 
12731
        updateStateCoord(_enemyDerrick.x, _enemyDerrick.y);
 
12732
 
 
12733
        /* Set minimum number of defenders to leave in the base */
 
12734
        updateNumDefenders();
 
12735
 
 
12736
        dbg("Starting taking " & getPlayerName(enemy) & "'s oil at " & sendForceX / 128 & " - " & sendForceY / 128 & "!!!!!", me);
 
12737
 
 
12738
        /* Assign attackers and commanders to groups */
 
12739
        prepareAttackers(false);
 
12740
 
 
12741
        startMovePhase();
 
12742
 
 
12743
        timeGuardPos = 0;       //cancel countdown
 
12744
        tTakeOil = tMaxTakeOil;
 
12745
 
 
12746
        countTakeOil = countTakeOil + 1;        //remember how many times we took oil
 
12747
 
 
12748
        //phase = phMoveToLoc;
 
12749
}
 
12750
 
 
12751
/* Changes state and returns old state */
 
12752
function void setState(int _newState)
 
12753
{
 
12754
        local int       _oldState;
 
12755
 
 
12756
        /* Initialize state time */
 
12757
        tState = 0;
 
12758
 
 
12759
        _oldState = state;
 
12760
        state = _newState;
 
12761
 
 
12762
        //return _oldState;
 
12763
}
 
12764
 
 
12765
/* Changes vtol state and returns old state */
 
12766
function void vsetState(int _newState)
 
12767
{
 
12768
        local int       _oldState;
 
12769
 
 
12770
        /* Initialize state time */
 
12771
        //tvState = 0;
 
12772
 
 
12773
        _oldState = vstate;
 
12774
        vstate = _newState;
 
12775
 
 
12776
        //return _oldState;
 
12777
}
 
12778
 
 
12779
//don't leave BBs in defend group
 
12780
function int sortOutBBs()
 
12781
{
 
12782
        local   DROID   _bbDroid;
 
12783
        local   int     _bucket,_numBBs;
 
12784
 
 
12785
        _bucket = initIterateGroupCmd(defendGr,true,false,true);
 
12786
        _bbDroid = iterateGroupCmd(defendGr,_bucket);
 
12787
        while(_bbDroid != NULLOBJECT)
 
12788
        {
 
12789
                if(_bbDroid.weapon == weaponBB)
 
12790
                {
 
12791
                        groupAddDroid(sendAttackGr,_bbDroid);
 
12792
                        _numBBs++;
 
12793
                }
 
12794
                _bbDroid = iterateGroupCmd(defendGr,_bucket);
 
12795
        }
 
12796
 
 
12797
        return _numBBs;
 
12798
}
 
12799
 
 
12800
function void doAttack()
 
12801
{
 
12802
        local   int             _bucket;
 
12803
        local   BASEOBJ         _target;
 
12804
 
 
12805
        //dbg(" " & me & ")  doAttack()");
 
12806
 
 
12807
        //if(state != stAttacking){return;}
 
12808
 
 
12809
        //if going back to base, check if already there
 
12810
        //-----------------------------------------------
 
12811
/*
 
12812
        if(phase == phRTB)
 
12813
        {
 
12814
                range = (20 * 128);             //attacker reached home base range
 
12815
                initIterateGroup(sendAttackGr);
 
12816
                droid = iterateGroup(sendAttackGr);
 
12817
                while(droid != NULLOBJECT)
 
12818
                {
 
12819
                        if(distBetweenTwoPoints(droid.x, droid.y, droid.orderx, droid.ordery) < range)
 
12820
                        {
 
12821
                                groupAddDroid(defendGr,droid);
 
12822
                        }//check if going back to base
 
12823
                        else if(distBetweenTwoPoints(baseX, baseY, droid.orderx, droid.ordery) >= range)
 
12824
                        {
 
12825
                                orderDroid(droid, DORDER_RTB);  //send back to base
 
12826
                        }
 
12827
 
 
12828
                        droid = iterateGroup(sendAttackGr);
 
12829
                }
 
12830
 
 
12831
                //Migration not over yet?
 
12832
                if(sendAttackGr.members <= 5)
 
12833
                {
 
12834
                        groupAddGroup(defendGr, sendAttackGr);
 
12835
                        phase = phNone;
 
12836
                        dbg("attackers backin the base !!!", me);
 
12837
                }
 
12838
        }
 
12839
*/
 
12840
 
 
12841
        //all real attack stuff comes here
 
12842
        //-----------------------------------------------
 
12843
 
 
12844
 
 
12845
        if(enemy < 0){MsgBox("doAttack - enemy < 0");return;}
 
12846
 
 
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
 
12850
        {
 
12851
                dbg("someone destroyed enemy, cancel attack", me);
 
12852
                stopAttack();
 
12853
                return;
 
12854
        }
 
12855
 
 
12856
        if((curBase[enemy][0] <= 0) or (curBase[enemy][1] <= 0)){MsgBox("doAttack - enemy (" & enemy & ")coords < 0"); return;}
 
12857
 
 
12858
 
 
12859
 
 
12860
        /* Update coordinates */
 
12861
        //if(curBase[enemy][0] > 0 and curBase[enemy][1] > 0)   //only update if set?
 
12862
        //{
 
12863
        
 
12864
        // Update current goto location to the new base location of current enemy if we are attacking its base
 
12865
        if(attackingEnemyBase(enemy))
 
12866
        {
 
12867
                updateStateCoord(curBase[enemy][0], curBase[enemy][1]);
 
12868
        }
 
12869
        //}
 
12870
 
 
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))
 
12875
        {
 
12876
                dbg("after revealing found enemy base again, attack (!!!!!!!!!!!!)", me);
 
12877
                setPhase(phMoveToLoc, NONE);    //go to the new enemy base location
 
12878
 
 
12879
                taunt(enemy, TAUNT_REDISCOVERED_BASE, 40);
 
12880
        }
 
12881
 
 
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
 
12887
 
 
12888
 
 
12889
        //------------------------------------------------
 
12890
        //manage attack
 
12891
        //------------------------------------------------
 
12892
 
 
12893
        //if there are enemy structures left, move closer to them to attack, don't run away
 
12894
 
 
12895
        //if((phase == phAttackingLoc) and (seeBase[enemy]))    //not revealing the base territory already
 
12896
 
 
12897
        if(phase != phSearchingForBase)         //not already revealing
 
12898
        {
 
12899
                if((sendForceX > 0) and (sendForceY > 0))
 
12900
                {
 
12901
                        if(canSeeLoc(sendForceX, sendForceY))   //no targets, check if any unrevealed territory left
 
12902
                        {
 
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
 
12906
 
 
12907
                                if(!enemyTargetInRange(enemy, sendForceX, sendForceY, (TILE * 3)))
 
12908
                                {
 
12909
                                        _target = findEnemyTargetInRange(enemy, sendForceX, sendForceY, (TILE * 13), true, true);
 
12910
                                        
 
12911
                                        // go to that target
 
12912
                                        if(_target != NULLOBJECT)
 
12913
                                        {
 
12914
                                                dbg("found new target at " & _target.x / TILE & " - " & _target.y / TILE, me);
 
12915
                                                
 
12916
                                                updateStateCoord(_target.x, _target.y);
 
12917
                                        }
 
12918
                                        else
 
12919
                                        {
 
12920
                                                dbg("ATTACK: No visible enemy structures left, revealing territory !!!!!", me);
 
12921
                                                
 
12922
                                                setPhase(phSearchingForBase, MINUTE * 2);       // 2 mins max
 
12923
                                                
 
12924
                                                taunt(enemy, TAUNT_LOST_BASE, 40);
 
12925
                                        }
 
12926
                                }
 
12927
                        }
 
12928
                }
 
12929
        }
 
12930
 
 
12931
 
 
12932
        //reveal territory near the enemy base
 
12933
        if(phase == phSearchingForBase)
 
12934
        {
 
12935
                range = (TILE * 16);            //search for enemy structures in en base range
 
12936
 
 
12937
                _bucket = initIterateGroupCmd(attackGr,true,true,true);
 
12938
                droid = iterateGroupCmd(attackGr,_bucket);
 
12939
                while(droid != NULLOBJECT)
 
12940
                {
 
12941
                        if(droidOrderIdle(droid) and !droidActionAttacking(droid))
 
12942
                        {
 
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
 
12945
                                {
 
12946
                                        orderDroidLoc(droid, DORDER_SCOUT, x, y);
 
12947
                                }
 
12948
                                else if(phase != phLostBase)
 
12949
                                {
 
12950
                                        dbg("nothing to reveal anymore, lost enemy base !!!", me);
 
12951
                                        setPhase(phLostBase, MINUTE * 1);       //no more unrevealed territory
 
12952
                                }
 
12953
                        }
 
12954
                        droid = iterateGroupCmd(attackGr,_bucket);
 
12955
                }
 
12956
        }
 
12957
 
 
12958
        //dbg(" " & me & ")  END doAttack()");
 
12959
}
 
12960
 
 
12961
/* range in world units!!!! */
 
12962
function void findAttackBaseTarget(DROID _looker, int _x, int _y, int _radius)
 
12963
{
 
12964
        ASSERT(_looker != NULLOBJECT, "findAttackBaseTarget: _looker is NULLOBJECT", me);
 
12965
 
 
12966
        retObj = NULLOBJECT;
 
12967
 
 
12968
        //dbg(" " & me & ")              findAttackBaseTarget");
 
12969
 
 
12970
        //find a target
 
12971
        if((_looker.order == DORDER_NONE) or (_looker.order == DORDER_SCOUT) or (_looker.order == DORDER_MOVE))
 
12972
        //if(_looker.order != DORDER_ATTACK)
 
12973
        {
 
12974
                //dbg(" " & me & ")              no order");
 
12975
                if(objHasWeapon(_looker))
 
12976
                {
 
12977
                        //dbg(" " & me & ")              has weapon");
 
12978
 
 
12979
                        /* Use weapon range if no radius specified */
 
12980
                        temp = _radius;
 
12981
                        if(_radius < 0)
 
12982
                        {
 
12983
                                _radius = objWeaponMaxRange(_looker);   //objWeaponMaxRange is in world units
 
12984
                                _radius = _radius + (2 * 128);  //target range = droid weapon range + 2 tiles
 
12985
                        }
 
12986
 
 
12987
                        if(_radius > 0)
 
12988
                        {
 
12989
                                /* Use unit coords if no position set where to look for units */
 
12990
                                if(_x < 0)
 
12991
                                        _x = _looker.x;
 
12992
 
 
12993
                                if(_y < 0)
 
12994
                                        _y = _looker.y;
 
12995
 
 
12996
                                /* see any trucks? */
 
12997
                                tempDroid = getClosestEnemyDroidByType(_x, _y, _radius, DROID_CONSTRUCT, FALSE, me);
 
12998
 
 
12999
                                if(tempDroid == NULLOBJECT)
 
13000
                                {
 
13001
                                        /* any repairers? */
 
13002
                                        tempDroid = getClosestEnemyDroidByType(_x, _y, _radius, DROID_REPAIR, FALSE, me);
 
13003
 
 
13004
                                        if(tempDroid != NULLOBJECT)
 
13005
                                        {
 
13006
                                                if(tempDroid.action == DACTION_REPAIR)  //only if repairing
 
13007
                                                {
 
13008
                                                        retObj = tempDroid;
 
13009
                                                }
 
13010
                                        }
 
13011
 
 
13012
                                        if(retObj == NULLOBJECT)
 
13013
                                        {
 
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
 
13015
                                                {
 
13016
                                                        retObj = getClosestEnemy(_x, _y, _radius, TRUE, FALSE, me);
 
13017
                                                }
 
13018
                                        }
 
13019
                                }
 
13020
                                else
 
13021
                                {
 
13022
                                        retObj = tempDroid;
 
13023
                                }
 
13024
 
 
13025
                        }
 
13026
                }
 
13027
        }
 
13028
}
 
13029
 
 
13030
function void findBBAttackBaseTarget(DROID _looker)
 
13031
{
 
13032
        retObj = NULLOBJECT;
 
13033
 
 
13034
        //temp = (2 * 128);     //"reached the destination" range
 
13035
 
 
13036
        if(_looker.order != DORDER_ATTACK)
 
13037
        {
 
13038
                //dbg(" " & me & ")              BB no order");
 
13039
                if(objHasWeapon(_looker))
 
13040
                {
 
13041
                        //dbg(" " & me & ")              BB has weapon");
 
13042
 
 
13043
                        temp = objWeaponMaxRange(_looker);      //objWeaponMaxRange is in world units
 
13044
                        if(temp > 0)
 
13045
                        {
 
13046
                                //dbg(" " & me & ")              BB has range");
 
13047
 
 
13048
                                temp2 = (temp + (3 * 128));     //target range = droid weapon range + 3 tiles
 
13049
 
 
13050
                                tempStruct = getClosestEnemyStructByType(_looker.x, _looker.y, temp2, REF_DEFENSE, me);
 
13051
                                if(tempStruct == NULLOBJECT)
 
13052
                                {
 
13053
                                        tempStruct = getClosestEnemyStructByType(_looker.x, _looker.y, temp2, REF_WALL, me);
 
13054
                                        if(tempStruct == NULLOBJECT)
 
13055
                                        {
 
13056
                                                tempStruct = getClosestEnemyStructByType(_looker.x, _looker.y, temp2, REF_WALLCORNER, me);
 
13057
                                        }
 
13058
 
 
13059
                                        if(tempStruct == NULLOBJECT)
 
13060
                                        {
 
13061
                                                tempStruct = getClosestEnemyStructByType(_looker.x, _looker.y, temp2, -1, me);  //any structure
 
13062
                                                if(tempStruct != NULLOBJECT)
 
13063
                                                {
 
13064
                                                        //dbg(" " & me & ")  BB found some structure");
 
13065
                                                        retObj = tempStruct;
 
13066
                                                }
 
13067
                                        }
 
13068
                                        else
 
13069
                                        {
 
13070
                                                //dbg(" " & me & ")  BB found wall");
 
13071
                                                retObj = tempStruct;
 
13072
                                        }
 
13073
                                }
 
13074
                                else
 
13075
                                {
 
13076
                                        //dbg(" " & me & ")  BB found defense");
 
13077
                                        retObj = tempStruct;
 
13078
                                }
 
13079
 
 
13080
                        }
 
13081
                }
 
13082
        }
 
13083
}
 
13084
 
 
13085
function void checkStopAttack()
 
13086
{
 
13087
        if(state != stAttacking){return;}       //exit if doAttack() already called stopAttack()
 
13088
 
 
13089
        if(enemy < 0)
 
13090
        {
 
13091
                MsgBox("checkStopAttack() - enemy < 0");
 
13092
                cancelAttack();
 
13093
                return;
 
13094
        }
 
13095
 
 
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
 
13101
        {
 
13102
                dbg("cancelling attack !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!", me);
 
13103
 
 
13104
                numPlayerAttackers[enemy] = max(minAttackers, numPlayerAttackers[enemy] + random(attackersIncrease));
 
13105
 
 
13106
                numPlayerAttackers[enemy] = min(numPlayerAttackers[enemy], maxAttackers);
 
13107
 
 
13108
                cancelAttack();
 
13109
        }
 
13110
 
 
13111
        //------------------------------------------------------------------------------
 
13112
        //Check we succeeded
 
13113
        //------------------------------------------------------------------------------
 
13114
        else if((phase == phLostBase) and (not canSeePlayerBase(enemy)))        //no enemy structures left (found)
 
13115
        {
 
13116
                dbg("cancelling attack, RTB", me);
 
13117
 
 
13118
                //knowBase[enemy] = FALSE;      //disabled 15.05.05 because phSearchingFor base was skipped because of this
 
13119
 
 
13120
                if(attackingEnemyBase(enemy))
 
13121
                {
 
13122
                        killedBase[enemy] = TRUE;       //remember this one's done, but doesn't have to be completely dead, so no dead[x] = TRUE;
 
13123
                        
 
13124
                        notifyPlayerBaseDestroyed(enemy);
 
13125
                }
 
13126
 
 
13127
                stopAttack();
 
13128
        }
 
13129
}
 
13130
 
 
13131
 
 
13132
function void gatewayDefenses()
 
13133
{
 
13134
        result = numTrucksSameOrder(DORDER_LINEBUILD);
 
13135
 
 
13136
        if(result > 0){return;}         //max 1 truck can be busy with gateway defenses
 
13137
 
 
13138
        droid = closestIdleTruck(baseX, baseY);
 
13139
 
 
13140
        if(droid == NULLOBJECT)
 
13141
        {
 
13142
                return;
 
13143
        }
 
13144
 
 
13145
        bResult = TRUE;
 
13146
 
 
13147
        x = baseX;
 
13148
        y = baseY;
 
13149
 
 
13150
        count = numGatewayDef - 1;
 
13151
        count2 = none;
 
13152
        while(bResult and (count >= 0) )
 
13153
        {
 
13154
                if(isStructureAvailable(gatewayDef[count],me))
 
13155
                {
 
13156
                        count2 = count;
 
13157
                        bResult = FALSE;        //found best one
 
13158
                }
 
13159
                count = count - 1;
 
13160
        }
 
13161
        if(not bResult)
 
13162
        {
 
13163
                skDefenseLocationB(ref x,ref y,wall,gatewayDef[count2],droid,me);
 
13164
        }
 
13165
}
 
13166
 
 
13167
//---------------------------------------------------------
 
13168
//      Store experience
 
13169
//---------------------------------------------------------
 
13170
function void storeBaseDefLocEv()
 
13171
{
 
13172
        if(obj2 == NULLOBJECT)
 
13173
        {
 
13174
                MsgBox("storeBaseDefLocEv - obj2 is NULLOBJECT");
 
13175
                return;
 
13176
        }
 
13177
 
 
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))
 
13180
        {
 
13181
                //move coords closer to base
 
13182
 
 
13183
                //temp = obj.x;
 
13184
                //temp2 = obj.y;
 
13185
 
 
13186
                learnBaseDefendLoc(me, obj2.player, obj2.x, obj2.y);
 
13187
 
 
13188
                storeBaseDefTime[obj2.player] = storeTime;              //start countdown
 
13189
        }
 
13190
 
 
13191
}
 
13192
 
 
13193
function void storeOilDefLocEv()
 
13194
{
 
13195
        if(obj2 == NULLOBJECT)
 
13196
        {
 
13197
                MsgBox("storeOilDefLocEv - obj2 is NULLOBJECT");
 
13198
                return;
 
13199
        }
 
13200
 
 
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))
 
13203
        {
 
13204
                learnOilDefendLoc(me, obj2.player, obj2.x, obj2.y);
 
13205
 
 
13206
                storeOilDefTime[obj2.player] = storeTime;               //start countdown
 
13207
        }
 
13208
}
 
13209
 
 
13210
 
 
13211
//---------------------------------
 
13212
//Go meet ally's force
 
13213
//---------------------------------
 
13214
function void joinForces(int _joinPlayer, int _x, int _y)
 
13215
{
 
13216
        dbg("joining forces with " & _joinPlayer, me);
 
13217
 
 
13218
        setState(stJoiningForces);
 
13219
        enemy = _joinPlayer;
 
13220
        
 
13221
        setPhase(phMoveToLoc, NONE);
 
13222
 
 
13223
        timeGuardPos = 0;               //reset countdown
 
13224
 
 
13225
        updateStateCoord(_x, _y);
 
13226
 
 
13227
        fillAttackers(numAttackersFromPriorty(false));
 
13228
 
 
13229
        msg("coming" , me, enemy);      //allyInThreat
 
13230
}
 
13231
 
 
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)
 
13235
{
 
13236
        local   DROID   _droid;
 
13237
        local   int     _bucket;
 
13238
 
 
13239
        _bucket = initIterateGroupCmd(_coordinateGr,true,true,true);
 
13240
        _droid = iterateGroupCmd(_coordinateGr,_bucket);
 
13241
        while(_droid != NULLOBJECT)
 
13242
        {
 
13243
                /* too far away and not going there */
 
13244
                if(distBetweenTwoPoints(_sendX, _sendY, _droid.x, _droid.y) > _range)
 
13245
                {
 
13246
                        if(_droid.orderx > 0)   //has move order
 
13247
                        {
 
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
 
13250
                                {
 
13251
                                        orderDroidLoc(_droid, _order, _sendX, _sendY);
 
13252
                                }
 
13253
                        }
 
13254
                        else if((_droid.order == DORDER_NONE) or (_droid.order == DORDER_GUARD))        //idle  //TODO: can be idle and have some other order
 
13255
                        {
 
13256
                                orderDroidLoc(_droid, _order, _sendX, _sendY);
 
13257
                        }
 
13258
                }
 
13259
 
 
13260
                _droid = iterateGroupCmd(_coordinateGr,_bucket);
 
13261
        }
 
13262
}
 
13263
 
 
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)
 
13267
{
 
13268
        local   DROID   _droid;
 
13269
        local   bool    _bNewReached;
 
13270
        local   int     _bucket;
 
13271
 
 
13272
        _bNewReached = false;
 
13273
 
 
13274
        _bucket = initIterateGroupCmd(_toCheckGr,true,true,false);
 
13275
        _droid = iterateGroupCmd(_toCheckGr,_bucket);
 
13276
        while(_droid != NULLOBJECT)
 
13277
        {
 
13278
                //Check if reached destination
 
13279
                if(distBetweenTwoPoints(_destX, _destY, _droid.x, _droid.y) <= _range)
 
13280
                {
 
13281
                        dbg("attacker reached", me);
 
13282
 
 
13283
                        _bNewReached = true;            //new unit has reached the destination point
 
13284
 
 
13285
                        if(_toCheckGr == sendAttackGr){
 
13286
                                selectDroid(_droid, FALSE);     //deselect since left sendAttackGr
 
13287
                        }
 
13288
 
 
13289
                        //add droid to the destination group
 
13290
                        if(_droid.droidType == DROID_COMMAND){
 
13291
                                cmdGr[ cmdToIndex(_droid) ] = _toAddToGr;       //change commander group
 
13292
 
 
13293
                                dbg("added commander " & cmdToIndex(_droid) & " to attackGr", me);
 
13294
                        }else{
 
13295
                                groupAddDroid(_toAddToGr, _droid);      //add to the new group
 
13296
                        }
 
13297
                }
 
13298
 
 
13299
                _droid = iterateGroupCmd(_toCheckGr,_bucket);
 
13300
        }
 
13301
 
 
13302
        return _bNewReached;
 
13303
}
 
13304
 
 
13305
function void updateDrop()
 
13306
{
 
13307
        if(dead[enemy])
 
13308
        {
 
13309
                cancelState();  //have to cancel to unload units
 
13310
        }
 
13311
 
 
13312
        updateDropPhase();
 
13313
}
 
13314
 
 
13315
event coordinatePhases(inactive)
 
13316
{
 
13317
        local   int             _sendRange,_sendersOrder,_reachedDestinationRadius,_bucket;
 
13318
        local   bool    _bStopped,_bReachedDestination;
 
13319
 
 
13320
        if(state == stNone)
 
13321
                exit;   //attackers idling
 
13322
 
 
13323
        /* main stuff begins here */
 
13324
        if((enemy < 0) and !defendingOil())
 
13325
        {
 
13326
                MsgBox(" " & me & " coordinatePhases() - no player set");
 
13327
                exit;
 
13328
        }
 
13329
 
 
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)
 
13335
        {
 
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
 
13339
        }
 
13340
        else if(defendingOil())
 
13341
        {
 
13342
                _sendersOrder = DORDER_MOVE;
 
13343
                _reachedDestinationRadius = REACHED_DEF_OIL_RANGE;
 
13344
        }
 
13345
 
 
13346
        if((sendForceX <= 0) or (sendForceY <= 0))
 
13347
        {
 
13348
                if(state == stHelpingAlly)
 
13349
                        msg("I can't see your  base" , me, enemy);      //allyInThreat
 
13350
 
 
13351
                dbg("coordinatePhases - (sendForceX <= 0) or (sendForceY <= 0)", me);
 
13352
                cancelState();
 
13353
                exit;
 
13354
        }
 
13355
 
 
13356
        /* drop phase */
 
13357
        if(state == stDrop)
 
13358
        {
 
13359
                updateDrop();
 
13360
                exit;
 
13361
        }
 
13362
 
 
13363
        /* transport phase */
 
13364
        if(state == stTransporting)
 
13365
        {
 
13366
                updateTransport();
 
13367
                exit;
 
13368
        }
 
13369
 
 
13370
        if(defendingBase())
 
13371
                exit;           //defenders are sent to defend automatically
 
13372
 
 
13373
        /* make sure sendAttackGr droids are going to the destination */
 
13374
        coordinateSendMovement(sendForceX, sendForceY, _sendRange, _sendersOrder, sendAttackGr);
 
13375
 
 
13376
        /* don't drift too far away from the defend location if defending oil or joining forces */
 
13377
        if(phase == phGuardingPos)
 
13378
        {
 
13379
                coordinateSendMovement(sendForceX, sendForceY, _sendRange, DORDER_SCOUT, attackGr);
 
13380
        }
 
13381
 
 
13382
        /* add to attackGr when new sendAttackGr droids reached the destination point */
 
13383
        if(checkReachedDestination(sendForceX, sendForceY, sendAttackGr, attackGr, _reachedDestinationRadius))
 
13384
        {
 
13385
                //New units have been added to the attackGr, assign any unassigned droids to commanders
 
13386
                assignDroidsToBestCommandersFromGroup(attackGr, attackGr);
 
13387
        }
 
13388
 
 
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));
 
13391
 
 
13392
        /* start action when first unit reached the destination point */
 
13393
        if((state == stTakingOil) or (state == stAttacking)
 
13394
                or (state == stHelpingAlly) or defendingOil())
 
13395
        {
 
13396
                if(_bReachedDestination)
 
13397
                {
 
13398
                        dbg("MANAGE UNITS: reached destination !!!!!", me);
 
13399
                        
 
13400
                        setPhase(phAttackingLoc, MINUTE * 10);  //shouldn't take more than 10 mins
 
13401
                }
 
13402
        }
 
13403
        /* start action when *most* of the units are there */
 
13404
        else if(state == stJoiningForces)
 
13405
        {
 
13406
                if(phase == phMoveToLoc)
 
13407
                {
 
13408
                        if(groupSizeCmds(attackGr,true,false,true) >= (groupSizeCmds(sendAttackGr,true,false,true) * 3))        //most of units arrived
 
13409
                        {
 
13410
                                msg("ok, i'm there" , me, enemy);
 
13411
                                timeGuardPos = maxTimeGuardPos;
 
13412
                                
 
13413
                                setPhase(phGuardingPos, NONE);
 
13414
 
 
13415
                                //exit;                         //must exit since vars are reset
 
13416
                        }
 
13417
                }
 
13418
        }
 
13419
 
 
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))
 
13423
        {
 
13424
                dbg("no attackers, phase = phMoveToLoc !!!!!!!!", me);
 
13425
                
 
13426
                setPhase(phMoveToLoc, NONE);
 
13427
                
 
13428
                timeGuardPos = 0;               //reset the oil guarding time
 
13429
        }
 
13430
 
 
13431
 
 
13432
        /* Manage attack */
 
13433
        if((state != stHelpingAlly) and ((phase == phAttackingLoc)
 
13434
                or (phase == phGuardingPos)))   //we are at the destination, stHelpingAlly is handled in manageHelpAlly()
 
13435
        {
 
13436
                _bucket = initIterateGroupCmd(attackGr,true,true,true);
 
13437
                droid = iterateGroupCmd(attackGr,_bucket);
 
13438
                while(droid != NULLOBJECT)
 
13439
                {
 
13440
                        //find a target to attack
 
13441
                        if(droid.weapon == weaponBB){
 
13442
                                findBBAttackBaseTarget(droid);
 
13443
                        }else{
 
13444
                                findAttackBaseTarget(droid, -1, -1, -1);
 
13445
                        }
 
13446
 
 
13447
                        //attack enemy target
 
13448
                        if(retObj != NULLOBJECT){
 
13449
                                orderDroidObj(droid, DORDER_ATTACK, retObj);
 
13450
                        }
 
13451
 
 
13452
                        //too far from attack location?
 
13453
                        //if( droidOrderIdle(droid) or !droidActionAttacking(droid) )
 
13454
                        if( droidOrderIdle(droid))
 
13455
                        {
 
13456
                                //set range
 
13457
                                if(objHasWeapon(droid)){
 
13458
                                        range = objWeaponMaxRange(droid);
 
13459
                                }else{  //repairs etc
 
13460
                                        range = (TILE * 8);
 
13461
                                }
 
13462
 
 
13463
                                // allow to travel further away if attacking or repairing
 
13464
                                if(droidActionAttacking(droid) or droidActionDroidRepair(droid)){
 
13465
                                        range = range + (TILE * 12);
 
13466
                                }
 
13467
 
 
13468
                                if(distBetweenTwoPoints(droid.x, droid.y, sendForceX, sendForceY) > range)
 
13469
                                {
 
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
 
13473
                                        {
 
13474
                                                dbg("too far from attack loc, send back", me);
 
13475
                                                orderDroidLoc(droid, DORDER_SCOUT, sendForceX, sendForceY);
 
13476
                                        }
 
13477
                                }
 
13478
                        }
 
13479
 
 
13480
                        droid = iterateGroupCmd(attackGr,_bucket);
 
13481
                }
 
13482
        }
 
13483
 
 
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
 
13486
        {
 
13487
                if(not knowBase[enemy])         //no visible structures left for this player
 
13488
                {
 
13489
                        //if(state == stHelpingAlly)
 
13490
                        //{
 
13491
                                msg("I don't see your  base" , me, enemy);      //allyInThreat
 
13492
                        //}
 
13493
 
 
13494
                        dbg("coordinatePhases - not haveBase", me);
 
13495
                        stopAllyDefense();
 
13496
                        exit;
 
13497
                }
 
13498
 
 
13499
                //did player disally while we are helping him?
 
13500
                if(not ally[enemy])             //no visible structures left for this player
 
13501
                {
 
13502
                        msg("backstabber!!!", me, enemy);       //allyInThreat
 
13503
                        breakAlliance(me, enemy);
 
13504
                        cancelAllyDefense();
 
13505
                        exit;
 
13506
                }
 
13507
        }
 
13508
        else if(state == stTakingOil)
 
13509
        {
 
13510
                //see if it's hopeless to go on
 
13511
                if((groupSizeCmds(sendAttackGr,true,false,true) +
 
13512
                        groupSizeCmds(attackGr,true,false,true)) < minOilAttackers)
 
13513
                {
 
13514
                        dbg("TAKE OIL: little attackers left, cancel", me);
 
13515
 
 
13516
                        taunt(enemy, TAUNT_FAILURE, 30);
 
13517
 
 
13518
                        stopTakingOil();
 
13519
 
 
13520
                        exit;
 
13521
                }
 
13522
 
 
13523
                //see if we can stop guarding this oil resource already
 
13524
                if(!_bStopped and (phase == phGuardingPos) and (timeGuardPos <= 0))             //guarding oil long enough
 
13525
                {
 
13526
                        dbg("TAKE OIL: waiting time is up!!!!!!!!!!!!!", me);
 
13527
 
 
13528
                        taunt(enemy, TAUNT_SUCCESS, 20);
 
13529
 
 
13530
                        stopTakingOil();
 
13531
 
 
13532
                        exit;
 
13533
                }
 
13534
 
 
13535
                /* something went wrong or we failed */
 
13536
                if(!_bStopped and tTakeOil <= 0)
 
13537
                {
 
13538
                        dbg("TAKE OIL: takeoil timeout!!!!!!!!!!!!!", me);
 
13539
 
 
13540
                        stopTakingOil();
 
13541
                        exit;
 
13542
                }
 
13543
 
 
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
 
13547
                {
 
13548
                        //if(numEnemyObjInRange(me, sendForceX, sendForceY, (8 * 128), FALSE) == 0)
 
13549
                        if(numEnemyWeapObjInRange(me, sendForceX, sendForceY, (8 * 128), false, true) == 0)
 
13550
                        {
 
13551
                                dbg("TAKE OIL: oil is well-defended, rtb!!!!!!!!!!!!!", me);
 
13552
                                stopTakingOil();
 
13553
                                exit;
 
13554
                        }
 
13555
                } */
 
13556
 
 
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))
 
13561
                {
 
13562
                        dbg("TAKE OIL: they have more than us", me);
 
13563
 
 
13564
                        taunt(enemy, TAUNT_FAILURE, 40);
 
13565
 
 
13566
                        stopTakingOil();
 
13567
                        exit;
 
13568
                }
 
13569
 
 
13570
 
 
13571
                //see if we killed all defenses and can start guard oil countdown
 
13572
                if(!_bStopped and (phase != phGuardingPos))     //not set yet
 
13573
                {
 
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)
 
13576
                        {
 
13577
                                if(groupSizeCmds(attackGr,true,false,true) > 0) //if we reached destination
 
13578
                                {
 
13579
                                        taunt(enemy, TAUNT_SUCCESS, 40);
 
13580
 
 
13581
                                        dbg("TAKE OIL: no enemies, started guarding", me);
 
13582
                                        timeGuardPos = maxTimeGuardPos;
 
13583
                                        
 
13584
                                        setPhase(phGuardingPos, NONE);
 
13585
                                }
 
13586
                        }
 
13587
                }
 
13588
 
 
13589
                if(_bStopped)
 
13590
                {
 
13591
                        if(canStartTakingOil() and (THROW_DICE <= CHANCE_COUNTER_OIL)) // enough units?
 
13592
                        {
 
13593
                                if(initializeStartTakingOil(sendForceX, sendForceY, MAX_COUNTER_OIL_DISTANCE))
 
13594
                                {
 
13595
                                        exit;   // exit here if we started attacking enemy oil
 
13596
                                }
 
13597
                        }
 
13598
                }
 
13599
 
 
13600
                if(_bStopped)
 
13601
                {
 
13602
                        exit;
 
13603
                }
 
13604
        }
 
13605
        else if(state == stJoiningForces)       //check if waited long enougn
 
13606
        {
 
13607
                /* see if we can stop waiting at joining pos already */
 
13608
                if((phase == phGuardingPos) and (timeGuardPos <= 0))
 
13609
                {
 
13610
                        dbg("JOIN FORCES: waiting time is up!!!!!!!!!!!!!", me);
 
13611
                        if(random(2) == 1)
 
13612
                        {
 
13613
                                msg("I'm going back" , me, enemy);
 
13614
                        }
 
13615
                        stopJoiningForces();
 
13616
                        exit;
 
13617
                }
 
13618
        }
 
13619
        else if(defendingOil())
 
13620
        {
 
13621
                // sucess is handled in everySecEv()
 
13622
 
 
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)
 
13626
                {
 
13627
                        dbg("DEFENDING OIL: little attackers left, cancel", me);
 
13628
 
 
13629
                        taunt(enemy, TAUNT_POSSESSION_LOSS, 50);
 
13630
 
 
13631
                        stopDefendingOil();
 
13632
                        _bStopped = true;
 
13633
                }
 
13634
 
 
13635
                // see if we want to counter-oil
 
13636
                if(_bStopped and (state == stNone))     // if idle
 
13637
                {
 
13638
                        if(canStartTakingOil() and (THROW_DICE <= CHANCE_COUNTER_OIL)) // enough units?
 
13639
                        {
 
13640
                                if(initializeStartTakingOil(sendForceX, sendForceY, MAX_COUNTER_OIL_DISTANCE))
 
13641
                                {
 
13642
                                        exit;   // exit here if we started attacking enemy oil
 
13643
                                }
 
13644
                        }
 
13645
                }
 
13646
 
 
13647
                //must exit here, since stopped defending oil
 
13648
                if(_bStopped)
 
13649
                {
 
13650
                        exit;
 
13651
                }
 
13652
        }
 
13653
 
 
13654
        /* check if we can send reinforcements, use more units if state == stHelpingAlly */
 
13655
        if(canSendReinf(state == stHelpingAlly))                //got enough
 
13656
        {
 
13657
                fillReinforcements(state == stHelpingAlly);
 
13658
        }
 
13659
}
 
13660
 
 
13661
function void saveExperience()
 
13662
{
 
13663
        if(not bLearn){return;}
 
13664
 
 
13665
        savePlayerAIExperience(me, FALSE);      //silent save
 
13666
 
 
13667
        timeSaveExperience = maxTimeSaveExperience;
 
13668
 
 
13669
        dbg("Saved AI Experience (*)", me);
 
13670
}
 
13671
 
 
13672
/* Returns name of the passed group */
 
13673
function string groupToString(GROUP _group)
 
13674
{
 
13675
        local   string  _sGroup;
 
13676
 
 
13677
        _sGroup = "Unknown";
 
13678
 
 
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";
 
13695
        }
 
13696
        return _sGroup;
 
13697
}
 
13698
 
 
13699
function string droidToGroupName(DROID _droid)
 
13700
{
 
13701
        local   GROUP   _group;
 
13702
 
 
13703
        if(_droid.droidType == DROID_COMMAND){
 
13704
                return groupToString( cmdGr[ cmdToIndex(_droid) ] );
 
13705
        }
 
13706
 
 
13707
        return groupToString( _droid.group );
 
13708
}
 
13709
 
 
13710
//---------------------------------------------------------
 
13711
//Don't trigger experience callbacks too frequently
 
13712
//---------------------------------------------------------
 
13713
event everySecEv(inactive)
 
13714
{
 
13715
        local   float           _newCurResUrgency;
 
13716
        
 
13717
        if(tPhase > 0)
 
13718
        {
 
13719
                tPhase--;
 
13720
                if(tPhase == 0)
 
13721
                {
 
13722
                        stopState();
 
13723
                        dbg("phase timeout", me);
 
13724
                }
 
13725
        }
 
13726
 
 
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
 
13732
        } */
 
13733
 
 
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)))
 
13737
        {
 
13738
                if(!defendingOil())
 
13739
                {
 
13740
                        resetOilDefendCoords();
 
13741
 
 
13742
                        dbg("derrick siege threat timed out", me);
 
13743
                }
 
13744
                else if(defendingOil())
 
13745
                {
 
13746
                        // make sure threat is really gone
 
13747
                        if(numFriendlyWeapStructsInRange(me, sendForceX, sendForceY,  (8 * TILE), true) >= 1)
 
13748
                        {
 
13749
                                if(numEnemyWeapObjInRange(me, sendForceX, sendForceY, (8 * TILE), false, true) == 0)
 
13750
                                {
 
13751
                                        taunt(enemy, TAUNT_SUCCESS, 70);
 
13752
 
 
13753
                                        stopDefendingOil();
 
13754
 
 
13755
                                        dbg("THREAT IS GONE - STOPPED DEFENDING OIL", me);
 
13756
                                }
 
13757
                        }
 
13758
                }
 
13759
        }
 
13760
 
 
13761
 
 
13762
 
 
13763
        if(watchWindowDebug == WATCH_DEBUG_CMDS)
 
13764
        {
 
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);
 
13769
 
 
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)
 
13773
                {
 
13774
                        setDebugMenuEntry("cmd0:" , 1);
 
13775
                }else{
 
13776
                        setDebugMenuEntry("cmd0: " & cmds[0].group.members & "/" & cmdDroidMaxGroup(cmds[0]) & " - " & getDroidRank(cmds[0]) & " - " & droidToGroupName(cmds[0]) , 1);
 
13777
                }
 
13778
                if(cmds[1] == NULLOBJECT)
 
13779
                {
 
13780
                        setDebugMenuEntry("cmd1:" , 2);
 
13781
                }else{
 
13782
                        setDebugMenuEntry("cmd1: " & cmds[1].group.members & "/" & cmdDroidMaxGroup(cmds[1]) & " - " & getDroidRank(cmds[1]) & " - " & droidToGroupName(cmds[1])  , 2);
 
13783
                }
 
13784
                if(cmds[2] == NULLOBJECT)
 
13785
                {
 
13786
                        setDebugMenuEntry("cmd2:" , 3);
 
13787
                }else{
 
13788
                        setDebugMenuEntry("cmd2: " & cmds[2].group.members & "/" & cmdDroidMaxGroup(cmds[2]) & " - " & getDroidRank(cmds[2]) & " - " & droidToGroupName(cmds[2])  , 3);
 
13789
                }
 
13790
                if(cmds[3] == NULLOBJECT)
 
13791
                {
 
13792
                        setDebugMenuEntry("cmd3:" , 4);
 
13793
                }else{
 
13794
                        setDebugMenuEntry("cmd3: " & cmds[3].group.members & "/" & cmdDroidMaxGroup(cmds[3]) & " - " & getDroidRank(cmds[3]) & " - " & droidToGroupName(cmds[3])  , 4);
 
13795
                }
 
13796
                if(cmds[4] == NULLOBJECT)
 
13797
                {
 
13798
                        setDebugMenuEntry("cmd4:" , 5);
 
13799
                }else{
 
13800
                        setDebugMenuEntry("cmd4: " & cmds[4].group.members & "/" & cmdDroidMaxGroup(cmds[4]) & " - " & getDroidRank(cmds[4]) & " - " & droidToGroupName(cmds[4])  , 5);
 
13801
                }
 
13802
 
 
13803
                //Display group of the selected droid
 
13804
                setDebugMenuEntry("unit group:" , 6);
 
13805
                InitEnumDroids(me, me);
 
13806
                droid = EnumDroid();
 
13807
                while(droid != NULLOBJECT)
 
13808
                {
 
13809
                        if(droid.selected){
 
13810
                                setDebugMenuEntry("unit group: " & droidToGroupName(droid), 6);
 
13811
                                droid = NULLOBJECT;
 
13812
                        }else{
 
13813
                                droid = EnumDroid();
 
13814
                        }
 
13815
                }
 
13816
        }
 
13817
 
 
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
 
13822
        {
 
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
 
13825
                }
 
13826
        }
 
13827
        else if(_newCurResUrgency < fMinResUrgency)             //going outside of the lowest boundry
 
13828
        {
 
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
 
13831
                }
 
13832
        }
 
13833
 
 
13834
        fCurResUrgency = _newCurResUrgency;             //Update
 
13835
 
 
13836
        /* Update duration of current state */
 
13837
        tState++;
 
13838
 
 
13839
        /* Update Reinforcement Countdown */
 
13840
        if(reinfTime > 0)
 
13841
                reinfTime = reinfTime - 1;
 
13842
 
 
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)
 
13845
        {
 
13846
                tLasSat = tLasSat + 1;          //continue recharging
 
13847
        }
 
13848
 
 
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)
 
13852
        {
 
13853
                tLasSatCountdown = tLasSatCountdown - 1;
 
13854
        }
 
13855
 
 
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 */
 
13857
/*
 
13858
        if(lasSatState[me] == lsDelayedFiring)
 
13859
        {
 
13860
                if(tLasSatCountdown <= 0)
 
13861
                {
 
13862
                        lasSatTarget = findLasSatTarget(lasSatEnemy);
 
13863
                        if(lasSatTarget != NULLOBJECT)
 
13864
                        {
 
13865
                                fireLasSat(lasSatTarget);
 
13866
                        }
 
13867
                }
 
13868
        }
 
13869
*/
 
13870
 
 
13871
 
 
13872
        if(helpTime > 0)
 
13873
                helpTime = helpTime - 1;
 
13874
 
 
13875
        if(timeGuardPos > 0)
 
13876
                timeGuardPos = timeGuardPos - 1;
 
13877
 
 
13878
        if(requestHelpTime > 0)
 
13879
                requestHelpTime = requestHelpTime - 1;
 
13880
 
 
13881
        if(collectTime > 0)
 
13882
                collectTime = collectTime - 1;
 
13883
 
 
13884
        if(timeNotifyEnemyInBase > 0)
 
13885
                timeNotifyEnemyInBase = timeNotifyEnemyInBase - 1;
 
13886
 
 
13887
        if(tWaitAlliesDrop > 0)
 
13888
                tWaitAlliesDrop = tWaitAlliesDrop - 1;
 
13889
 
 
13890
        if(tWaitLoadDrop > 0)
 
13891
                tWaitLoadDrop = tWaitLoadDrop - 1;
 
13892
 
 
13893
        if(tSyncDrop > 0)
 
13894
                tSyncDrop = tSyncDrop - 1;
 
13895
 
 
13896
        if(tTakeOil > 0)
 
13897
                tTakeOil = tTakeOil - 1;
 
13898
 
 
13899
        if(timeSaveExperience > 0)
 
13900
        {
 
13901
                timeSaveExperience = timeSaveExperience - 1;
 
13902
 
 
13903
                if(timeSaveExperience <= 0)
 
13904
                {
 
13905
                        saveExperience();
 
13906
                }
 
13907
        }
 
13908
 
 
13909
        if(notifyReadyAttackTime > 0)
 
13910
        {
 
13911
                notifyReadyAttackTime = notifyReadyAttackTime - 1;
 
13912
 
 
13913
                if(notifyReadyAttackTime == 0)  //remember countdown is finished
 
13914
                {
 
13915
                        bNotifiedReadyAttack = TRUE;
 
13916
                        dbg("bNotifiedReadyAttack == TRUE", me);
 
13917
                }
 
13918
        }
 
13919
 
 
13920
        //store exrepience countdown for every player
 
13921
        _temp = 0;
 
13922
        while(_temp < multiPlayerMaxPlayers)
 
13923
        {
 
13924
                if(storeOilDefTime[_temp] > 0)
 
13925
                {
 
13926
                        storeOilDefTime[_temp] = storeOilDefTime[_temp] - 1;
 
13927
                }
 
13928
 
 
13929
                if(storeBaseDefTime[_temp] > 0)
 
13930
                {
 
13931
                        storeBaseDefTime[_temp] = storeBaseDefTime[_temp] - 1;
 
13932
                }
 
13933
 
 
13934
                if(allyOfferTime[_temp] > 0)
 
13935
                {
 
13936
                        allyOfferTime[_temp] = allyOfferTime[_temp] - 1;
 
13937
                }
 
13938
 
 
13939
                if(tRequestStatus[_temp] > 0)
 
13940
                {
 
13941
                        tRequestStatus[_temp] = tRequestStatus[_temp] - 1;
 
13942
                }
 
13943
 
 
13944
                if(tWaitPlayerReply[_temp] > 0)
 
13945
                {
 
13946
                        tWaitPlayerReply[_temp] = tWaitPlayerReply[_temp] - 1;
 
13947
                }
 
13948
 
 
13949
                _temp = _temp + 1;
 
13950
        }
 
13951
 
 
13952
        tLastResearch++;        //will be reset by doResearch if research is not idle
 
13953
 
 
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
 
13959
        {
 
13960
                if(tState == 6) // do only once per idle state
 
13961
                {
 
13962
                        notifyIdle(false);
 
13963
                }
 
13964
        }
 
13965
}
 
13966
 
 
13967
function bool canFollowAttackRequest(int _attackRequester, bool _bHighPriorityTask)
 
13968
{
 
13969
        if(defendingBase() or (state == stAttacking) or
 
13970
                (state == stDrop) or (state == stTransporting) or
 
13971
                ((state == stHelpingAlly) and (enemy != _attackRequester)))
 
13972
        {
 
13973
                notifyStatus(_attackRequester);
 
13974
                return(FALSE);
 
13975
        }
 
13976
 
 
13977
        if(not haveTheoreticallyMinAttackers(_bHighPriorityTask))
 
13978
        {
 
13979
                msg("let me get more units", me, _attackRequester);
 
13980
                return(FALSE);
 
13981
        }
 
13982
 
 
13983
        return(TRUE);
 
13984
}
 
13985
 
 
13986
function bool isCurrentOrder(int _state, int _enemy)
 
13987
{
 
13988
        local int _dummy;       //FIXME
 
13989
        _dummy = 0;
 
13990
        return ((_state == state) and (enemy == _enemy));
 
13991
}
 
13992
 
 
13993
/* Check if we are attacking some soecific (or any) enemy base */
 
13994
function bool attackingEnemyBase(int _enemy)
 
13995
{
 
13996
        return ((state == stAttacking) and (attackReason == ATTACK_BASE) and
 
13997
                        ( (enemy == _enemy) or (_enemy == ANY) ));              // match the enemy
 
13998
}
 
13999
 
 
14000
/* Returns true if we are attacking enemy arty location */
 
14001
function bool counteringArty()
 
14002
{
 
14003
        return ((state == stAttacking) and (attackReason == ATTACK_COUNTER_ARTY));
 
14004
}
 
14005
 
 
14006
function bool idling()
 
14007
{
 
14008
        return (state == stNone);
 
14009
}
 
14010
 
 
14011
function bool defendingBase()
 
14012
{
 
14013
        return (state == stDefendingBase);
 
14014
}
 
14015
 
 
14016
function bool helpingAlly()
 
14017
{
 
14018
        return (state == stHelpingAlly);
 
14019
}
 
14020
 
 
14021
function bool defendingOil()
 
14022
{
 
14023
        return (state == stDefendingOil);
 
14024
}
 
14025
 
 
14026
function bool canAlly(int _player)
 
14027
{
 
14028
        if(allianceExistsBetween(_player ,me))
 
14029
        {
 
14030
                return(FALSE);          //already allied
 
14031
        }
 
14032
 
 
14033
        /* check if attacked by this player */
 
14034
        if(defendingBase())
 
14035
        {
 
14036
                if(numPlayerWeapObjInRange(_player, me, baseX, baseY, baseRange + (5 * 128), false, true) > 5)  //attacking us
 
14037
                {
 
14038
                        return(TRUE);
 
14039
                }
 
14040
        }
 
14041
 
 
14042
        if((state != stNone) and (enemy == _player))
 
14043
        {
 
14044
                return(FALSE);
 
14045
        }
 
14046
 
 
14047
        /* check not allied to too many players already */
 
14048
        if((numAllies(me) + 1) >= (multiPlayerMaxPlayers / 2))
 
14049
        {
 
14050
                return(FALSE);
 
14051
        }
 
14052
 
 
14053
        return(TRUE);
 
14054
}
 
14055
 
 
14056
//decide if last beacon was placed long ago
 
14057
function bool beaconTimeout(int _player)
 
14058
{
 
14059
                if((tBeacon[_player] > 0) and (( tBeacon[_player] + tBeaconTimeout) < GAME_TIME_IN_SECS))       //not too long ago
 
14060
                {
 
14061
                        return TRUE;    //this beacon is still 'fresh'
 
14062
                }
 
14063
 
 
14064
                return FALSE;
 
14065
}
 
14066
 
 
14067
function bool haveBeacon(int _player)
 
14068
{
 
14069
                if((tBeacon[_player] > 0) and (not beaconTimeout(_player)))
 
14070
                {
 
14071
                        return TRUE;    //have beacon for this player
 
14072
                }
 
14073
 
 
14074
                return FALSE;
 
14075
}
 
14076
 
 
14077
function void makeAlliances()
 
14078
{
 
14079
        /* find closest player */
 
14080
        temp = bestAlliancePlayer();
 
14081
        if(temp == none)
 
14082
        {
 
14083
                temp = random(multiPlayerMaxPlayers);
 
14084
        }
 
14085
 
 
14086
        if(temp == me){return;}
 
14087
        if(allianceExistsBetween(me, temp)){return;}    //my ally
 
14088
        if(allyOfferTime[temp] > 0){return;}            //offered already
 
14089
 
 
14090
 
 
14091
        /* don't offer alliance to a player we are attacking */
 
14092
        if((state != stNone) and (enemy == temp))
 
14093
        {
 
14094
                return;
 
14095
        }
 
14096
 
 
14097
        doOfferAlliance(temp);
 
14098
}
 
14099
 
 
14100
function void doOfferAlliance(int _alliancePlayer)
 
14101
{
 
14102
        allyOfferTime[_alliancePlayer] = maxAllyOfferTime;
 
14103
 
 
14104
        msg("ally?" , me, _alliancePlayer);
 
14105
}
 
14106
 
 
14107
function int bestAlliancePlayer()
 
14108
{
 
14109
        //return        - closest enemy index
 
14110
        retInt = none;
 
14111
 
 
14112
        _temp3 = 99999;
 
14113
        _temp = 0;
 
14114
        _temp4 = 0;
 
14115
        while(_temp < multiPlayerMaxPlayers)
 
14116
        {
 
14117
                if(knowBase[_temp] and (not dead[_temp]) and (not allianceExistsBetween(me, _temp)) and (_temp != me))
 
14118
                {
 
14119
                        if(allyOfferTime[_temp] <= 0)
 
14120
                        {
 
14121
                                if(not((state != stNone) and (enemy == _temp)))         //attacking him?
 
14122
                                {
 
14123
                                        intOK[_temp4] = _temp;  //store this one
 
14124
                                        _temp4 = _temp4 + 1;    //how many available
 
14125
 
 
14126
                                        _temp2 = distBetweenTwoPoints(baseX, baseY, curBase[_temp][0], curBase[_temp][1]);
 
14127
                                        if(_temp2 < _temp3)
 
14128
                                        {
 
14129
                                                _temp3 = _temp2;
 
14130
                                                retInt = _temp;         //remember closest
 
14131
                                        }
 
14132
                                }
 
14133
                        }
 
14134
                }
 
14135
 
 
14136
                _temp = _temp + 1;
 
14137
        }
 
14138
 
 
14139
        if((_temp4 > 0) and (random(4) <= 1))   //found at least 1 and 50%
 
14140
        {
 
14141
                retInt = intOK[random(_temp4)];         //choose one of the available
 
14142
        }
 
14143
 
 
14144
 
 
14145
        return(retInt);         //return closest or random available
 
14146
}
 
14147
 
 
14148
event allianceOffered(inactive)
 
14149
{
 
14150
        if(temp2 != me){exit;}  //offered not to me
 
14151
 
 
14152
        //if(DEBUG_MSG and (not isHumanPlayer(temp))){exit;}    //don't ally with AIs for now
 
14153
 
 
14154
        if(not canAlly(temp))           //shouldn't ally
 
14155
        {
 
14156
                exit;
 
14157
        }
 
14158
 
 
14159
        doAlly(temp);
 
14160
}
 
14161
 
 
14162
event droidSeen(inactive)
 
14163
{
 
14164
        //droid - that was seen
 
14165
        //obj   - who saw
 
14166
 
 
14167
        if(droid == NULLOBJECT)
 
14168
        {
 
14169
                exit;
 
14170
        }
 
14171
 
 
14172
        if(not isVtol(droid))
 
14173
        {
 
14174
                exit;
 
14175
        }
 
14176
 
 
14177
        if(not hasVTOLs[droid.player])
 
14178
        {
 
14179
                hasVTOLs[droid.player] = TRUE;
 
14180
 
 
14181
                dbg(getPlayerName(droid.player) & " got VTOLs", me);
 
14182
 
 
14183
                /* notify allies about enemy using VTOLs */
 
14184
                if(not allianceExistsBetween(me, droid.player))
 
14185
                {
 
14186
                        notifyPlayerHasVTOLs(droid.player);
 
14187
                }
 
14188
        }
 
14189
}
 
14190
 
 
14191
event objectSeen(inactive)
 
14192
{
 
14193
        //obj   - what was seen
 
14194
        //obj2  - who saw
 
14195
 
 
14196
        if((obj == NULLOBJECT) or (obj2 == NULLOBJECT))
 
14197
        {
 
14198
                exit;
 
14199
        }
 
14200
 
 
14201
        if((obj.player > 7) or (obj2.player > 7))       //skip scavengers
 
14202
        {
 
14203
                exit;
 
14204
        }
 
14205
 
 
14206
        /* ignore walls and defenses */
 
14207
        if(obj.type == OBJ_STRUCTURE)
 
14208
        {
 
14209
                _structure = objToStructure(obj);
 
14210
 
 
14211
                temp = getStructureType(_structure);
 
14212
                if((_temp == 7) or (_temp == 8) or (_temp == 6) or (_temp == 6))        //wall, cornerwall, defense, rearm
 
14213
                {
 
14214
                        exit;
 
14215
                }
 
14216
        }
 
14217
 
 
14218
        if(dead[obj.player])    //if we thought he was dead
 
14219
        {
 
14220
                rememberPlayerIsAlive(obj.player);
 
14221
 
 
14222
                //dbg("saw player " & obj.player & "'s object at " & (obj.x / 128) & " - " & (obj.y / 128), me);
 
14223
                notifyPlayerAlive(obj.player);
 
14224
        }
 
14225
}
 
14226
 
 
14227
function void rememberPlayerIsAlive(int _alivePlayer)
 
14228
{
 
14229
        if(gameTime < 200){return;}     //engine bugs at startup
 
14230
 
 
14231
        dbg(getPlayerName(_alivePlayer) & " IS ALIVE!!!!!!!!!+++++++++++", me);
 
14232
 
 
14233
        dead[_alivePlayer] = FALSE;
 
14234
        killedBase[_alivePlayer] = FALSE;
 
14235
}
 
14236
 
 
14237
function void doAlly(int _playerOffered)
 
14238
{
 
14239
        createAlliance(_playerOffered, me);
 
14240
 
 
14241
        ally[_playerOffered] = TRUE;
 
14242
        allyOfferTime[_playerOffered] = 0;      //reset, when disally, can immediately offer alliance again
 
14243
 
 
14244
        if((state != stNone) and (enemy == _playerOffered))
 
14245
        {
 
14246
                stopState();    //stop if were attacking him
 
14247
        }
 
14248
 
 
14249
        /* Request help if in danger */
 
14250
        if(state != stNone)
 
14251
        {
 
14252
                notifyStatus(_playerOffered);
 
14253
        }
 
14254
}
 
14255
 
 
14256
function void buildAA()
 
14257
{
 
14258
        best = findBestAA();
 
14259
        if(best == none){return;}
 
14260
 
 
14261
        range = MAX_BASE_PERIM_RANGE;   //too many on spot range
 
14262
 
 
14263
        temp = 0;
 
14264
        while(temp < multiPlayerMaxPlayers)
 
14265
        {
 
14266
                if(!allianceExistsBetween(me, temp))
 
14267
                {
 
14268
                                if(knowBase[temp] and !dead[temp] and hasVTOLs[temp])   //found his base and saw him using VTOLs
 
14269
                                {
 
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);
 
14273
 
 
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)
 
14276
                                        {
 
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))
 
14280
                                                {
 
14281
                                                        return;
 
14282
                                                }
 
14283
 
 
14284
                                                if(distBetweenTwoPoints(buildX, buildY, x, y) > range)  //build loc moved too far away
 
14285
                                                {
 
14286
                                                        return; //original site was probably blocked, don't build too far away from orig site
 
14287
                                                }
 
14288
 
 
14289
                                                /* it worked, build AA */
 
14290
                                                buildOnMap(AA[best], buildX, buildY, 2);
 
14291
                                        }
 
14292
                                }
 
14293
                }
 
14294
                temp++;
 
14295
        }
 
14296
}
 
14297
 
 
14298
function int findBestAA()
 
14299
{
 
14300
        //return        - defense index
 
14301
 
 
14302
        /* find best defense */
 
14303
        _temp2 = none;
 
14304
        _temp = 0;
 
14305
        while(_temp < numAA)
 
14306
        {
 
14307
                if(isStructureAvailable(AA[_temp],me))
 
14308
                {
 
14309
                        _temp2 = _temp;         //Best defense
 
14310
                }
 
14311
                _temp = _temp + 1;
 
14312
        }
 
14313
 
 
14314
        return(_temp2);
 
14315
}
 
14316
 
 
14317
event consoleEv(consoleTr)
 
14318
{
 
14319
 
 
14320
        //turn on 'autogame'
 
14321
        if(cstr == "autogame on" && (msgPlayer2 == me))
 
14322
        {
 
14323
                if(debugModeEnabled() && myResponsibility(me))
 
14324
                {
 
14325
                        if(not bRunning)                //make sure current machine is responsible for this AI and it's not already active
 
14326
                        {
 
14327
                                console(getPlayerName(me) & " activated");
 
14328
                                mainInitialize();
 
14329
                        }
 
14330
                }
 
14331
        }
 
14332
 
 
14333
        //turn off 'autogames'
 
14334
        if(cstr == "autogame off" && debugModeEnabled()  && (msgPlayer2 == me))
 
14335
        {
 
14336
                if(bRunning)            //make sure this AI is active
 
14337
                {
 
14338
                        console(getPlayerName(me) & " deactivated");
 
14339
 
 
14340
                        shutDown();
 
14341
                }
 
14342
        }
 
14343
 
 
14344
        if(not DEBUG_MSG){exit;}
 
14345
        if(!debugModeEnabled()){exit;}
 
14346
 
 
14347
        if(strcmp(cstr, "/baserange"))
 
14348
        {
 
14349
                dbg("baseRange: " & (baseRange / 128), me);
 
14350
        }
 
14351
        else if(strcmp(cstr, "/request help"))
 
14352
        {
 
14353
                requestHelp(baseX, baseY);
 
14354
        }
 
14355
        else if(strcmp(cstr, "/defendcoord"))
 
14356
        {
 
14357
                dbg("x: " & (groupCMD_x(defendGr) / 128) & " y: " & (groupCMD_y(defendGr) / 128), me);
 
14358
        }
 
14359
        else if(strcmp(cstr, "/state"))
 
14360
        {
 
14361
                dbg("state: " & state, me);
 
14362
        }
 
14363
        else if(strcmp(cstr, "/phase"))
 
14364
        {
 
14365
                dbg("phase: " & phase, me);
 
14366
        }
 
14367
        else if(strcmp(cstr, "/stop"))
 
14368
        {
 
14369
                stopState();
 
14370
        }
 
14371
        else if(strcmp(cstr, "/cancel"))
 
14372
        {
 
14373
                cancelState();
 
14374
        }
 
14375
        else if(strcmp(cstr, "/numtrucks"))
 
14376
        {
 
14377
                _temp2 = numBuildersInProduction(me);
 
14378
                _temp = groupSizeCmds(buildGr,true,false,true);
 
14379
                dbg("Trucks: " & _temp & "/" & _temp2, me);
 
14380
        }
 
14381
        else if(strcmp(cstr, "/see enemy?"))
 
14382
        {
 
14383
                if(enemy >= 0)
 
14384
                        dbg("seeBase[" & enemy & "] = " & canSeePlayerBase(enemy), me);
 
14385
 
 
14386
                if(enemy == none)
 
14387
                        dbg("no enemy", me);
 
14388
        }
 
14389
        else if(strcmp(cstr, "/addallylassat"))
 
14390
        {
 
14391
                _temp = 0;
 
14392
                while(_temp < 8)
 
14393
                {
 
14394
                        if(allianceExistsBetween(_temp ,me) and me != _temp)
 
14395
                        {
 
14396
                                x = curBase[_temp][0];
 
14397
                                y = curBase[_temp][0];
 
14398
                                if(pickStructLocation(lasSat, ref x, ref y, _temp))
 
14399
                                {
 
14400
                                        addStructure( lasSat, _temp, x, y);
 
14401
                                }
 
14402
                        }
 
14403
                        _temp = _temp + 1;
 
14404
                }
 
14405
        }
 
14406
        else if(strcmp(cstr, "/addlassat"))
 
14407
        {
 
14408
                x = baseX;
 
14409
                y = baseY;
 
14410
                if(pickStructLocation(lasSat, ref x, ref y, me))
 
14411
                {
 
14412
                        addStructure(lasSat, me, x, y);
 
14413
                        lasSatState[me] = lsRecharging;
 
14414
                }
 
14415
        }
 
14416
        else if(strcmp(cstr, "/numfacs"))
 
14417
        {
 
14418
                temp = getNumStructures(fac,me);
 
14419
                dbg("num facs: " & temp, me);
 
14420
        }
 
14421
        else if(strcmp(cstr, "/numtransp"))
 
14422
        {
 
14423
                dbg("numTransporters: " & numTransporters, me);
 
14424
        }
 
14425
        else if(strcmp(cstr, "/transpstatus"))
 
14426
        {
 
14427
                _temp = transporterCapacity(transporter[0]);
 
14428
                dbg("action: " & transporter[0].action & ", order: " & transporter[0].order & ", capacity :" & _temp, me);
 
14429
        }
 
14430
/*
 
14431
        else if(strcmp(cstr, "/numres"))
 
14432
        {
 
14433
                _temp = numResearchLeft(me, resUnitTransporter);
 
14434
                dbg("num res until transport: " & _temp, me);
 
14435
        }
 
14436
*/
 
14437
        else if(strcmp(cstr, "/numrepprod"))
 
14438
        {
 
14439
                _temp = totalRepairersInProduction();
 
14440
                dbg("repair units in production: " & _temp, me);
 
14441
        }
 
14442
 
 
14443
        else if(strcmp(cstr, "/allystates"))
 
14444
        {
 
14445
 
 
14446
                dbg("0: " & allyState[0], me);
 
14447
                dbg("1: " & allyState[1], me);
 
14448
                dbg("2: " & allyState[2], me);
 
14449
 
 
14450
                dbg("0: " & allyPhase[0], me);
 
14451
                dbg("1: " & allyPhase[1], me);
 
14452
                dbg("2: " & allyPhase[2], me);
 
14453
 
 
14454
                dbg("0: " & allyEnemy[0], me);
 
14455
                dbg("1: " & allyEnemy[1], me);
 
14456
                dbg("2: " & allyEnemy[2], me);
 
14457
        }
 
14458
 
 
14459
        else if(strcmp(cstr, "/alert?"))
 
14460
        {
 
14461
                if(alert)
 
14462
                {
 
14463
                        dbg("yes, alert", me);
 
14464
                }
 
14465
                else
 
14466
                {
 
14467
                        dbg("no, no alert", me);
 
14468
                }
 
14469
        }
 
14470
        else if(strcmp(cstr, "/takeoil"))
 
14471
        {
 
14472
                dbg("numTakeOil: " & numTakeOil & ", countTakeOil: " & countTakeOil, me);
 
14473
        }
 
14474
        else if(strcmp(cstr, "/sendForce"))
 
14475
        {
 
14476
                dbg("sendForceX: " & sendForceX / 128 & ", sendForceY: " & sendForceY / 128, me);
 
14477
        }
 
14478
        else if(strcmp(cstr, "/addpower"))
 
14479
        {
 
14480
                addPower(3000, me);
 
14481
        }
 
14482
        else if(strcmp(cstr, "/checkbase on"))
 
14483
        {
 
14484
                bCheckBaseDebug = true;
 
14485
                dbg("bCheckBaseDebug on", me);
 
14486
        }
 
14487
        else if(strcmp(cstr, "/checkbase off"))
 
14488
        {
 
14489
                bCheckBaseDebug = false;
 
14490
                dbg("bCheckBaseDebug off", me);
 
14491
        }
 
14492
        else if(strcmp(cstr, "/baseloc"))
 
14493
        {
 
14494
                count = 0;
 
14495
                while(count < multiPlayerMaxPlayers)
 
14496
                {
 
14497
                        dbg(getPlayerName(count) & "'s base " & (curBase[count][0] / TILE) & "/" & (curBase[count][1] / TILE), me);
 
14498
                        count++;
 
14499
                }
 
14500
        }
 
14501
        else if(strcmp(cstr, "/temp"))
 
14502
        {
 
14503
                count = 0;
 
14504
                while(count <= 7)
 
14505
                {
 
14506
                        //count2 = checkPlayerDead(count);
 
14507
                        dbg(getPlayerName(count) & " is dead = " & checkPlayerDead(count), me);
 
14508
                        count = count + 1;
 
14509
                }
 
14510
        }
 
14511
        else if(strcmp(cstr, "/temp2")) //4
 
14512
        {
 
14513
                count = 0;
 
14514
                while(count <= 7)
 
14515
                {
 
14516
                        dbg("knowBase " & getPlayerName(count) & " is = " & knowBase[count], me);
 
14517
                        count = count + 1;
 
14518
                }
 
14519
        }
 
14520
        else if(strcmp(cstr, "/temp3")) //0
 
14521
        {
 
14522
                count = 0;
 
14523
                while(count <= 7)
 
14524
                {
 
14525
                        dbg("seeBase " & getPlayerName(count) & " is = " & canSeePlayerBase(count), me);
 
14526
                        count = count + 1;
 
14527
                }
 
14528
        }
 
14529
        else if(strcmp(cstr, "/temp4")) //-7
 
14530
        {
 
14531
                count = 0;
 
14532
                while(count <= 7)
 
14533
                {
 
14534
                        if(mapRevealedInRange(curBase[count][0],curBase[count][1], (2 * 128), me))
 
14535
                        {
 
14536
                                dbg("base revealed for " & count, me);
 
14537
                        }
 
14538
                        else
 
14539
                        {
 
14540
                                dbg("base not revealed for " & count, me);
 
14541
                        }
 
14542
                        count = count + 1;
 
14543
                }
 
14544
        }
 
14545
        else if(strcmp(cstr, "/temp5"))
 
14546
        {
 
14547
                count = 0;
 
14548
                while(count <= 7)
 
14549
                {
 
14550
                        //count2 = canSeePlayer(count);         //can see any other objects?
 
14551
 
 
14552
                        if(not canSeePlayer(count))
 
14553
                        {
 
14554
                                dbg("can't see " & getPlayerName(count), me);
 
14555
                        }
 
14556
                        else
 
14557
                        {
 
14558
                                dbg("can see " & getPlayerName(count), me);
 
14559
                        }
 
14560
                        count = count + 1;
 
14561
                }
 
14562
        }
 
14563
        else if(strcmp(cstr, "/temp6")) //0
 
14564
        {
 
14565
                count = 0;
 
14566
                while(count <= 7)
 
14567
                {
 
14568
                        dbg("dead " & count & " is = " & dead[count], me);
 
14569
                        count = count + 1;
 
14570
                }
 
14571
        }
 
14572
        else if(strcmp(cstr, "/temp7")) //0
 
14573
        {
 
14574
                count = 0;
 
14575
                while(count <= 7)
 
14576
                {
 
14577
                        if(allianceExistsBetween(count ,me))
 
14578
                        {
 
14579
                                MsgBox("dropBeacon for " & count);
 
14580
                                dropBeacon("help", count, me, baseX, baseY,0);
 
14581
                        }
 
14582
                        count = count + 1;
 
14583
                }
 
14584
 
 
14585
        }
 
14586
        else if(strcmp(cstr, "/fast"))
 
14587
        {
 
14588
                //maxTrucks = 4;
 
14589
                //minTrucks = 2;
 
14590
 
 
14591
                numDefenders = 2;
 
14592
                minAttackers = 3;
 
14593
                numAttackers = 3;
 
14594
 
 
14595
                minReinforcements = 7;
 
14596
 
 
14597
                maxOilScouts = 1;
 
14598
 
 
14599
                numOilScouts = 1;
 
14600
 
 
14601
                dbg("FAST ATTACK MODE ON", me);
 
14602
        }
 
14603
        else if(strcmp(cstr, "/range on"))
 
14604
        {
 
14605
                //showRangeAtPos(baseX, baseY, baseRange + defendCorridor);
 
14606
                if(sendForceX > 0)
 
14607
                {
 
14608
                        if(helpingAlly()){
 
14609
                                showRangeAtPos(sendForceX, sendForceY, sendHelpRange);
 
14610
                        }else{
 
14611
                                showRangeAtPos(sendForceX, sendForceY, REINF_ENEMY_COUNT_RANGE);
 
14612
                        }
 
14613
                }
 
14614
        }
 
14615
        else if(strcmp(cstr, "/save"))
 
14616
        {
 
14617
                saveExperience();
 
14618
        }
 
14619
        else if(strcmp(cstr, "/save"))
 
14620
        {
 
14621
                saveExperience();
 
14622
        }
 
14623
        else if(strcmp(cstr, "/range off"))
 
14624
        {
 
14625
                showRangeAtPos(sendForceX, sendForceY, -1);
 
14626
        }
 
14627
        else if(strcmp(cstr, "/msg on"))
 
14628
        {
 
14629
                dbgMsgOn(me, TRUE);
 
14630
                console("turned on debug messages");
 
14631
        }
 
14632
        else if(strcmp(cstr, "/msg off"))
 
14633
        {
 
14634
                console("turned off debug messages");
 
14635
                dbgMsgOn(me, FALSE);
 
14636
        }
 
14637
        else
 
14638
        {
 
14639
                        /************************/
 
14640
                        /*       offer          */
 
14641
                        /************************/
 
14642
                temp2 = 0;
 
14643
                while(temp2 < 8)
 
14644
                {
 
14645
                        if(strcmp(cstr, "/offer " & temp2))
 
14646
                        {
 
14647
                                if(temp2 != me)
 
14648
                                {
 
14649
                                        doOfferAlliance(temp2);
 
14650
                                }
 
14651
                                else
 
14652
                                {
 
14653
                                        dbg("can't ally myself", me);
 
14654
                                }
 
14655
 
 
14656
                                exit;
 
14657
                        }
 
14658
                        temp2 = temp2 + 1;
 
14659
                }
 
14660
        }
 
14661
 
 
14662
}
 
14663
 
 
14664
event beaconEv(inactive)
 
14665
{
 
14666
        local   int _players;
 
14667
        local   string _processedString;
 
14668
 
 
14669
        if(msgPlayer >= 8)
 
14670
        {
 
14671
                MsgBox("beaconTr - msgPlayer >= 8");
 
14672
                exit;
 
14673
        }
 
14674
 
 
14675
        /* Get target players */
 
14676
        _processedString = cstr;
 
14677
        //_players = getTargetPlayers(ref _processedString);
 
14678
 
 
14679
        //dbg("beaconEv()!!!! = " & cstr & ", from " & msgPlayer, me);
 
14680
 
 
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
 
14684
 
 
14685
        processCommand(cstr, msgPlayer, TRUE);
 
14686
        //dbg("beaconEv()!!!! END = " & cstr & ", from " & msgPlayer, me);
 
14687
}
 
14688
 
 
14689
event multiMsgEv(inactive)
 
14690
{
 
14691
        local   int _players;
 
14692
        local   string _processedString;
 
14693
        if(msgPlayer == me)
 
14694
                exit;
 
14695
 
 
14696
        /* Get target players */
 
14697
        _processedString = cstr;
 
14698
//      _players = getTargetPlayers(ref _processedString);
 
14699
 
 
14700
        dbg(" " & me & " multiMsgEv() = " & cstr & ", from " & msgPlayer, me);
 
14701
 
 
14702
        //dbg("multiMsgEv() = " & cstr & ", from " & msgPlayer, me);
 
14703
 
 
14704
        /* See if sender was referring to us */
 
14705
        processCommand(cstr, msgPlayer, FALSE);
 
14706
 
 
14707
 
 
14708
        //dbg("processDebugCommand() start = " & cstr & ", from " & msgPlayer, me);
 
14709
        //process debug messages
 
14710
        if(DEBUG_COMMANDS)
 
14711
        {
 
14712
                processDebugCommand(msgPlayer, cstr);
 
14713
        }
 
14714
        //dbg("multiMsgEv() END = " & cstr & ", from " & msgPlayer, me);
 
14715
}
 
14716
 
 
14717
function void processDebugCommand(int _msgPlayer, STRING _cstr)
 
14718
{
 
14719
        if(strcmp(_cstr, "stop"))
 
14720
        {
 
14721
                stopState();
 
14722
        }
 
14723
        else if(strcmp(cstr, "see enemy?"))
 
14724
        {
 
14725
                if(enemy >= 0)
 
14726
                        dbg("seeBase[" & enemy & "] = " & canSeePlayerBase(enemy), me);
 
14727
 
 
14728
                if(enemy == none)
 
14729
                        dbg("no enemy", me);
 
14730
        }
 
14731
        else if(strcmp(_cstr, "status?"))
 
14732
        {
 
14733
                if(alert){msg("alert = TRUE" , me, _msgPlayer);}        //alert
 
14734
                else{msg("alert = FALSE" , me, _msgPlayer);}
 
14735
 
 
14736
                if(lowMilitary){msg("lowMilitary = TRUE" , me, _msgPlayer);}    //lowMilitary
 
14737
                else{msg("lowMilitary = FALSE" , me, _msgPlayer);}
 
14738
 
 
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);
 
14743
        }
 
14744
        else if(strcmp(cstr, "range on"))
 
14745
        {
 
14746
                showRangeAtPos(baseX, baseY, baseRange + defendCorridor);
 
14747
        }
 
14748
        else if(strcmp(cstr, "range off"))
 
14749
        {
 
14750
                showRangeAtPos(baseX, baseY, -1);
 
14751
        }
 
14752
        else if(strcmp(cstr, "msg on"))
 
14753
        {
 
14754
                dbgMsgOn(me, TRUE);
 
14755
        }
 
14756
        else if(strcmp(cstr, "msg off"))
 
14757
        {
 
14758
                dbgMsgOn(me, FALSE);
 
14759
        }
 
14760
        else if(strcmp(_cstr, "num res?"))
 
14761
        {
 
14762
                msg("num res=" & numBusyByType(resFac), me, _msgPlayer);
 
14763
        }
 
14764
        else if(strcmp(cstr, "fast"))
 
14765
        {
 
14766
                numDefenders = 2;
 
14767
                minAttackers = 3;
 
14768
                numAttackers = 3;
 
14769
 
 
14770
                minReinforcements = 7;
 
14771
 
 
14772
                maxOilScouts = 1;
 
14773
 
 
14774
                numOilScouts = 1;
 
14775
 
 
14776
                dbg("FAST ATTACK MODE ON", me);
 
14777
        }
 
14778
        else if(strcmp(cstr, "numres"))
 
14779
        {
 
14780
                temp = numBusyByType(resFac);
 
14781
                dbg("numres: " & temp, me);
 
14782
        }
 
14783
        else if(strcmp(cstr, "/knowbase"))
 
14784
        {
 
14785
                temp = 0;
 
14786
                while(temp < multiPlayerMaxPlayers)
 
14787
                {
 
14788
                        if(knowBase[temp])
 
14789
                        {
 
14790
                                console(temp & " - yes");
 
14791
                        }
 
14792
                        else
 
14793
                        {
 
14794
                                console(temp & " - no");
 
14795
                        }
 
14796
                        temp++;
 
14797
                }
 
14798
        }
 
14799
        else if(strcmp(cstr, "/dead"))
 
14800
        {
 
14801
                temp = 0;
 
14802
                while(temp < multiPlayerMaxPlayers)
 
14803
                {
 
14804
                        if(dead[temp])
 
14805
                        {
 
14806
                                console(temp & " - yes");
 
14807
                        }
 
14808
                        else
 
14809
                        {
 
14810
                                console(temp & " - no");
 
14811
                        }
 
14812
                        temp++;
 
14813
                }
 
14814
        }
 
14815
        else if(strcmp(cstr, "/hasVTOLs"))
 
14816
        {
 
14817
                temp = 0;
 
14818
                while(temp < multiPlayerMaxPlayers)
 
14819
                {
 
14820
                        if(hasVTOLs[temp])
 
14821
                        {
 
14822
                                console(temp & " - yes");
 
14823
                        }
 
14824
                        else
 
14825
                        {
 
14826
                                console(temp & " - no");
 
14827
                        }
 
14828
                        temp++;
 
14829
                }
 
14830
        }
 
14831
}
 
14832
 
 
14833
//function void processCommand(int _msgPlayer, STRING _cstr, bool _bBlipMessage, string _processedString, int _targetPlayers)
 
14834
function void processCommand(string _message, int _sender, bool _bBlipMessage)
 
14835
{
 
14836
        local   int             _numMsgs,_curMsg,_addressedPlayers,_x,_y,_player;
 
14837
        local   string          _msg,_processedString;
 
14838
 
 
14839
        //dbg("processCommand(" & _message & ", " & _sender & ")", me);
 
14840
 
 
14841
        if(dead[_sender] and (multiPlayerAlliancesType != ALLIANCES_TEAMS)){    //if we thought he was dead and teams are off
 
14842
                rememberPlayerIsAlive(_sender);
 
14843
        }
 
14844
 
 
14845
        /* Extract semantic information */
 
14846
        _curMsg = 0;
 
14847
        _numMsgs = processChatMsg(_message);
 
14848
 
 
14849
        debug(me & ") processCommand: '" & _message & "' from " & _sender);
 
14850
        dbg("processCommand: '" & _message & "' from " & _sender, me);
 
14851
        dbg("got " & _numMsgs & " commands", me);
 
14852
 
 
14853
        if(_message == "are you aiv?" or _message == "are you aivolution?")
 
14854
        {
 
14855
                notifyAll("yes");
 
14856
        }
 
14857
 
 
14858
        /* Process all messages */
 
14859
        while(_curMsg < _numMsgs)
 
14860
        {
 
14861
                if(chatCmdIsPlayerAddressed(_curMsg, me))
 
14862
                {
 
14863
                        dbg("i'm addressed", me);
 
14864
                        _msg = getChatCmdDescription(_curMsg);
 
14865
 
 
14866
                        if(_msg == "ally me")
 
14867
                        {
 
14868
                                if(alliancesLocked())
 
14869
                                {
 
14870
                                        return;
 
14871
                                }
 
14872
 
 
14873
                                if(allianceExistsBetween(_sender ,me) and (random(2) == 1))
 
14874
                                {
 
14875
                                        msg("already allied" , me, _sender);
 
14876
                                }
 
14877
 
 
14878
                                if(not canAlly(_sender))                //shouldn't ally
 
14879
                                {
 
14880
                                        if(random(2) == 1){msg("no" , me, _sender);}
 
14881
                                        return;
 
14882
                                }
 
14883
 
 
14884
                                msg("ok" , me, _sender);
 
14885
 
 
14886
                                doAlly(_sender);
 
14887
                        }
 
14888
 
 
14889
                        /* ally mesages only */
 
14890
                        if(not allianceExistsBetween(me , _sender))
 
14891
                                return;
 
14892
 
 
14893
                        if(_msg == "go?")
 
14894
                        {
 
14895
                                allyState[_sender] = stNone;
 
14896
                                allyPhase[_sender] = phNone;
 
14897
                                allyEnemy[_sender] = none;
 
14898
 
 
14899
                                /* tell him we are busy */
 
14900
                                if(not canFollowAttackRequest(_sender, true))
 
14901
                                {
 
14902
                                        return;
 
14903
                                }
 
14904
 
 
14905
                                /* tell him we are ready */
 
14906
                                msg("where" , me, _sender);
 
14907
                        }
 
14908
                        if(_msg == "go center")
 
14909
                        {
 
14910
                                /* tell him we are busy */
 
14911
                                if(not canFollowAttackRequest(_sender, true))
 
14912
                                        return;
 
14913
 
 
14914
                                /* cancel current state since not doing anything important */
 
14915
                                if(state != stNone)
 
14916
                                        cancelState();
 
14917
 
 
14918
                                joinForces(_sender, mapWidth*64,  mapHeight*64);                //to center
 
14919
 
 
14920
                                return;
 
14921
                        }
 
14922
                        else if(_msg == "status?")
 
14923
                        {
 
14924
                                if(state == stNone)
 
14925
                                {
 
14926
                                        notifyIdle(false);
 
14927
                                }
 
14928
                                else
 
14929
                                {
 
14930
                                        notifyStatus(_sender);
 
14931
                                }
 
14932
                        }
 
14933
                        else if(_msg == "pumping units")
 
14934
                        {
 
14935
                                allyState[_sender] = stNone;
 
14936
                                allyPhase[_sender] = phNone;
 
14937
                                allyEnemy[_sender] = none;
 
14938
                        }
 
14939
                        else if(_msg == "stop")
 
14940
                        {
 
14941
                                if((state != stNone) and (enemy == _sender))
 
14942
                                {
 
14943
                                        msg("ok" , me, _sender);
 
14944
                                        stopState();
 
14945
                                }
 
14946
                        }
 
14947
                        else if(_msg == "got power?")
 
14948
                        {
 
14949
                                notifyPower(_sender);
 
14950
                        }
 
14951
                        //else if(strcmp(_msg, "cya"))  //player has lost
 
14952
                        //{
 
14953
                        //      if(allianceExistsBetween(me , _sender))
 
14954
                        //      {
 
14955
                        //              dead[_sender] = TRUE;
 
14956
                        //
 
14957
                        //              allyState[_sender] = stNone;
 
14958
                        //              allyPhase[_sender] = phNone;
 
14959
                        //              allyEnemy[_sender] = none;
 
14960
                        //      }
 
14961
                        //}
 
14962
                        else if(_msg == "go!")
 
14963
                        {
 
14964
                                /* tell him we are busy */
 
14965
                                if(not canFollowAttackRequest(_sender, true))
 
14966
                                        return;
 
14967
 
 
14968
                                /* cancel current state since not doing anything important */
 
14969
                                if(state != stNone)
 
14970
                                        cancelState();
 
14971
 
 
14972
                                /* know location? */
 
14973
                                if(not haveBeacon(_sender))
 
14974
                                {
 
14975
                                        if(random(5) == 0)
 
14976
                                        {
 
14977
                                                msg("I can't read your thoughts", me, _sender);
 
14978
                                        }
 
14979
                                        msg("drop a beacon", me, _sender);
 
14980
                                        return;
 
14981
                                }
 
14982
 
 
14983
                                joinForces(_sender, beaconX[_sender], beaconY[_sender]);                //not to center
 
14984
                                return;
 
14985
                        }
 
14986
 
 
14987
                        else if(_msg == "help me")
 
14988
                        {
 
14989
                                allyState[_sender] = stDefendingBase;   //remember he's in trouble
 
14990
                                allyEnemy[_sender] = none;
 
14991
                                allyPhase[_sender] = phNone;
 
14992
 
 
14993
                                if(_bBlipMessage)       //processing message from blip
 
14994
                                {
 
14995
                                        curHelpX[_sender] = x;
 
14996
                                        curHelpY[_sender] = y;
 
14997
                                }
 
14998
 
 
14999
                                /* got beacon msg and are already doing this command => just correct the coords */
 
15000
                                if(isCurrentOrder(stHelpingAlly, _sender))
 
15001
                                {
 
15002
                                        if(_bBlipMessage)       //processing message from blip
 
15003
                                        {
 
15004
                                                updateStateCoord(beaconX[_sender], beaconY[_sender]);
 
15005
                                                helpTime = maxHelpTime;         //reset help timeout timer
 
15006
 
 
15007
                                                if(random(2)==0)
 
15008
                                                {
 
15009
                                                        msg("roger", me, _sender);
 
15010
                                                }
 
15011
                                                return;
 
15012
                                        }
 
15013
                                        else    /* if a message, not a blip */
 
15014
                                        {
 
15015
                                                helpTime = maxHelpTime;         //reset help timeout timer
 
15016
                                                msg("I am!", me, _sender);
 
15017
                                                return;
 
15018
                                        }
 
15019
                                }
 
15020
 
 
15021
                                if(state == stHelpingAlly)              /* busy with something else */
 
15022
                                {
 
15023
                                        //msg("defending player " & enemy & " already", me, _sender);
 
15024
                                        notifyStatus(_sender);
 
15025
                                        return;
 
15026
                                }
 
15027
 
 
15028
                                if(defendingBase())
 
15029
                                {
 
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);
 
15032
                                        return;
 
15033
                                }
 
15034
 
 
15035
                                temp = totalWeapUnits();
 
15036
                                if(temp < minAllyHelpers)
 
15037
                                {
 
15038
                                        msg("have nothing", me, _sender);
 
15039
                                        return;
 
15040
                                }
 
15041
 
 
15042
                                if(curHelpX[_sender] <= 0)
 
15043
                                {
 
15044
                                        msg("give vision", me, _sender);
 
15045
                                        return;
 
15046
                                }
 
15047
 
 
15048
                                if(state != stNone)
 
15049
                                {
 
15050
                                        pauseState();           //resume when done helping
 
15051
                                }
 
15052
 
 
15053
                                msg("coming, hold on", me, _sender);
 
15054
 
 
15055
                                startHelpAlly(_sender, curHelpX[_sender], curHelpY[_sender]);
 
15056
                        }
 
15057
                        else if(_msg == "i'm ok")
 
15058
                        {
 
15059
                                allyState[_sender] = stNone;
 
15060
                                allyPhase[_sender] = phNone;
 
15061
                                allyEnemy[_sender] = none;
 
15062
 
 
15063
                                if((state == stHelpingAlly) and (enemy == _sender))
 
15064
                                {
 
15065
                                        msg("roger", me, _sender);
 
15066
                                        stopAllyDefense();
 
15067
                                }
 
15068
 
 
15069
                                /* remind allies we are in trouble */
 
15070
                                if(defendingBase())
 
15071
                                        requestHelp(baseX, baseY);
 
15072
                        }
 
15073
                        else if(_msg == "give vision")
 
15074
                        {
 
15075
                                giftRadar(me, _sender, FALSE);
 
15076
                        }
 
15077
                        else if(_msg == "can't see him")                //a reply after "go x"
 
15078
                        {
 
15079
                                //if(state == stAttacking)
 
15080
                                //{
 
15081
                                //      msg("go", me, _sender);         //just follow my units
 
15082
                                //}
 
15083
 
 
15084
                                //todo: del
 
15085
                                //MsgBox("test");
 
15086
 
 
15087
                                giftRadar(me, _sender, FALSE);
 
15088
                        }
 
15089
                        else if(_msg == "let's lassat someone")
 
15090
                        {
 
15091
                                lasSatState[_sender] = lsWaitingReply;
 
15092
 
 
15093
                                if(lasSatState[me] == lsReady)
 
15094
                                {
 
15095
                                        msg("ok", me, _sender);
 
15096
                                        dbg("have a lassat requester********", me);
 
15097
                                        lasSatState[me] = lsWaitingForRequester;        //join the strike
 
15098
                                }
 
15099
                                else if(lasSatState[me] == lsRecharging)        //tell him to wait, if we are almost finished recharging
 
15100
                                {
 
15101
                                        if((tLasSatReady - tLasSat) < tLasSatWaitAlliesMax)     //not much left
 
15102
                                        {
 
15103
                                                lasSatState[me] = lsRequesterWaitingRecharging;
 
15104
                                                msg("wait, lassat almost ready", me, _sender);
 
15105
                                        }
 
15106
                                }
 
15107
                        }
 
15108
                        else if(_msg == "wait, lassat almost ready")
 
15109
                        {
 
15110
                                dbg("LASSAT: " & getPlayerName(_sender) & "has joined us********", me);
 
15111
                                lasSatState[_sender] = lsRequesterWaitingRecharging;    //remember ally is almost done recharging
 
15112
 
 
15113
                        }
 
15114
                        else if(_msg == "lassat ready")
 
15115
                        {
 
15116
                                dbg("LASSAT: " & getPlayerName(_sender) & " waits for us********", me);
 
15117
                                lasSatState[_sender] = lsWaitingForRequester;   //remember ally is waiting for the requester to start lassat strike
 
15118
                        }
 
15119
                        else if(_msg == "defending my oil")
 
15120
                        {
 
15121
                                allyState[_sender] = stDefendingOil;
 
15122
                                allyPhase[_sender] = phMoveToLoc;
 
15123
                                allyEnemy[_sender] = none;
 
15124
                        }
 
15125
                        else
 
15126
                        {
 
15127
                                        /************************/
 
15128
                                        /*       ally           */
 
15129
                                        /************************/
 
15130
                                if(DEBUG_MSG)
 
15131
                                {
 
15132
                                        temp2 = 0;
 
15133
                                        while(temp2 < 8)
 
15134
                                        {
 
15135
                                                if(_msg == "ally " & temp2 & "!")
 
15136
                                                {
 
15137
                                                        if(temp2 != me)
 
15138
                                                        {
 
15139
                                                                doAlly(temp2);
 
15140
                                                        }
 
15141
                                                        else
 
15142
                                                        {
 
15143
                                                                dbg("can't ally myself", me);
 
15144
                                                        }
 
15145
 
 
15146
                                                        return;
 
15147
                                                }
 
15148
                                                temp2 = temp2 + 1;
 
15149
                                        }
 
15150
                                }
 
15151
 
 
15152
                                        /*************************/
 
15153
                                        /*        go player         */
 
15154
                                        /*************************/
 
15155
 
 
15156
                                //if(match(_processedString,"go <player>", ref _player))
 
15157
                                if((_msg == "attack player") and (getNumArgsInCmd(_curMsg) == 1))
 
15158
                                {
 
15159
                                        //get player index
 
15160
                                        if(getChatCmdParam(ref _player, _curMsg, 0))
 
15161
                                        {
 
15162
                                                dbg("*************go " & _player, me);
 
15163
 
 
15164
                                                if((_player == me) or (ally[_player]))
 
15165
                                                {
 
15166
                                                        notifyAllies(getPlayerName(_player) & "???", false);
 
15167
                                                        return;
 
15168
                                                }
 
15169
 
 
15170
                                                if(dead[_player])
 
15171
                                                {
 
15172
                                                        notifyAllies(getPlayerName(_player) & " is dead", false);
 
15173
                                                        return;
 
15174
                                                }
 
15175
 
 
15176
                                                /* got beacon msg and are already doing this command => just correct the coords */
 
15177
                                                if(isCurrentOrder(stAttacking, _player))
 
15178
                                                {
 
15179
                                                        if(_bBlipMessage)       /* processing beacon msg */
 
15180
                                                        {
 
15181
                                                                updateStateCoord(beaconX[_sender], beaconY[_sender]);
 
15182
                                                                if(random(2)==0)
 
15183
                                                                {
 
15184
                                                                        notifyAllies("roger", false);
 
15185
                                                                }
 
15186
                                                                return;
 
15187
                                                        }
 
15188
                                                        else    /* if a normal msg, and we are already doind it, say so, since the destination can only be tweaked with a beacon */
 
15189
                                                        {
 
15190
                                                                notifyAllies("I am", false);
 
15191
                                                                return;
 
15192
                                                        }
 
15193
                                                }               /* we are doing something else already */
 
15194
                                                else if(not canFollowAttackRequest(_sender, true))
 
15195
                                                {
 
15196
                                                        return;
 
15197
                                                }
 
15198
 
 
15199
                                                /* know location? */
 
15200
                                                if(haveBeacon(_sender))
 
15201
                                                {
 
15202
                                                        _x = beaconX[_sender];
 
15203
                                                        _y = beaconY[_sender];
 
15204
                                                }
 
15205
                                                else    /* no beacon provided, use the current enemy location */
 
15206
                                                {
 
15207
                                                        if(killedBase[_player] and (not canSeePlayerBase(_player)))     /* we have no idea where the enemy has rebuilt the base */
 
15208
                                                        {
 
15209
                                                                notifyAllies(getPlayerName(_sender) & ", drop a beacon", false);
 
15210
                                                                return;
 
15211
                                                        }
 
15212
                                                        else if(curBase[_player][0] > 0)        /* remember or can directly see it */
 
15213
                                                        {
 
15214
                                                                _x = curBase[_player][0];
 
15215
                                                                _y = curBase[_player][1];
 
15216
                                                        }
 
15217
                                                        else
 
15218
                                                        {
 
15219
                                                                notifyAllies(getPlayerName(_sender) & ", drop a beacon", false);
 
15220
                                                                return;
 
15221
                                                        }
 
15222
                                                }
 
15223
 
 
15224
                                                /* cancel current state since not doing anything important */
 
15225
                                                if(state != stNone)
 
15226
                                                {
 
15227
                                                        cancelState();
 
15228
                                                }
 
15229
 
 
15230
                                                if(killedBase[_player])
 
15231
                                                {
 
15232
                                                        notifyAllies(getPlayerName(_sender) & ", ok, but haven't we destroyed " & getPlayerName(_player) & "'s base already?", false);
 
15233
                                                }
 
15234
                                                else
 
15235
                                                {
 
15236
                                                        notifyAllies("ok" , false);
 
15237
                                                }
 
15238
 
 
15239
                                                allyState[_sender] = stAttacking;
 
15240
                                                allyEnemy[_sender] = _player;
 
15241
                                                allyPhase[_sender] = phMoveToLoc;       //or phAttackingLoc
 
15242
 
 
15243
                                                offeredEnemy = _player; //remember the offer
 
15244
 
 
15245
                                                attackReason = ATTACK_BASE;
 
15246
                                                startAttack(_player, _x, _y);
 
15247
                                                notifyAllies("attacking " & getPlayerName(_player), TRUE);
 
15248
                                                return;
 
15249
                                        }
 
15250
                                }
 
15251
 
 
15252
                                        /*************************/
 
15253
                                        /*      going player     */
 
15254
                                        /*************************/
 
15255
 
 
15256
                                //if(match(_processedString,"going <player>", ref _player))
 
15257
                                if((_msg == "attacking player?") and (getNumArgsInCmd(_curMsg) == 1))
 
15258
                                {
 
15259
                                        //get player index
 
15260
                                        if(getChatCmdParam(ref _player, _curMsg, 0))
 
15261
                                        {
 
15262
                                                dbg("*************going " & _player, me);
 
15263
 
 
15264
                                                allyState[_sender] = stAttacking;
 
15265
                                                allyEnemy[_sender] = _player;
 
15266
                                                allyPhase[_sender] = phMoveToLoc;       //or phAttackingLoc
 
15267
 
 
15268
                                                if(_player == me)
 
15269
                                                {
 
15270
                                                        notifyAllies(getPlayerName(_sender) & ", you bastard!", false);
 
15271
                                                        breakAlliance(me, _sender);
 
15272
                                                        return;
 
15273
                                                }
 
15274
 
 
15275
                                                if(ally[_player]){return;}              //just exit quietly
 
15276
 
 
15277
                                                if(dead[_player])
 
15278
                                                {
 
15279
                                                        notifyAllies("isn't " & getPlayerName(_player) & " dead already?", false);
 
15280
                                                        return;
 
15281
                                                }
 
15282
 
 
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)
 
15285
                                                {
 
15286
                                                        return;                 //just exit
 
15287
                                                }
 
15288
 
 
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)
 
15291
                                                {
 
15292
                                                        return;
 
15293
                                                }
 
15294
 
 
15295
                                                if(not haveTheoreticallyMinAttackers(true))
 
15296
                                                {
 
15297
                                                        return;         //ignore
 
15298
                                                }
 
15299
 
 
15300
                                                /* know location? */
 
15301
                                                if(haveBeacon(_sender))
 
15302
                                                {
 
15303
                                                        _x = beaconX[_sender];
 
15304
                                                        _y = beaconY[_sender];
 
15305
                                                }
 
15306
                                                else    /* no beacon provided, use the current enemy location */
 
15307
                                                {
 
15308
                                                        if(killedBase[_player] and (not canSeePlayerBase(_player)))     /* we have no idea where the enemy has rebuilt the base */
 
15309
                                                        {
 
15310
                                                                notifyAllies(getPlayerName(_sender) & ", drop a beacon", false);
 
15311
                                                                return;
 
15312
                                                        }
 
15313
                                                        else if(curBase[_player][0] > 0)        /* remember or can directly see it */
 
15314
                                                        {
 
15315
                                                                _x = curBase[_player][0];
 
15316
                                                                _y = curBase[_player][1];
 
15317
                                                        }
 
15318
                                                }
 
15319
 
 
15320
                                                if(state != stNone)     //stop if dealing with the one who messaged
 
15321
                                                {
 
15322
                                                        cancelState();
 
15323
                                                }
 
15324
 
 
15325
                                                //enemy = _player;
 
15326
                                                attackReason = ATTACK_BASE;
 
15327
                                                startAttack(_player, _x, _y);
 
15328
                                                notifyAllies("attacking " & getPlayerName(_player), TRUE);
 
15329
                                                return;
 
15330
                                        }
 
15331
                                }
 
15332
 
 
15333
                                        /*****************************/
 
15334
                                        /*      x got VTOLs      */
 
15335
                                        /*****************************/
 
15336
                                //if(match(_msg,"<player> got vtols", ref _player))
 
15337
                                if((_msg == "player has vtols") and (getNumArgsInCmd(_curMsg) == 1))
 
15338
                                {
 
15339
                                        //get player index
 
15340
                                        if(getChatCmdParam(ref _player, _curMsg, 0))
 
15341
                                        {
 
15342
                                                dbg("*************" & getPlayerName(_player) & " got vtols", me);
 
15343
 
 
15344
                                                if(random(2) == 0)
 
15345
                                                {
 
15346
                                                        if(hasVTOLs[_player])
 
15347
                                                        {
 
15348
                                                                notifyAllies("I know", false);
 
15349
                                                        }
 
15350
                                                        else
 
15351
                                                        {
 
15352
                                                                notifyAllies("ok", false);
 
15353
                                                        }
 
15354
                                                }
 
15355
 
 
15356
                                                hasVTOLs[_player] = TRUE;
 
15357
                                                return;
 
15358
                                        }
 
15359
                                }
 
15360
 
 
15361
                                        /*************************/
 
15362
                                        /*      take enemy oil x         */
 
15363
                                        /*************************/
 
15364
 
 
15365
                                //if(match(_processedString,"gonna get <player>'s derrick", ref _player))
 
15366
                                if((_msg == "getting player oil") and (getNumArgsInCmd(_curMsg) == 1))
 
15367
                                {
 
15368
                                        //get player index
 
15369
                                        if(getChatCmdParam(ref _player, _curMsg, 0))
 
15370
                                        {
 
15371
                                                dbg("*************gonna get " & getPlayerName(_player) & "'s derrick", me);
 
15372
 
 
15373
                                                allyState[_sender] = stTakingOil;
 
15374
                                                allyEnemy[_sender] = _player;
 
15375
                                                allyPhase[_sender] = phMoveToLoc;       //or phAttackingLoc
 
15376
 
 
15377
                                                if(_player == me)
 
15378
                                                {
 
15379
                                                        notifyAllies(getPlayerName(_sender) & ", you bastard!", false);
 
15380
                                                        breakAlliance(me, _sender);
 
15381
                                                        return;
 
15382
                                                }
 
15383
 
 
15384
                                                if(ally[_player])
 
15385
                                                        return;         //just exit quietly
 
15386
 
 
15387
                                                /* ignore if already attacking this enemy somehow */
 
15388
                                                if(enemy == _player)
 
15389
                                                        return;
 
15390
 
 
15391
                                                if(dead[_player])
 
15392
                                                {
 
15393
                                                        notifyAllies("isn't " & getPlayerName(_player) & " dead already?", false);
 
15394
                                                        return;
 
15395
                                                }
 
15396
 
 
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)
 
15399
                                                {
 
15400
                                                        return;                 //just exit
 
15401
                                                }
 
15402
 
 
15403
 
 
15404
                                                /* do we want to attack enemy's oil? */
 
15405
                                                if(random(10) <= 6)
 
15406
                                                {
 
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" */
 
15409
                                                        {
 
15410
                                                                /* find a derrick */
 
15411
                                                                structure = findEnemyDerrick(_player);  /* find enemy derrick to attack */
 
15412
                                                                if(structure != NULLOBJECT)
 
15413
                                                                {
 
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)))
 
15416
                                                                        {
 
15417
                                                                                cancelState();          //stop if doing anything unimportant
 
15418
 
 
15419
                                                                                startTakingOil(structure);
 
15420
                                                                                notifyTakeOil(structure.player, structure.x, structure.y);
 
15421
                                                                                return;
 
15422
                                                                        }
 
15423
                                                                }
 
15424
                                                        }
 
15425
                                                }
 
15426
 
 
15427
                                                /* didn't start attacking derrick, decide if we want (and can) to attack the base directly */
 
15428
                                                if(knowBase[_player] and haveTheoreticallyMinAttackers(false))
 
15429
                                                {
 
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);
 
15434
                                                        return;
 
15435
                                                }
 
15436
 
 
15437
                                                return;
 
15438
                                        }
 
15439
                                }
 
15440
                                        /*************************/
 
15441
                                        /*      lassat player x          */
 
15442
                                        /*************************/
 
15443
 
 
15444
                                //if(match(_processedString,"lassat <player>", ref _player))
 
15445
                                if((_msg == "lassat player") and (getNumArgsInCmd(_curMsg) == 1))
 
15446
                                {
 
15447
                                        //get player index
 
15448
                                        if(getChatCmdParam(ref _player, _curMsg, 0))
 
15449
                                        {
 
15450
                                                dbg("*******lassat " & _player, me);
 
15451
 
 
15452
                                                /* remember he just lassatted */
 
15453
                                                lasSatState[_sender] = lsRecharging;
 
15454
                                                lasSatEnemy = _player;
 
15455
 
 
15456
                                                /* if we were waiting for him to start the attack, start delayed attack */
 
15457
                                                if(lasSatState[me] == lsWaitingForRequester)
 
15458
                                                {
 
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)
 
15461
                                                }
 
15462
                                                return;
 
15463
                                        }
 
15464
                                }
 
15465
 
 
15466
                        }
 
15467
                        //else
 
15468
                        //{
 
15469
                        //      dbg("unknown message", me);
 
15470
                        //}
 
15471
                }
 
15472
                else
 
15473
                {
 
15474
                        dbg("i'm not addressed", me);
 
15475
                }
 
15476
                _curMsg++;
 
15477
        }
 
15478
 
 
15479
        //dbg("processCommand(" & _message & ", " & _sender & ") END------", me);
 
15480
}
 
15481
 
 
15482
event   keyPressed(CALL_KEY_PRESSED, ref temp, ref temp2)
 
15483
{
 
15484
        //console("Key pressed: " & temp & ", meta key: " & temp2);
 
15485
        if(DEBUG_MSG)
 
15486
        {
 
15487
                if (temp != KEY_ESC)
 
15488
                {
 
15489
                        if(temp == KEY_SPACE)           //space
 
15490
                        {
 
15491
                                toggleDebugMenu();
 
15492
                        }
 
15493
                        else if(temp == KEY_D and temp2 == KEY_LCTRL)
 
15494
                        {
 
15495
                                dbg("Damaged selected object by 10%", me);
 
15496
                                InitEnumDroids(me, me);
 
15497
                                droid = EnumDroid();
 
15498
                                while(droid != NULLOBJECT)
 
15499
                                {
 
15500
                                        if(droid.selected)
 
15501
                                        {
 
15502
                                                forceDamageObject(droid, 10);
 
15503
                                        }
 
15504
                                        droid = EnumDroid();
 
15505
                                }
 
15506
                        }
 
15507
                        else if(temp == KEY_U and temp2 == KEY_LCTRL)
 
15508
                        {
 
15509
                                if(baseX > 0 and baseY > 0)
 
15510
                                {
 
15511
                                        updatePlayerTileVis(me);
 
15512
                                        if(checkVisibleTile(me, baseX / TILE, baseY / TILE))
 
15513
                                        {
 
15514
                                                dbg("yes", me);
 
15515
                                        }
 
15516
                                }
 
15517
                        }
 
15518
 
 
15519
                }
 
15520
        }
 
15521
 
 
15522
        if(DEBUG_ALL)
 
15523
        {
 
15524
                if(temp == KEY_P and (temp2 == KEY_RCTRL or temp2 == KEY_LCTRL))
 
15525
                {
 
15526
                        addPower(1000, me);
 
15527
                        console("add power");
 
15528
                }
 
15529
 
 
15530
                if(temp == KEY_N)
 
15531
                {
 
15532
                        watchWindowDebug = modulo(watchWindowDebug + 1, 3);
 
15533
                }
 
15534
        }
 
15535
}
 
15536
 
 
15537
function void toggleDebugMenu()
 
15538
{
 
15539
        debugMenuUp = not debugMenuUp;
 
15540
        debugMenu(debugMenuUp);
 
15541
}
 
15542
 
 
15543
/* Returns true if AI has all vital structures */
 
15544
function bool haveMinimalStructures()
 
15545
{
 
15546
        local   int                     _index;
 
15547
        local   STRUCTURE       _structure;
 
15548
 
 
15549
        _index = 0;
 
15550
        while(_index < numVitalStructs)
 
15551
        {
 
15552
                if( (getNumStructures(minimalStruct[_index], me) + numStatBusy(minimalStruct[_index], FALSE))
 
15553
                                < numMinimalStruct[_index] )
 
15554
                {
 
15555
                        return FALSE;
 
15556
                }
 
15557
                _index++;
 
15558
        }
 
15559
 
 
15560
        return TRUE;
 
15561
}
 
15562
 
 
15563
function void checkMinimalStructures()
 
15564
{
 
15565
        local   int                     _index,_maxTrucks,_maxStructsAtATime,_numStructsAtATime;
 
15566
        local   bool            _bStartedBuild;
 
15567
        local   STRUCTURE       _structure;
 
15568
        local   FEATURE         _oil;
 
15569
 
 
15570
        _maxStructsAtATime = 2;
 
15571
        _numStructsAtATime = 0;
 
15572
 
 
15573
        _index = 0;
 
15574
        while((_index < numVitalStructs) and (_numStructsAtATime < _maxStructsAtATime))
 
15575
        {
 
15576
                if( (getNumStructures(minimalStruct[_index], me) +
 
15577
                        numStatBusy(minimalStruct[_index], false)) < numMinimalStruct[_index] )
 
15578
                {
 
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
 
15583
                        }
 
15584
 
 
15585
                        //if it's a derrick
 
15586
                        if(minimalStruct[_index] == derrick)
 
15587
                        {
 
15588
                                _oil = findBestOilToBuildOn(baseX, baseY, -1);
 
15589
 
 
15590
                                if(_oil != NULLOBJECT){
 
15591
                                        dbg("Building minimal base - oil", me);
 
15592
 
 
15593
                                        bDummy = buildUsingClosestTruck(derrick, _oil.x, _oil.y, _maxTrucks);   //Can skip "buildOnMap" for oil
 
15594
                                }
 
15595
                        }
 
15596
                        else
 
15597
                        {
 
15598
                                _bStartedBuild = buildInBase(minimalStruct[_index], _maxTrucks);
 
15599
 
 
15600
                                if(_bStartedBuild){
 
15601
                                        _numStructsAtATime++;
 
15602
 
 
15603
                                        dbg("Building minimal base " & _index, me);
 
15604
                                }
 
15605
                        }
 
15606
                }
 
15607
                _index++;
 
15608
        }
 
15609
}
 
15610
 
 
15611
function bool droidActionAttacking(DROID _droid)
 
15612
{
 
15613
        if(_droid.order == DORDER_ATTACK){
 
15614
                return true;
 
15615
        }
 
15616
 
 
15617
        if(_droid.action == DACTION_ATTACK or
 
15618
           _droid.action == DACTION_ROTATETOATTACK or
 
15619
           _droid.action == DACTION_MOVETOATTACK){
 
15620
                return true;
 
15621
        }
 
15622
 
 
15623
        return false;
 
15624
}
 
15625
 
 
15626
function bool droidOrderIdle(DROID _droid)
 
15627
{
 
15628
        if(_droid.order == DORDER_NONE){
 
15629
                return true;
 
15630
        }
 
15631
 
 
15632
        if(_droid.order == DORDER_GUARD){
 
15633
                return true;
 
15634
        }
 
15635
 
 
15636
        if(_droid.order == DORDER_RTB){
 
15637
                return true;
 
15638
        }
 
15639
 
 
15640
        return false;
 
15641
}
 
15642
 
 
15643
function bool droidActionDroidRepair(DROID _repairer)
 
15644
{
 
15645
        if(_repairer.action == DACTION_DROIDREPAIR){
 
15646
                return true;
 
15647
        }
 
15648
 
 
15649
        if(_repairer.action == DACTION_MOVETODROIDREPAIR){
 
15650
                return true;
 
15651
        }
 
15652
 
 
15653
        return false;
 
15654
}
 
15655
 
 
15656
function int numVisibleOilResInRange(int _x, int _y, int _range)
 
15657
{
 
15658
        local   int                     _numOil;
 
15659
        local   FEATURE         _oil;
 
15660
 
 
15661
        initGetFeature(oilRes,me,me);
 
15662
        _oil = getFeature(me);
 
15663
        while(_oil != NULLOBJECT)
 
15664
        {
 
15665
                if((_range <= 0) or (distBetweenTwoPoints(_x, _y, _oil.x, _oil.y) < _range))
 
15666
                {
 
15667
                        _numOil++;
 
15668
                }
 
15669
                _oil = getFeature(me);
 
15670
        }
 
15671
 
 
15672
        return _numOil;
 
15673
}
 
15674
 
 
15675
function int numDerricksInRange(int _targetPlayer, int _x, int _y, int _range)
 
15676
{
 
15677
        local   int                             _numDerricks;
 
15678
        local   STRUCTURE               _derrick;
 
15679
 
 
15680
        _numDerricks = 0;
 
15681
 
 
15682
        initEnumStruct(false,derrick,_targetPlayer,me);
 
15683
        _derrick = enumStruct();
 
15684
        while(_derrick != NULLOBJECT)
 
15685
        {
 
15686
                if((_range <= 0) or
 
15687
                        (distBetweenTwoPoints(_x, _y, _derrick.x, _derrick.y) < _range))
 
15688
                {
 
15689
                        _numDerricks++;
 
15690
                }
 
15691
                _derrick = enumStruct();
 
15692
        }
 
15693
 
 
15694
        return _numDerricks;
 
15695
}
 
15696
 
 
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)
 
15699
{
 
15700
        return numVisibleOilResInRange(_x, _y, _range) +
 
15701
                        numDerricksInRange(me, _x, _y, _range);
 
15702
}
 
15703
 
 
15704
function BASEOBJ closerObject(BASEOBJ _obj1, BASEOBJ _obj2, int _x, int _y)
 
15705
{
 
15706
        if(_obj1 == NULLOBJECT and _obj2 == NULLOBJECT){
 
15707
                return _obj1;   //NULLOBJECT
 
15708
        }
 
15709
 
 
15710
        if(_obj1 == NULLOBJECT){
 
15711
                return _obj2;
 
15712
        }
 
15713
 
 
15714
        if(_obj2 == NULLOBJECT){
 
15715
                return _obj1;
 
15716
        }
 
15717
 
 
15718
        if(distBetweenTwoPoints(_obj1.x, _obj1.y, _x, _y)
 
15719
                < distBetweenTwoPoints(_obj2.x, _obj2.y, _x, _y))
 
15720
        {
 
15721
                return _obj1;
 
15722
        }
 
15723
 
 
15724
        return _obj2;
 
15725
}
 
15726
 
 
15727
// decide if we have to defend oil derrick
 
15728
function void dealWithOilAttacked(int _oilx, int _oily)
 
15729
{
 
15730
        local   BASEOBJ         _oilLocation;
 
15731
 
 
15732
        if(isInMyBase(_oilx, _oily)){
 
15733
                return;
 
15734
        }
 
15735
 
 
15736
        // remember when oil derrick under attack was attacked last time
 
15737
        if(tOilAttackBegin > 0)         // noticed some oil derrick being under attack
 
15738
        {
 
15739
                // check if same derrick was attacked again
 
15740
                _oilLocation = closerObject(closestDerrick(_oilx, _oily),
 
15741
                                        closestOilResource(_oilx, _oily), _oilx, _oily);
 
15742
 
 
15743
                if(_oilLocation != NULLOBJECT)
 
15744
                {
 
15745
                        if(distBetweenTwoPoints(lastOilAttackedX, lastOilAttackedY,
 
15746
                                _oilLocation.x, _oilLocation.y) <= RANGE_ALL_OIL_DEFENSES)
 
15747
                        {
 
15748
                                // remember last time derrick under siege was attacked
 
15749
                                tLastOilAttack = GAME_TIME_IN_SECS;
 
15750
                        }
 
15751
                }
 
15752
        }
 
15753
 
 
15754
        // if it's a beginning of the attack, remember coordinates and when derrick was attacked
 
15755
        if(tOilAttackBegin <= 0)
 
15756
        {
 
15757
                // find derrick in danger
 
15758
                _oilLocation = closerObject(closestDerrick(_oilx, _oily),
 
15759
                                        closestOilResource(_oilx, _oily), _oilx, _oily);
 
15760
 
 
15761
                // make sure found derrick is not too far away
 
15762
                if(_oilLocation != NULLOBJECT)
 
15763
                {
 
15764
                        if(distBetweenTwoPoints(_oilx, _oily, _oilLocation.x,
 
15765
                                        _oilLocation.y) <= RANGE_ALL_OIL_DEFENSES)
 
15766
                        {
 
15767
                                tOilAttackBegin = GAME_TIME_IN_SECS;
 
15768
                                tLastOilAttack = GAME_TIME_IN_SECS;
 
15769
 
 
15770
                                lastOilAttackedX = _oilLocation.x;
 
15771
                                lastOilAttackedY = _oilLocation.y;
 
15772
                        }
 
15773
                }
 
15774
        }
 
15775
 
 
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)))
 
15779
        {
 
15780
                if(canStartDefendingOil())
 
15781
                {
 
15782
                        if(checkOilThreat(lastOilAttackedX, lastOilAttackedY))
 
15783
                        {
 
15784
                                // start defending oil
 
15785
                                initializeStartDefeindingOil(lastOilAttackedX, lastOilAttackedY);
 
15786
                        }
 
15787
                }
 
15788
        }
 
15789
}
 
15790
 
 
15791
function bool canStartDefendingOil()
 
15792
{
 
15793
        //if(!defendingOil() and !helpingAlly() and !defendingBase())           // not busy
 
15794
        if(state == stNone)             // not busy
 
15795
        {
 
15796
                if(numAvailableAttackers() >= MIN_OIL_DEFENDERS)
 
15797
                {
 
15798
                        return true;
 
15799
                }
 
15800
        }
 
15801
 
 
15802
        return false;
 
15803
}
 
15804
 
 
15805
function bool checkOilThreat(int _oilx, int _oily)
 
15806
{
 
15807
        local   int             _enemyForce,_allyForce,_range,_tankShootRange;
 
15808
 
 
15809
        _range = CHECK_OIL_THREAT_RANGE;
 
15810
        _tankShootRange = (TILE * 7);           //doesn't make sense to change state if we can reach it anyway
 
15811
 
 
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
 
15815
        {
 
15816
                if(!isNearEnemyBase(_oilx, _oily))
 
15817
                {
 
15818
                        _enemyForce = enemyWeapObjCostInRange(me, _oily,
 
15819
                                _oily, _range, false, true);
 
15820
 
 
15821
                        _allyForce = friendlyWeapObjCostInRange(me, _oilx,
 
15822
                                _oily, _range, false, true);
 
15823
 
 
15824
                        // make sure enemy force is stronger
 
15825
                        if((_enemyForce - _allyForce) > 0)
 
15826
                        {
 
15827
                                return true;
 
15828
                        }
 
15829
                }
 
15830
        }
 
15831
 
 
15832
        return false;
 
15833
}
 
15834
 
 
15835
function bool canStartTakingOil()
 
15836
{
 
15837
        //if(!defendingOil() and !helpingAlly() and !defendingBase())           // not busy
 
15838
        if(numAvailableAttackers() >= numOilAttackers){
 
15839
                return true;
 
15840
        }
 
15841
 
 
15842
        // if(state != stNone){         // busy
 
15843
                // return false;
 
15844
        // }
 
15845
 
 
15846
        return false;
 
15847
}
 
15848
 
 
15849
function bool initializeStartTakingOil(int _oilx, int _oily, int _maxRange)
 
15850
{
 
15851
        local   STRUCTURE       _enemyDerrick;
 
15852
 
 
15853
        // cancel state if busy and not doing anything important
 
15854
        if(state != stNone){
 
15855
                cancelState();
 
15856
        }
 
15857
 
 
15858
        _enemyDerrick = findBestEnemyDerrick(none, numAvailableAttackers(),
 
15859
                        sendForceX, sendForceY, _maxRange);
 
15860
 
 
15861
        if(_enemyDerrick == NULLOBJECT)
 
15862
        {
 
15863
                return false;
 
15864
        }
 
15865
 
 
15866
        startTakingOil(_enemyDerrick);
 
15867
 
 
15868
        return true;
 
15869
}
 
15870
 
 
15871
// make necessary calculations to be able to start defending oil derrick
 
15872
function void initializeStartDefeindingOil(int _oilx, int _oily)
 
15873
{
 
15874
        local   int             _maxDefendingOilTime;
 
15875
 
 
15876
        _maxDefendingOilTime = distBetweenTwoPoints(_oilx, _oily,
 
15877
                baseX, baseY) / TILE + MIN_DEF_OIL_TIME;
 
15878
 
 
15879
        dbg("OIL IS THREATENED AT " & (_oilx / TILE) & "/" &
 
15880
                (_oily / TILE) & " (" & _maxDefendingOilTime & " secs)", me);
 
15881
 
 
15882
        // cancel state if busy and not doing anything important
 
15883
        if(state != stNone){
 
15884
                cancelState();
 
15885
        }
 
15886
 
 
15887
        startDefendingOil(_oilx, _oily, _maxDefendingOilTime);
 
15888
}
 
15889
 
 
15890
function void startDefendingOil(int _derrickX, int _derrickY, int _maxTime)
 
15891
{
 
15892
        dbg("DEFENDING OIL!!!!!!!!!!!!!!!!!!!!!!!!!!", me);
 
15893
 
 
15894
        enemy = none;
 
15895
 
 
15896
        updateStateCoord(_derrickX, _derrickY);
 
15897
 
 
15898
        // circlePerimPoint(_derrickX, _derrickY, ref sendForceX, ref sendForceY, (TILE * 4));
 
15899
 
 
15900
        if((sendForceX <= 0) or (sendForceY <= 0))
 
15901
        {
 
15902
                MsgBox("startDefendingOil() - sendForceX <= 0");
 
15903
                exit;
 
15904
        }
 
15905
 
 
15906
        setState(stDefendingOil);
 
15907
 
 
15908
        setPhase(phMoveToLoc, NONE);
 
15909
 
 
15910
        maxStateTime = _maxTime;
 
15911
 
 
15912
        // Set minimum number of defenders to leave in the base
 
15913
        updateNumDefenders();
 
15914
 
 
15915
        dbg("defending oil at " & _derrickX & "/" & _derrickY & " !!!!!!!!!!!!!!!!!!!!!!!!", me);
 
15916
 
 
15917
        /* Assign attackers and commanders to groups */
 
15918
        prepareAttackers(false);
 
15919
 
 
15920
        startMovePhase();
 
15921
 
 
15922
        dropAllyBeacon("defending my oil", sendForceX, sendForceY);
 
15923
}
 
15924
 
 
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)
 
15930
{
 
15931
        local   float _sqrtDivEffect,           //square root from (ally effectiveness / enemy effectiveness)
 
15932
                                  _sqrtMultTimeEffect;  //time multiplied with square root from (ally effectiveness * enemy effectiveness)
 
15933
 
 
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;
 
15937
        }
 
15938
 
 
15939
        _sqrtDivEffect = sqrt(_allyEffectiveness / _enemyEffectiveness);
 
15940
        _sqrtMultTimeEffect = sqrt(_allyEffectiveness * _enemyEffectiveness) * (float)_time;
 
15941
 
 
15942
        return 0.5 * (( _fAllyStartForce - _sqrtDivEffect * _fEnemyStartForce) * exp(_sqrtMultTimeEffect) +
 
15943
                                  (_fAllyStartForce + _sqrtDivEffect * _fEnemyStartForce) * exp(-_sqrtMultTimeEffect));
 
15944
}
 
15945
 
 
15946
function bool LanchasterVictory(float _fStartForceA, float _fStartForceB,
 
15947
                                                                float _fKillRateA, float _fKillRateB)
 
15948
{
 
15949
        //ASSERT(!(_fStartForceB > 0 and _fKillRateB <= 0.0), "_fKillRateB can't be 0", me);
 
15950
 
 
15951
        // avoid division by zero
 
15952
/*      if(_fStartForceB <= 0 or _fKillRateB <= 0.0){
 
15953
                return true;
 
15954
        }
 
15955
 
 
15956
        // check if force A is going to win
 
15957
        if( ((float)_fStartForceA / (float)_fStartForceB) > sqrt(_fKillRateA / _fKillRateB)){
 
15958
                return true;
 
15959
        } */
 
15960
 
 
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)
 
15963
        {
 
15964
                if(_fStartForceA > 0.0 and _fStartForceB <= 0.0){
 
15965
                        return true;
 
15966
                }else if(_fStartForceA <= 0.0 and _fStartForceB > 0.0){
 
15967
                        return false;
 
15968
                }
 
15969
        }
 
15970
 
 
15971
        if( (sqrt(_fKillRateA) * _fStartForceA) >= (sqrt(_fKillRateB) * _fStartForceB) ){
 
15972
                return true;
 
15973
        }
 
15974
 
 
15975
        return false;
 
15976
}
 
15977
 
 
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)
 
15981
{
 
15982
        local   float   _fTimeToWin,_fKillFactor,_devisor;
 
15983
 
 
15984
        if(_fStartForceA <= 0.0 or _fStartForceB <= 0.0 or _fKillRateB == 0.0){
 
15985
                return 0;
 
15986
        }
 
15987
 
 
15988
        _fKillFactor = (_fStartForceB / _fStartForceA) *
 
15989
                                        sqrt(_fKillRateA / _fKillRateB);
 
15990
 
 
15991
        // avoid division by 0
 
15992
        if( (1.0 - _fKillFactor) == 0.0){
 
15993
                return 0;
 
15994
        }
 
15995
 
 
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) );
 
15999
 
 
16000
        // avoid division by 0
 
16001
        if(_devisor == 0.0){
 
16002
                return 0;
 
16003
        }
 
16004
        
 
16005
        _fTimeToWin = 1.0 / _devisor;
 
16006
 
 
16007
        return (int)_fTimeToWin;
 
16008
}
 
16009
 
 
16010
function float weaponDamagePerSec(int _player, WEAPON _weap)
 
16011
{
 
16012
        local   float   _fFirePowerPerSec,_fFireRatePerSec,_fShortRangeDamagePerSec,
 
16013
                                        _fLongRangeDamagePerSec,_fReloadTimeInSecs,_fFirePauseInSecs;
 
16014
        
 
16015
        local   int             _upgradedShortHit,_upgradedLongHit,_upgradedDamage,
 
16016
                                        _upgradedFirePause;
 
16017
                                        
 
16018
        local   int             _tempShortHit;
 
16019
 
 
16020
        _tempShortHit = weaponShortHitUpgrade(_player, _weap);
 
16021
                        
 
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;
 
16027
 
 
16028
 
 
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));
 
16035
        
 
16036
        
 
16037
        // avoid division by 0
 
16038
        _fFirePauseInSecs = (float)_upgradedFirePause / 1000.0;
 
16039
        if(_fFirePauseInSecs == 0.0){
 
16040
                _fFirePauseInSecs = 0.001;
 
16041
        }
 
16042
 
 
16043
        if(_weap.numRounds > 0){
 
16044
 
 
16045
                // avoid division by 0
 
16046
                if(_weap.reloadTime == 0){
 
16047
                        _fReloadTimeInSecs = 0.001;
 
16048
                }else{
 
16049
                        _fReloadTimeInSecs = (float)_weap.reloadTime / 1000.0;
 
16050
                }
 
16051
 
 
16052
                _fFireRatePerSec = 1.0 / ((_fReloadTimeInSecs + (_fFirePauseInSecs * (float)(_weap.numRounds - 1))) / (float)_weap.numRounds);
 
16053
        }else{
 
16054
                _fFireRatePerSec = 1.0 / _fFirePauseInSecs;
 
16055
        }
 
16056
 
 
16057
 
 
16058
        _fShortRangeDamagePerSec = _fFireRatePerSec * ((float)_upgradedDamage / 100.0 * (float)_upgradedShortHit);
 
16059
        _fLongRangeDamagePerSec = _fFireRatePerSec * ((float)_upgradedDamage / 100.0 * (float)_upgradedLongHit);
 
16060
 
 
16061
        _fFirePowerPerSec = (_fShortRangeDamagePerSec + _fLongRangeDamagePerSec) / 2.0;
 
16062
 
 
16063
        return _fFirePowerPerSec;
 
16064
}
 
16065
 
 
16066
// firepower of a droid (including upgrades)
 
16067
function float objBaseDamagePerSec(BASEOBJ _obj)
 
16068
{
 
16069
        // Make sure droid has a weapon
 
16070
        if(_obj.weapon == NULLSTAT){
 
16071
                return 0.0;
 
16072
        }
 
16073
 
 
16074
        return weaponDamagePerSec(_obj.player, _obj.weapon);
 
16075
}
 
16076
 
 
16077
function float enemyFirepowerInRange(int _x, int _y, int _range)
 
16078
{
 
16079
        local   int             _enemy;
 
16080
        local   float   _fFirePower;
 
16081
 
 
16082
        _fFirePower = 0.0;
 
16083
        _enemy = 0;
 
16084
        while(_enemy < MAX_PLAYERS)
 
16085
        {
 
16086
                if(_enemy != me and !allianceExistsBetween(_enemy, me))
 
16087
                {
 
16088
                        _fFirePower = _fFirePower + playerFirepowerInRange(_enemy, _x, _y, _range);
 
16089
                }
 
16090
                _enemy++;
 
16091
        }
 
16092
 
 
16093
        return _fFirePower;
 
16094
}
 
16095
 
 
16096
function float friendlyFirepowerInRange(int _x, int _y, int _range)
 
16097
{
 
16098
        local   int             _allyOrMe;
 
16099
        local   float   _fFirePower;
 
16100
 
 
16101
        _fFirePower = 0.0;
 
16102
        _allyOrMe = 0;
 
16103
        while(_allyOrMe < MAX_PLAYERS)
 
16104
        {
 
16105
                if(_allyOrMe == me or allianceExistsBetween(_allyOrMe, me))
 
16106
                {
 
16107
                        _fFirePower = _fFirePower + playerFirepowerInRange(_allyOrMe, _x, _y, _range);
 
16108
                }
 
16109
                _allyOrMe++;
 
16110
        }
 
16111
 
 
16112
        return _fFirePower;
 
16113
}
 
16114
 
 
16115
function float playerFirepowerInRange(int _player, int _x, int _y, int _range)
 
16116
{
 
16117
        local   float           _fFirePower;
 
16118
        local   DROID           _droid;
 
16119
        local   STRUCTURE       _structure;
 
16120
 
 
16121
        _fFirePower = 0.0;
 
16122
 
 
16123
        InitEnumDroids(_player,me);
 
16124
        _droid = EnumDroid();
 
16125
        while(_droid != NULLOBJECT)
 
16126
        {
 
16127
                if(!isVtol(_droid))
 
16128
                {
 
16129
                        if(objHasWeapon(_droid))
 
16130
                        {
 
16131
                                if(distBetweenTwoPoints(_x, _y, _droid.x, _droid.y) < _range)
 
16132
                                {
 
16133
                                        _fFirePower = _fFirePower + objBaseDamagePerSec(_droid);
 
16134
                                }
 
16135
                        }
 
16136
                }
 
16137
                _droid = EnumDroid();
 
16138
        }
 
16139
 
 
16140
        //iterate through all strucrures
 
16141
        initEnumStruct(TRUE,derrick,_player,me);
 
16142
        _structure = enumStruct();
 
16143
        while(_structure != NULLOBJECT)
 
16144
        {
 
16145
                if(objHasWeapon(_structure))
 
16146
                {
 
16147
                        if(structureComplete(_structure))
 
16148
                        {
 
16149
                                if(distBetweenTwoPoints(_x, _y, _structure.x, _structure.y) < _range)
 
16150
                                {
 
16151
                                        _fFirePower = _fFirePower + objBaseDamagePerSec(_structure);
 
16152
                                }
 
16153
                        }
 
16154
                }
 
16155
                _structure = enumStruct();
 
16156
        }
 
16157
 
 
16158
        return _fFirePower;
 
16159
}
 
16160
 
 
16161
function float groupFirepower(GROUP _group)
 
16162
{
 
16163
        local   int             _bucket;
 
16164
        local   float   _fFirePower;
 
16165
        local   DROID   _droid;
 
16166
 
 
16167
        _fFirePower = 0.0;
 
16168
 
 
16169
        _bucket = initIterateGroupCmd(_group,true,true,true);
 
16170
        _droid = iterateGroupCmd(_group, _bucket);
 
16171
        while(_droid != NULLOBJECT)
 
16172
        {
 
16173
                _fFirePower = _fFirePower + objBaseDamagePerSec(_droid);
 
16174
                _droid = iterateGroupCmd(_group, _bucket);
 
16175
        }
 
16176
 
 
16177
        return _fFirePower;
 
16178
}
 
16179
 
 
16180
function float groupHP(GROUP _group)
 
16181
{
 
16182
        local   int             _bucket;
 
16183
        local   float   _fDroidHP;
 
16184
        local   DROID   _droid;
 
16185
 
 
16186
        _fDroidHP = 0.0;
 
16187
 
 
16188
        _bucket = initIterateGroupCmd(_group,true,true,true);
 
16189
        _droid = iterateGroupCmd(_group, _bucket);
 
16190
        while(_droid != NULLOBJECT)
 
16191
        {
 
16192
                _fDroidHP = _fDroidHP + (float)_droid.hitPoints;
 
16193
                _droid = iterateGroupCmd(_group, _bucket);
 
16194
        }
 
16195
 
 
16196
        return _fDroidHP;
 
16197
}
 
16198
 
 
16199
 
 
16200
function int totalEnemyWeapObjHPInRange(int _x, int _y, int _range, bool _bVtols)
 
16201
{
 
16202
        local   int             _enemy,_enemyHP;
 
16203
 
 
16204
        _enemyHP = 0;
 
16205
        _enemy = 0;
 
16206
        while(_enemy < MAX_PLAYERS)
 
16207
        {
 
16208
                if(_enemy != me and !allianceExistsBetween(_enemy, me))
 
16209
                {
 
16210
                        _enemyHP = _enemyHP + totalPlayerWeapObjHPInRange(_enemy, _x, _y, _range, _bVtols);
 
16211
                }
 
16212
                _enemy++;
 
16213
        }
 
16214
 
 
16215
        return _enemyHP;
 
16216
}
 
16217
 
 
16218
function int totalFriendlyWeapObjHPInRange(int _x, int _y, int _range, bool _bVtols)
 
16219
{
 
16220
        local   int             _allyOrMe,_friendlyHP;
 
16221
 
 
16222
        _friendlyHP = 0;
 
16223
        _allyOrMe = 0;
 
16224
        while(_allyOrMe < MAX_PLAYERS)
 
16225
        {
 
16226
                if(_allyOrMe == me or allianceExistsBetween(_allyOrMe, me))
 
16227
                {
 
16228
                        _friendlyHP = _friendlyHP + totalPlayerWeapObjHPInRange(_allyOrMe, _x, _y, _range, _bVtols);
 
16229
                }
 
16230
                _allyOrMe++;
 
16231
        }
 
16232
 
 
16233
        return _friendlyHP;
 
16234
}
 
16235
 
 
16236
 
 
16237
function int totalPlayerWeapObjHPInRange(int _player, int _x, int _y,
 
16238
                                                                                 int _range, bool _bVtols)
 
16239
{
 
16240
        local   int                     _hp;
 
16241
        local   DROID           _droid;
 
16242
        local   STRUCTURE       _structure;
 
16243
 
 
16244
        _hp = 0;
 
16245
 
 
16246
        InitEnumDroids(_player,me);
 
16247
        _droid = EnumDroid();
 
16248
        while(_droid != NULLOBJECT)
 
16249
        {
 
16250
                if(!isVtol(_droid) or _bVtols)
 
16251
                {
 
16252
                        if(objHasWeapon(_droid))
 
16253
                        {
 
16254
                                if(distBetweenTwoPoints(_x, _y, _droid.x, _droid.y) < _range)
 
16255
                                {
 
16256
                                        _hp = _hp + _droid.hitPoints;
 
16257
                                }
 
16258
                        }
 
16259
                }
 
16260
                _droid = EnumDroid();
 
16261
        }
 
16262
 
 
16263
        //iterate through all strucrures
 
16264
        initEnumStruct(TRUE,derrick,_player,me);
 
16265
        _structure = enumStruct();
 
16266
        while(_structure != NULLOBJECT)
 
16267
        {
 
16268
                if(objHasWeapon(_structure))
 
16269
                {
 
16270
                        if(structureComplete(_structure))
 
16271
                        {
 
16272
                                if(distBetweenTwoPoints(_x, _y, _structure.x, _structure.y) < _range)
 
16273
                                {
 
16274
                                        _hp = _hp + _structure.hitPoints;
 
16275
                                }
 
16276
                        }
 
16277
                }
 
16278
                _structure = enumStruct();
 
16279
        }
 
16280
 
 
16281
        return _hp;
 
16282
}
 
16283
 
 
16284
function bool isTankTemplate(TEMPLATE _tmpl)
 
16285
{
 
16286
        local   int     _tmplIndex,_techIndex;
 
16287
 
 
16288
        _techIndex = 0;
 
16289
        while(_techIndex < numBranches)
 
16290
        {
 
16291
                _tmplIndex = 0;
 
16292
                while(_tmplIndex < numTemplates[_techIndex])
 
16293
                {
 
16294
                        if(_tmpl == tmpl[_techIndex][_tmplIndex])
 
16295
                        {
 
16296
                                return true;
 
16297
                        }
 
16298
                        _tmplIndex++;
 
16299
                }
 
16300
 
 
16301
                _techIndex++;
 
16302
        }
 
16303
 
 
16304
        return false;
 
16305
}
 
16306
 
 
16307
function void resetOilDefendCoords()
 
16308
{
 
16309
        tOilAttackBegin = none;         // when enemy started attacking oil derrick
 
16310
        tLastOilAttack = none;
 
16311
        lastOilAttackedX = none;        // position of the attacked oil derrick
 
16312
        lastOilAttackedY = none;
 
16313
}
 
16314
 
 
16315
event evUpdateMapRevealFactor(inactive)
 
16316
{
 
16317
        updateMapRevealFactor();
 
16318
}
 
16319
 
 
16320
function void updateMapRevealFactor()
 
16321
{
 
16322
        local   int             _x,_y,_numUnrevealedTiles,_totalTiles,_step;
 
16323
 
 
16324
        _numUnrevealedTiles = 0;
 
16325
 
 
16326
        _step = 3;
 
16327
 
 
16328
        _x = 1;
 
16329
        while(_x < (mapWidth - 1))
 
16330
        {
 
16331
                _y = 1;
 
16332
                while(_y < (mapHeight - 1))
 
16333
                {
 
16334
                        if(!mapTileVisible(me, _x,_y))
 
16335
                        {
 
16336
                                _numUnrevealedTiles++;
 
16337
                        }
 
16338
                        _y = _y + _step;
 
16339
                }
 
16340
                _x = _x + _step;
 
16341
        }
 
16342
 
 
16343
        _totalTiles = mapWidth * mapHeight;
 
16344
 
 
16345
        fMapRevealFactor = MAP_REVEAL_FAC_UBOUND -
 
16346
                                        (float)(_totalTiles - max(0, _numUnrevealedTiles * _step)) /
 
16347
                                        (float)_totalTiles;
 
16348
}
 
16349
 
 
16350
function DROID closestEnemyDroidByType(int _x, int _y, int _range, int _type)
 
16351
{
 
16352
        local   DROID   _droid,_closestDroid;
 
16353
        local   int             _closestDist,_tempDist,_enemy;
 
16354
 
 
16355
        _closestDist = 99999;
 
16356
        _closestDroid = NULLOBJECT;
 
16357
 
 
16358
        _enemy = 0;
 
16359
        while(_enemy < MAX_PLAYERS)
 
16360
        {
 
16361
                if(!allianceExistsBetween(_enemy, me) and _enemy != me)
 
16362
                {
 
16363
                        InitEnumDroids(_enemy, me);
 
16364
                        _droid = EnumDroid();
 
16365
                        while(_droid != NULLOBJECT)
 
16366
                        {
 
16367
                                if(_type < 0 or _droid.droidType == _type)
 
16368
                                {
 
16369
                                        _tempDist = distBetweenTwoPoints(_droid.x, _droid.y, _x, _y);
 
16370
                                        if(_range < 0 or _tempDist < _range)
 
16371
                                        {
 
16372
                                                if(_tempDist < _closestDist)
 
16373
                                                {
 
16374
                                                        _closestDist = _tempDist;
 
16375
                                                        _closestDroid = _droid;
 
16376
                                                }
 
16377
                                        }
 
16378
                                }
 
16379
                                _droid = EnumDroid();
 
16380
                        }
 
16381
                }
 
16382
 
 
16383
                _enemy++;
 
16384
        }
 
16385
 
 
16386
        return _closestDroid;
 
16387
}
 
16388
 
 
16389
/* Thank someone */
 
16390
function string strGratitude()
 
16391
{
 
16392
        dice = random(10);
 
16393
 
 
16394
        if(dice < 5){
 
16395
                return "thanks";
 
16396
        }else if(dice < 7){
 
16397
                return "thanks!!";
 
16398
        }else{
 
16399
                return "thank you";
 
16400
        }
 
16401
        
 
16402
        return "thanks";
 
16403
}
 
16404
 
 
16405
function void setPhase(int _phase, int _timeout)
 
16406
{
 
16407
        phase = _phase;
 
16408
        tPhase = _timeout;
 
16409
}
 
16410
 
 
16411
function bool canSeePlayerBase(int _player)
 
16412
{
 
16413
        return seeBase[_player];
 
16414
}
 
16415
 
 
16416
function bool canSeeLoc(int _x, int _y)
 
16417
{
 
16418
        updatePlayerTileVis(me);
 
16419
        return checkVisibleTile(me, _x / TILE, _y / TILE);
 
16420
}
 
16421
 
 
16422
function bool enemyTargetInRange(int _enemy, int _x, int _y, int _range)
 
16423
{
 
16424
        local bool _bHaveTarget;
 
16425
        
 
16426
        _bHaveTarget = structInRangeVis(me, _enemy, _x, _y, _range);
 
16427
        
 
16428
        if(!_bHaveTarget)
 
16429
        {
 
16430
                _bHaveTarget = droidInRangeVis(me, _enemy, _x, _y, _range);
 
16431
        }
 
16432
        
 
16433
        return _bHaveTarget;
 
16434
}
 
16435
 
 
16436
function BASEOBJ findEnemyTargetInRange(int _enemy, int _x, int _y, int _range, bool _bStructures, bool _bDroids)
 
16437
{
 
16438
        local BASEOBJ _target;
 
16439
        
 
16440
        // structures
 
16441
        if(_bStructures)
 
16442
        {
 
16443
                _target = getClosestEnemyStructByType(_x, _y, _range, REF_FACTORY, _enemy);
 
16444
 
 
16445
                if(_target == NULLOBJECT)
 
16446
                {
 
16447
                        _target = getClosestEnemyStructByType(_x, _y, _range, REF_CYBORG_FACTORY, _enemy);
 
16448
                }
 
16449
                
 
16450
                if(_target == NULLOBJECT)
 
16451
                {
 
16452
                        _target = getClosestEnemyStructByType(_x, _y, _range, REF_HQ, _enemy);
 
16453
                }
 
16454
                
 
16455
                if(_target == NULLOBJECT)
 
16456
                {
 
16457
                        _target = getClosestEnemyStructByType(_x, _y, _range, REF_POWER_GEN, _enemy);
 
16458
                }
 
16459
 
 
16460
                // find any
 
16461
                if(_target == NULLOBJECT)
 
16462
                {
 
16463
                        _target = getClosestEnemyStructByType(_x, _y, _range, NONE, _enemy);
 
16464
                }
 
16465
        }
 
16466
 
 
16467
        // droids
 
16468
        if(_bDroids and _target == NULLOBJECT)
 
16469
        {
 
16470
                _target = getClosestEnemyDroidByType(_x, _y, _range, NONE, true, _enemy);
 
16471
        }
 
16472
 
 
16473
        return _target;
 
16474
}
 
16475
 
 
16476
function PROPULSION getBestTankPropulsion()
 
16477
{
 
16478
        local   int     _index;
 
16479
        
 
16480
        _index = numTankPropulsions - 1;
 
16481
        while(_index >= 0)
 
16482
        {
 
16483
                if(isComponentAvailable(me, tankPropulsion[_index]))
 
16484
                {
 
16485
                        dbg("best prop index is " & _index, me);
 
16486
                        return tankPropulsion[_index];
 
16487
                }
 
16488
                _index--;
 
16489
        }
 
16490
        
 
16491
        dbg("no prop ", me);
 
16492
        return NULLSTAT;
 
16493
}
 
16494
 
 
16495
function BODY getBestTankBody(int _factoryCapacity)
 
16496
{
 
16497
        local   int     _index;
 
16498
        
 
16499
        _index = numTankBodies - 1;
 
16500
        while(_index >= 0)
 
16501
        {
 
16502
                if(isComponentAvailable(me, tankBody[_index]))
 
16503
                {
 
16504
                        // make sure can be built by factory
 
16505
                        if(getBodySize(tankBody[_index]) <= _factoryCapacity)
 
16506
                        {
 
16507
                                dbg("best body index is " & _index, me);
 
16508
                                return tankBody[_index];
 
16509
                        }
 
16510
                }
 
16511
                _index--;
 
16512
        }
 
16513
        
 
16514
        dbg("no body for size " & _factoryCapacity & " (" & getBodySize(tankBody[0]) & ")", me);
 
16515
        return NULLSTAT;
 
16516
}
 
16517
 
 
16518
function WEAPON getBestTankATWeapon()
 
16519
{
 
16520
        local   int     _index,_bestIndex,_bestDamage,_damage;
 
16521
        local   WEAPON  _bestWeapon;
 
16522
        
 
16523
        _bestDamage = NONE;
 
16524
        _bestIndex = NONE;
 
16525
        
 
16526
        _index = 0;
 
16527
        while(_index < numTankATWeapons)
 
16528
        {
 
16529
                if(isComponentAvailable(me, tankATWeapon[_index]))
 
16530
                {
 
16531
                        _damage = (int)weaponDamagePerSec(me, tankATWeapon[_index]);
 
16532
                        dbg("damage of " & _index & " is " & _damage, me);
 
16533
                        if((_damage > _bestDamage) || (_bestIndex == NONE))
 
16534
                        {
 
16535
                                dbg("_bestIndex = " & _index , me);
 
16536
                                _bestIndex = _index;
 
16537
                                _bestWeapon = tankATWeapon[_index];
 
16538
                                _bestDamage =_damage;
 
16539
                        }
 
16540
                }
 
16541
                _index++;
 
16542
        }
 
16543
        
 
16544
        dbg("best weapon index is " & _bestIndex, me);
 
16545
 
 
16546
        return _bestWeapon;             // can be NULLSTAT
 
16547
}
 
16548
 
 
16549
function TEMPLATE getBestTankATTemplate(int _factoryCapacity)
 
16550
{
 
16551
        local   TEMPLATE        _newTemplate;
 
16552
        local   BODY            _bestBody;
 
16553
        local   PROPULSION      _bestPropulsion;
 
16554
        local   WEAPON          _bestWeapon;
 
16555
        
 
16556
        _bestBody = getBestTankBody(_factoryCapacity);
 
16557
        _bestPropulsion = getBestTankPropulsion();
 
16558
        _bestWeapon = getBestTankATWeapon();
 
16559
        
 
16560
        if(_bestBody != NULLSTAT and
 
16561
                _bestPropulsion != NULLSTAT and
 
16562
                _bestWeapon != NULLSTAT)
 
16563
        {
 
16564
                _newTemplate = assembleWeaponTemplate(me, _bestBody, _bestPropulsion, _bestWeapon);
 
16565
        }
 
16566
 
 
16567
        return _newTemplate;    //      can be NULLTEMPLATE
 
16568
}