Diff
checker
テキスト
テキスト
画像
ドキュメント
Excel
フォルダ
Legal
Enterprise
デスクトップ
料金
ログイン
Diffchecker デスクトップのダウンロード
テキスト比較
2 つのテキスト ファイルの違いを見つける
ツール
履歴
ライブエディター
未変更行を折りたたむ
折り返しなし
レイアウト
分割
統合
比較精度
スマート
単語
文字
シンタックスハイライト
構文を選択
無視
テキスト変換
最初の差分へ移動
入力を編集
Diffchecker Desktop
Diffcheckerを実行する最も安全な方法。Diffchecker Desktopアプリを入手:あなたの差分はコンピューターから出ることはありません!
Desktopを入手
Untitled diff
作成日
9 年前
差分は期限切れになりません
クリア
エクスポート
共有
説明
33 削除
行
合計
削除
文字
合計
削除
この機能を引き続き使用するには、アップグレードしてください
Diff
checker
Pro
価格を見る
835 行
すべてコピー
32 追加
行
合計
追加
文字
合計
追加
この機能を引き続き使用するには、アップグレードしてください
Diff
checker
Pro
価格を見る
834 行
すべてコピー
/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
// general ai for skirmish game
// general ai for skirmish game
/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
// Warzone2100, Pumpkin Studios,
// Warzone2100, Pumpkin Studios,
// alex lee.98/99.
// alex lee.98/99.
//
//
/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
//Tile in world units
//Tile in world units
#define TILE 128
#define TILE 128
#define NONE (-1)
#define NONE (-1)
// These are final rules of the lexical parser
// These are final rules of the lexical parser
#define R_REQUEST_HELP "help me"
#define R_REQUEST_HELP "help me"
#define R_REQUEST_BEACON "drop a beacon"
#define R_REQUEST_BEACON "drop a beacon"
#define R_REPORT_SAFETY "i'm ok"
#define R_REPORT_SAFETY "i'm ok"
#define R_REQUEST_ALLY "ally me"
#define R_REQUEST_ALLY "ally me"
// These are our own messages - lexical parser should be able to handle them
// These are our own messages - lexical parser should be able to handle them
#define M_REQUEST_HELP "help me!!"
#define M_REQUEST_HELP "help me!!"
#define M_REQUEST_BEACON "drop a beacon"
#define M_REQUEST_BEACON "drop a beacon"
#define M_AFFIRMATIVE_OK "ok"
#define M_AFFIRMATIVE_OK "ok"
#define M_AFFIRMATIVE_ROGER "roger"
#define M_AFFIRMATIVE_ROGER "roger"
#define M_ANNOYED "bug off"
#define M_ANNOYED "bug off"
#define M_HELPERS_KILLED "that was all I had.."
#define M_HELPERS_KILLED "that was all I had.."
#define M_HELP_NO_UNITS "I don't have anything"
#define M_HELP_NO_UNITS "I don't have anything"
#define MAX_PROBABILITY 100
#define MAX_PROBABILITY 100
// Base threat range in world units
// Base threat range in world units
#define W_BASE_THREAT_RANGE ((17 + (mapWidth + mapHeight) / 2 / 35) * TILE)
#define W_BASE_THREAT_RANGE ((17 + (mapWidth + mapHeight) / 2 / 35) * TILE)
#define ALL_ALLIES -1
#define ALL_ALLIES -1
#define BASE_DEFEND_DURATION (3 * 60)
#define BASE_DEFEND_DURATION (3 * 60)
// Delay before we repeat our request, in seconds
// Delay before we repeat our request, in seconds
#define HELP_REQUEST_INTERVAL (3 * 60)
#define HELP_REQUEST_INTERVAL (3 * 60)
//in secs
//in secs
#define BEACON_TIMEOUT 30
#define BEACON_TIMEOUT 30
#define MAX_DROIDS 150
#define MAX_DROIDS 150
//range for trucks to look for more oil
//range for trucks to look for more oil
#define MORE_OIL_RANGE (10 * TILE)
#define MORE_OIL_RANGE (10 * TILE)
//don't try to build on oil if there's threat within this range
//don't try to build on oil if there's threat within this range
#define OIL_THREAT_RANGE (9 * TILE)
#define OIL_THREAT_RANGE (9 * TILE)
コピー
コピー済み
コピー
コピー済み
#define MAX_TRUCKS
12
#define MAX_TRUCKS
15
#define MIN_TRUCKS
5
#define MIN_TRUCKS
12
//Enter power saving mode when lower than this
//Enter power saving mode when lower than this
#define LOW_POWER 250
#define LOW_POWER 250
//Target type values
//Target type values
#define NO_TARGET_VALUE 0
#define NO_TARGET_VALUE 0
#define DROID_TARGET_VALUE 1
#define DROID_TARGET_VALUE 1
#define OTHER_TARGET_VALUE 2
#define OTHER_TARGET_VALUE 2
#define DEFENSE_TARGET_VALUE 3
#define DEFENSE_TARGET_VALUE 3
#define RESEARCH_TARGET_VALUE 4
#define RESEARCH_TARGET_VALUE 4
#define HQ_TARGET_VALUE 5
#define HQ_TARGET_VALUE 5
#define OIL_TARGET_VALUE 6
#define OIL_TARGET_VALUE 6
#define FACTORY_TARGET_VALUE 7
#define FACTORY_TARGET_VALUE 7
#define UNLIMITED (-1)
#define UNLIMITED (-1)
#define AA_THREAT_RANGE (TILE * 12)
#define AA_THREAT_RANGE (TILE * 12)
#define MAX_DEFENDERS_RADIUS (TILE * 40)
#define MAX_DEFENDERS_RADIUS (TILE * 40)
#define MAX_VTOL_DEFEND_RADIUS (TILE * 25)
#define MAX_VTOL_DEFEND_RADIUS (TILE * 25)
// AI will remember max this number of structures
// AI will remember max this number of structures
#define MAX_REBUILD_STRUCT 100
#define MAX_REBUILD_STRUCT 100
//Total number of technology branches
//Total number of technology branches
#define TECHS 2
#define TECHS 2
//How many best templates to choose from when deciding what template to build
//How many best templates to choose from when deciding what template to build
コピー
コピー済み
コピー
コピー済み
#define MAX_RANDOM_TEMPLATES
4
#define MAX_RANDOM_TEMPLATES
6
private int me; // player for this instance.
private int me; // player for this instance.
public int tileExpand; // rate of exploration
public int tileExpand; // rate of exploration
public int numScouts[TECHS],maxScouts[TECHS]; // aim for...
public int numScouts[TECHS],maxScouts[TECHS]; // aim for...
public int numDefenders[TECHS],maxDefenders[TECHS];
public int numDefenders[TECHS],maxDefenders[TECHS];
public int numAttackers[TECHS],maxAttackers[TECHS];
public int numAttackers[TECHS],maxAttackers[TECHS];
public int numCyborgs[TECHS],maxCyborgs[TECHS];
public int numCyborgs[TECHS],maxCyborgs[TECHS];
public int branchDefault,branchVTOL,techCount[TECHS],maxVtolFacs[TECHS],maxIdleRes[TECHS],
public int branchDefault,branchVTOL,techCount[TECHS],maxVtolFacs[TECHS],maxIdleRes[TECHS],
maxVTOLs[TECHS],numVtolTargets,vtolTargetWeight[10],numRebuildStat[TECHS];
maxVTOLs[TECHS],numVtolTargets,vtolTargetWeight[10],numRebuildStat[TECHS];
public RESEARCHSTAT tech[TECHS][30]; //technology for different research branches
public RESEARCHSTAT tech[TECHS][30]; //technology for different research branches
public STRUCTURESTAT vtolTarget[10],rebuildStat[TECHS][2];
public STRUCTURESTAT vtolTarget[10],rebuildStat[TECHS][2];
// structures
// structures
private int baseX,baseY,minx,miny,maxx,maxy;
private int baseX,baseY,minx,miny,maxx,maxy;
public int numStructs,numIncendrys,numDefStructs,numExtraStructs[TECHS],numWallWeaps,numBaseStruct,numLightCyborgs,numFundamental;
public int numStructs,numIncendrys,numDefStructs,numExtraStructs[TECHS],numWallWeaps,numBaseStruct,numLightCyborgs,numFundamental;
private STRUCTURESTAT structChoice[5];
private STRUCTURESTAT structChoice[5];
コピー
コピー済み
コピー
コピー済み
public STRUCTURESTAT incendrys[
8
],structs[13],defStructs[26],extraStructs[TECHS][6],wallWeaps[11];
public STRUCTURESTAT incendrys[
10
],structs[13],defStructs[26],extraStructs[TECHS][6],wallWeaps[11];
public STRUCTURESTAT sensorTower,wall,cornerWall,resLab,powGen,playerHQ,lassat,factory,derrick,cybFactory,
public STRUCTURESTAT sensorTower,wall,cornerWall,resLab,powGen,playerHQ,lassat,factory,derrick,cybFactory,
コピー
コピー済み
コピー
コピー済み
vtolDefStruct[
5
],vtolPad,vtolFactory,uplink,baseStruct[8];
vtolDefStruct[
9
],vtolPad,vtolFactory,uplink,baseStruct[8];
public STRUCTURESTAT powModule,facModule,resModule,vtolModule;
public STRUCTURESTAT powModule,facModule,resModule,vtolModule;
public int extraStruct;
public int extraStruct;
// unit templates
// unit templates
public int numTemplates[TECHS];
public int numTemplates[TECHS];
public TEMPLATE tmpl[TECHS][70];
public TEMPLATE tmpl[TECHS][70];
コピー
コピー済み
コピー
コピー済み
private TEMPLATE tmplChoice[
5
];
private TEMPLATE tmplChoice[
67
];
コピー
コピー済み
コピー
コピー済み
public TEMPLATE cybTempl[
10
],superCyb[
4
],cybMechanic,cybEngineer,hovertruck;
public TEMPLATE cybTempl[
7
],superCyb[
21
],cybMechanic,cybEngineer,hovertruck;
コピー
コピー済み
コピー
コピー済み
public TEMPLATE vtols[
18
];
public TEMPLATE vtols[
20
];
public int numVtolTemplates;
public int numVtolTemplates;
コピー
コピー済み
コピー
コピー済み
public TEMPLATE sense[
11
];
public TEMPLATE sense[
8
];
public int numSenseTemplates;
public int numSenseTemplates;
コピー
コピー済み
コピー
コピー済み
public TEMPLATE constructor,repair
;
public TEMPLATE constructor,repair
[7]
;
public int numRepairUnits;
public int numRepairUnits;
コピー
コピー済み
コピー
コピー済み
public int numSensorUnits;
public int numRepairTemplates;
//defend
//defend
private GROUP defendGroup;
private GROUP defendGroup;
private bool defendbusy;
private bool defendbusy;
private BASEOBJ defendObj;
private BASEOBJ defendObj;
public RESEARCHSTAT nexusDefence;
public RESEARCHSTAT nexusDefence;
private RESEARCHSTAT research;
private RESEARCHSTAT research;
//build
//build
private GROUP buildGroup;
private GROUP buildGroup;
private int buildX,buildY,buildX2,buildY2;
private int buildX,buildY,buildX2,buildY2;
public FEATURESTAT oilRes;
public FEATURESTAT oilRes;
// scout
// scout
private GROUP scoutGroup;
private GROUP scoutGroup;
private int scoutX,scoutY;
private int scoutX,scoutY;
private int scoutTLX,scoutTLY,scoutW,scoutH;
private int scoutTLX,scoutTLY,scoutW,scoutH;
// attack
// attack
private GROUP attackGroup;
private GROUP attackGroup;
コピー
コピー済み
コピー
コピー済み
private BASEOBJ attackObj,allOutAttack,vtolGrAttackObj[
10
];
private BASEOBJ attackObj,allOutAttack,vtolGrAttackObj[
39
];
// vtols
// vtols
private GROUP vtolDefendGr,vtolAttackGr[10];
private GROUP vtolDefendGr,vtolAttackGr[10];
// generic
// generic
private STRUCTURE structure,structure2,rebuildObj[100];
private STRUCTURE structure,structure2,rebuildObj[100];
private DROID droid;
private DROID droid;
private FEATURE feature;
private FEATURE feature;
private BASEOBJ baseobj,baseobj2;
private BASEOBJ baseobj,baseobj2;
private int count,count2,result,result2,tempx,tempy;
private int count,count2,result,result2,tempx,tempy;
private bool boolResult,boolResult2;
private bool boolResult,boolResult2;
private bool powerSave,_DEBUG,bRunning;
private bool powerSave,_DEBUG,bRunning;
// Hopefully this will be at least as large as MAX_PLAYERS... Why can't I just use MAX_PLAYERS as the array size?!
// Hopefully this will be at least as large as MAX_PLAYERS... Why can't I just use MAX_PLAYERS as the array size?!
// P.S. And why can't I put a comment on the same line as a #define??!! Gah, who cares if the lua2 branch works, lets switch to it, anyway.
// P.S. And why can't I put a comment on the same line as a #define??!! Gah, who cares if the lua2 branch works, lets switch to it, anyway.
#define MAX_PLAYERS_HACK 17
#define MAX_PLAYERS_HACK 17
private int allianceTime[MAX_PLAYERS_HACK];
private int allianceTime[MAX_PLAYERS_HACK];
private int sender,x,y,beaconX[8],beaconY[8],tBeacon[8],
private int sender,x,y,beaconX[8],beaconY[8],tBeacon[8],
tLastHelpRequest,lastHelpPlayer,tHelp,tHelpTimeout,helpX,helpY;
tLastHelpRequest,lastHelpPlayer,tHelp,tHelpTimeout,helpX,helpY;
private string message;
private string message;
private int defendX,defendY,__defendRadiusUnused,tDefendStart,tDefendTimeout,
private int defendX,defendY,__defendRadiusUnused,tDefendStart,tDefendTimeout,
defendMoveType,baseRange,curTech,numVtolAttackGroups,numAttackVtols,
defendMoveType,baseRange,curTech,numVtolAttackGroups,numAttackVtols,
numDefendVtols,rebuildStructX[MAX_REBUILD_STRUCT],rebuildStructY[MAX_REBUILD_STRUCT],countRebuildStruct;
numDefendVtols,rebuildStructX[MAX_REBUILD_STRUCT],rebuildStructY[MAX_REBUILD_STRUCT],countRebuildStruct;
private STRUCTURESTAT rebuildStructStat[MAX_REBUILD_STRUCT];
private STRUCTURESTAT rebuildStructStat[MAX_REBUILD_STRUCT];
private STRUCTURESTAT fundamentalBeingBuilt;
private STRUCTURESTAT fundamentalBeingBuilt;
private int order; // callback global
private int order; // callback global
/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
// triggers.
// triggers.
#region triggers
#region triggers
trigger reachedTr (CALL_DROID_REACH_LOCATION, me, ref droid, ref order);
trigger reachedTr (CALL_DROID_REACH_LOCATION, me, ref droid, ref order);
コピー
コピー済み
コピー
コピー済み
trigger buildExpandTr (every,
6
00);
trigger buildExpandTr (every,
3
00);
trigger fortifyTr (every,
1000
);
trigger fortifyTr (every,
400
);
trigger upgradeStructuresTr (every,
360
);
trigger upgradeStructuresTr (every,
50
);
trigger conDroidsTr (every,
9
00); // was 1400
trigger conDroidsTr (every,
2
00); // was 1400
trigger repairDroidsTr (every,
2600
);
trigger repairDroidsTr (every,
400);
trigger sensorDroidsTr (every, 400
);
trigger basedetailsTr (every, 600 );
trigger basedetailsTr (every, 600 );
trigger buildDerrickTr (every, 80 );
trigger buildDerrickTr (every, 80 );
コピー
コピー済み
コピー
コピー済み
trigger buildOilDefenseOrRetreatTr (every,
120
);
trigger buildOilDefenseOrRetreatTr (every,
200
);
trigger incendryTr (every,
25
0 );
trigger incendryTr (every,
12
0 );
trigger buildPowerGeneratorsTr (every, 80 );
trigger buildPowerGeneratorsTr (every, 80 );
trigger buildBaseTr (every, 150 );
trigger buildBaseTr (every, 150 );
trigger finishStructsTr (every, 210);
trigger finishStructsTr (every, 210);
trigger droidBuiltTr (CALL_NEWDROID,me, ref droid,ref structure);
trigger droidBuiltTr (CALL_NEWDROID,me, ref droid,ref structure);
trigger structBuiltTr (CALL_STRUCTBUILT, me, ref droid, ref structure);
trigger structBuiltTr (CALL_STRUCTBUILT, me, ref droid, ref structure);
trigger droidDestroyedTr (CALL_DROID_DESTROYED, me, ref droid);
trigger droidDestroyedTr (CALL_DROID_DESTROYED, me, ref droid);
trigger structureDestroyedTr (CALL_STRUCT_DESTROYED, me, ref structure);
trigger structureDestroyedTr (CALL_STRUCT_DESTROYED, me, ref structure);
trigger rebuildStructureTr (every, 50);
trigger rebuildStructureTr (every, 50);
trigger consolidateEventTr (every, 3100);
trigger consolidateEventTr (every, 3100);
コピー
コピー済み
コピー
コピー済み
trigger factoryEventTr (every,
170
);
trigger factoryEventTr (every,
90
);
trigger cyborgFactoryEventTr (every,
170
);
trigger cyborgFactoryEventTr (every,
90
);
trigger chooseScoutAreaTr (every, 200 );
trigger chooseScoutAreaTr (every, 200 );
trigger expandScoutAreaTr (every, 600 );
trigger expandScoutAreaTr (every, 600 );
trigger scoutMainTr (every, 150 );
trigger scoutMainTr (every, 150 );
trigger newObjectReportTr (CALL_OBJ_SEEN, me, ref baseobj, ref baseobj2);
trigger newObjectReportTr (CALL_OBJ_SEEN, me, ref baseobj, ref baseobj2);
コピー
コピー済み
コピー
コピー済み
trigger attackStuffTr (every,
3
00 );
trigger attackStuffTr (every,
2
00 );
trigger allOutAttackTr (every,
4
000);
trigger allOutAttackTr (every,
2
000);
trigger defendWatchTr (CALL_STRUCT_ATTACKED, me, ref structure, ref baseobj);
trigger defendWatchTr (CALL_STRUCT_ATTACKED, me, ref structure, ref baseobj);
コピー
コピー済み
コピー
コピー済み
trigger defendReturnTr (every,
500
);
trigger defendReturnTr (every,
100000
);
trigger doResearchTr (CALL_RESEARCHCOMPLETED, ref research, ref structure, me);
trigger doResearchTr (CALL_RESEARCHCOMPLETED, ref research, ref structure, me);
trigger vtolDefendTr (CALL_STRUCT_ATTACKED, me, ref structure, ref baseobj);
trigger vtolDefendTr (CALL_STRUCT_ATTACKED, me, ref structure, ref baseobj);
コピー
コピー済み
コピー
コピー済み
trigger vtolStructsTr (every,
290
);
trigger vtolStructsTr (every,
600
);
trigger buildVtolsTr (every,
360
);
trigger buildVtolsTr (every,
180
);
trigger vtolAttackTr (every, 1
5
0);
trigger vtolAttackTr (every, 1
0);
trigger vtolEnablerTr (every, 700);
trigger vtolEnablerTr (every, 700);
trigger takeoverTr (CALL_UNITTAKEOVER, ref droid);
trigger takeoverTr (CALL_UNITTAKEOVER, ref droid);
trigger useLassatTr (every, 3000);
trigger useLassatTr (every, 3000);
trigger reassignTr (CALL_PLAYERLEFT,ref count);
trigger reassignTr (CALL_PLAYERLEFT,ref count);
trigger formAllianceEventTr (every,170);
trigger formAllianceEventTr (every,170);
trigger breakAllianceEventTr (every,3000);
trigger breakAllianceEventTr (every,3000);
trigger difficultyModifierTr (every,600);
trigger difficultyModifierTr (every,600);
trigger humanAllianceTr (CALL_ALLIANCEOFFER,ref count, ref count2);
trigger humanAllianceTr (CALL_ALLIANCEOFFER,ref count, ref count2);
trigger multiMsgTr (CALL_AI_MSG, me, ref sender, ref message);
trigger multiMsgTr (CALL_AI_MSG, me, ref sender, ref message);
trigger beaconTr (CALL_BEACON, me, ref sender, ref x, ref y, ref message);
trigger beaconTr (CALL_BEACON, me, ref sender, ref x, ref y, ref message);
trigger consoleTr (CALL_CONSOLE, ref sender, ref message);
trigger consoleTr (CALL_CONSOLE, ref sender, ref message);
trigger watchBaseThreatTr (every, 120);
trigger watchBaseThreatTr (every, 120);
trigger manageAllyHelpTr (every, 80);
trigger manageAllyHelpTr (every, 80);
trigger everySec (every, 10);
trigger everySec (every, 10);
trigger manageDefendLocationTr (every, 70);
trigger manageDefendLocationTr (every, 70);
trigger startLevelTr (CALL_START_NEXT_LEVEL);
trigger startLevelTr (CALL_START_NEXT_LEVEL);
trigger chainloadTr (wait, 1);
trigger chainloadTr (wait, 1);
trigger slowloadTr (wait, 13);
trigger slowloadTr (wait, 13);
コピー
コピー済み
コピー
コピー済み
trigger checkResearchTr (every,
400
);
trigger checkResearchTr (every,
50
);
/* Events */
/* Events */
event conDroids;
event conDroids;
event multiMsgEv;
event multiMsgEv;
event beaconEv;
event beaconEv;
event watchBaseThreat;
event watchBaseThreat;
event manageAllyHelp;
event manageAllyHelp;
event everySecEv;
event everySecEv;
event manageDefendLocationEv;
event manageDefendLocationEv;
event structureDestroyed;
event structureDestroyed;
event rebuildStructureEv;
event rebuildStructureEv;
event doResearch;
event doResearch;
event buildDerrick;
event buildDerrick;
/* Function prototypes */
/* Function prototypes */
function bool haveBeacon(int _player);
function bool haveBeacon(int _player);
function bool beaconTimeout(int _player);
function bool beaconTimeout(int _player);
function void processCommand(string _message, int _sender, bool _bBlipMessage);
function void processCommand(string _message, int _sender, bool _bBlipMessage);
function bool haveHelpers();
function bool haveHelpers();
function bool attemptToHelp(int _playerToHelp, int _x, int _y);
function bool attemptToHelp(int _playerToHelp, int _x, int _y);
function void helpPlayer(int _playerToHelp, int _helpX, int _helpY);
function void helpPlayer(int _playerToHelp, int _helpX, int _helpY);
function bool canStopHelpingAlly();
function bool canStopHelpingAlly();
function void stopHelpingAlly();
function void stopHelpingAlly();
function bool helpingAlly();
function bool helpingAlly();
function bool helpAllyTimeout();
function bool helpAllyTimeout();
function void requestHelp(int _helpX, int _helpY);
function void requestHelp(int _helpX, int _helpY);
function void doRequestHelp(int _helpX, int _helpY);
function void doRequestHelp(int _helpX, int _helpY);
function bool allyBaseAtLoc(int _ally, int _x, int _y);
function bool allyBaseAtLoc(int _ally, int _x, int _y);
function void messagePlayer(int _playerToMessage, string _message, int _probability);
function void messagePlayer(int _playerToMessage, string _message, int _probability);
function void messagePlayerAddressed(int _playerToMessage, int _playersToAddress, string _message);
function void messagePlayerAddressed(int _playerToMessage, int _playersToAddress, string _message);
function bool canSeeAllies();
function bool canSeeAllies();
function bool baseInTrouble();
function bool baseInTrouble();
function string m_affirmative();
function string m_affirmative();
function void defendLocation(int _defendX, int _defendY, int _tDefendTimeout, bool _bMove);
function void defendLocation(int _defendX, int _defendY, int _tDefendTimeout, bool _bMove);
function void stopDefendingLocation();
function void stopDefendingLocation();
function bool defendingLocation();
function bool defendingLocation();
function bool defendLocationTimeout();
function bool defendLocationTimeout();
function bool friendlyPlayer(int _playerToCheck);
function bool friendlyPlayer(int _playerToCheck);
function void factoryBuildDroid(STRUCTURE _factory);
function void factoryBuildDroid(STRUCTURE _factory);
function void cybFactorBuildCyborg(STRUCTURE _factory);
function void cybFactorBuildCyborg(STRUCTURE _factory);
function void vtolFactoryBuildVtol(STRUCTURE _factory);
function void vtolFactoryBuildVtol(STRUCTURE _factory);
function bool insideBase(int _x, int _y);
function bool insideBase(int _x, int _y);
function int numAlliesInBase(bool _bVtols);
function int numAlliesInBase(bool _bVtols);
function int numEnemiesInBase(bool _bVtols);
function int numEnemiesInBase(bool _bVtols);
function bool defendingOwnBase();
function bool defendingOwnBase();
function int targetTypeValue(BASEOBJ _target);
function int targetTypeValue(BASEOBJ _target);
function int numBitsSet(int _integer);
function int numBitsSet(int _integer);
function int findResearch(int _searchStart, int _techTree);
function int findResearch(int _searchStart, int _techTree);
function bool upgradeFactory(DROID _truck, int _maxBuilders);
function bool upgradeFactory(DROID _truck, int _maxBuilders);
function bool upgradeVtolFactory(DROID _truck, int _maxBuilders);
function bool upgradeVtolFactory(DROID _truck, int _maxBuilders);
function bool upgradeResearch(DROID _truck, int _maxBuilders);
function bool upgradeResearch(DROID _truck, int _maxBuilders);
function bool upgradePowGen(DROID _truck, int _maxBuilders);
function bool upgradePowGen(DROID _truck, int _maxBuilders);
function void buildRearmPads();
function void buildRearmPads();
function int numEnemyAAInRange(int _x, int _y, int _range);
function int numEnemyAAInRange(int _x, int _y, int _range);
function BASEOBJ chooseVtolTarget(bool bExclusiveTarget);
function BASEOBJ chooseVtolTarget(bool bExclusiveTarget);
function int getVtolTargetWeight(BASEOBJ _target);
function int getVtolTargetWeight(BASEOBJ _target);
function bool vtolTargetAssigned(BASEOBJ _target);
function bool vtolTargetAssigned(BASEOBJ _target);
function int numBuildSameBuilding(STRUCTURESTAT _checkStat, int _x, int _y);
function int numBuildSameBuilding(STRUCTURESTAT _checkStat, int _x, int _y);
function int totalVtols();
function int totalVtols();
function bool needTank();
function bool needTank();
function void setTechBranch(int _tech);
function void setTechBranch(int _tech);
function DROID closestIdleTruck(int _x, int _y);
function DROID closestIdleTruck(int _x, int _y);
function void buildOnExactLocation(DROID _truck, int _x, int _y, STRUCTURESTAT _stat);
function void buildOnExactLocation(DROID _truck, int _x, int _y, STRUCTURESTAT _stat);
function void rebuildStructures();
function void rebuildStructures();
function BASEOBJ chooseVtolDefenceTarget(int _x, int _y, int _range, bool bExclusiveTarget);
function BASEOBJ chooseVtolDefenceTarget(int _x, int _y, int _range, bool bExclusiveTarget);
function int numGroupSameOrder(GROUP _group, int _orderIndex);
function int numGroupSameOrder(GROUP _group, int _orderIndex);
function void rearrangeAttackVtols();
function void rearrangeAttackVtols();
function int numStructBusyByType(STRUCTURESTAT _busyStructType);
function int numStructBusyByType(STRUCTURESTAT _busyStructType);
function bool aiResponsibleForPlayer(int _player);
function bool aiResponsibleForPlayer(int _player);
function void reassignAI();
function void reassignAI();
function void shutDownAI();
function void shutDownAI();
function bool buildUnit(TEMPLATE _tankTemplate, STRUCTURE _factory, STRUCTURESTAT _factoryType, bool _bIdleOnly);
function bool buildUnit(TEMPLATE _tankTemplate, STRUCTURE _factory, STRUCTURESTAT _factoryType, bool _bIdleOnly);
function STRUCTURE findIdleStructure(STRUCTURESTAT _structType, bool _bIdleOnly);
function STRUCTURE findIdleStructure(STRUCTURESTAT _structType, bool _bIdleOnly);
#endregion triggers
#endregion triggers
/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
// HouseKeeping
// HouseKeeping
event initialisedEvent(CALL_GAMEINIT)
event initialisedEvent(CALL_GAMEINIT)
{
{
local int player;
local int player;
// initialise
// initialise
me = getPlayer("Nexus");
me = getPlayer("Nexus");
_DEBUG = FALSE;
_DEBUG = FALSE;
dbgMsgOn(me, _DEBUG);
dbgMsgOn(me, _DEBUG);
extraStruct = 0;
extraStruct = 0;
numRepairUnits = 0;
numRepairUnits = 0;
コピー
コピー済み
コピー
コピー済み
numSensorUnits = 0;
allOutAttack = NULLOBJECT;
allOutAttack = NULLOBJECT;
tLastHelpRequest = -1; //when we requested help for the last time
tLastHelpRequest = -1; //when we requested help for the last time
lastHelpPlayer = -1; //we are not currently helping anyone
lastHelpPlayer = -1; //we are not currently helping anyone
tHelp = -1; //when we started helping last time
tHelp = -1; //when we started helping last time
tHelpTimeout = -1; //time when help times out
tHelpTimeout = -1; //time when help times out
helpX = -1;
helpX = -1;
helpY = -1;
helpY = -1;
defendX = -1;
defendX = -1;
defendY = -1;
defendY = -1;
tDefendStart = -1;
tDefendStart = -1;
tDefendTimeout = -1;
tDefendTimeout = -1;
defendMoveType = -1; //move or scout
defendMoveType = -1; //move or scout
baseRange = 4 * TILE;
baseRange = 4 * TILE;
// set current research branch
// set current research branch
setTechBranch(-1);
setTechBranch(-1);
numVtolAttackGroups = 10;
numVtolAttackGroups = 10;
numAttackVtols = 10; //num vtols in an attack group
numAttackVtols = 10; //num vtols in an attack group
numDefendVtols = 5; //num vtols in an attack group
numDefendVtols = 5; //num vtols in an attack group
// setup build group - all initial droids are in buildgroup!
// setup build group - all initial droids are in buildgroup!
groupAddArea(buildGroup, me, 0, 0, (mapWidth*128), (mapHeight*128));
groupAddArea(buildGroup, me, 0, 0, (mapWidth*128), (mapHeight*128));
// note where our base is.
// note where our base is.
getPlayerStartPosition(me, ref baseX, ref baseY);
getPlayerStartPosition(me, ref baseX, ref baseY);
// defence.
// defence.
defendbusy = FALSE;
defendbusy = FALSE;
// setup scouts
// setup scouts
structure = getStructure(factory, me);
structure = getStructure(factory, me);
if(structure != NULLOBJECT)
if(structure != NULLOBJECT)
{
{
scoutTLX = structure.x;
scoutTLX = structure.x;
scoutTLY = structure.y;
scoutTLY = structure.y;
}
}
else
else
{
{
scoutTLX = baseX;
scoutTLX = baseX;
scoutTLY = baseY;
scoutTLY = baseY;
}
}
scoutW = 256;
scoutW = 256;
scoutH = 256;
scoutH = 256;
scoutX = scoutTLX;
scoutX = scoutTLX;
scoutY = scoutTLY;
scoutY = scoutTLY;
// clear the alliance array...
// clear the alliance array...
player = 0;
player = 0;
while (player != MAX_PLAYERS)
while (player != MAX_PLAYERS)
{
{
allianceTime[player] = 0;
allianceTime[player] = 0;
player = player + 1;
player = player + 1;
}
}
fundamentalBeingBuilt = derrick; // to avoid ever being null
fundamentalBeingBuilt = derrick; // to avoid ever being null
if(aiResponsibleForPlayer(me))
if(aiResponsibleForPlayer(me))
{
{
bRunning = true;
bRunning = true;
}
}
else
else
{
{
bRunning = false;
bRunning = false;
shutDownAI();
shutDownAI();
}
}
}
}
// check whether we have at least one structure of that type
// check whether we have at least one structure of that type
function bool haveStructure(STRUCTURESTAT type)
function bool haveStructure(STRUCTURESTAT type)
{
{
return getStructure(type, me) != NULLOBJECT;
return getStructure(type, me) != NULLOBJECT;
}
}
// check if we are getting any income
// check if we are getting any income
function bool havePowerSource()
function bool havePowerSource()
{
{
// we don't check buildings being finished here
// we don't check buildings being finished here
return haveStructure(powGen) and haveStructure(derrick);
return haveStructure(powGen) and haveStructure(derrick);
}
}
// I am not sure why we need this hack, but the AI can still end up not researching anything at times
// I am not sure why we need this hack, but the AI can still end up not researching anything at times
event checkResearch(checkResearchTr)
event checkResearch(checkResearchTr)
{
{
setEventTrigger(doResearch, chainloadTr);
setEventTrigger(doResearch, chainloadTr);
}
}
function void dbgPlr(string message)
function void dbgPlr(string message)
{
{
setEventTrigger(doResearch, chainloadTr);
setEventTrigger(doResearch, chainloadTr);
if (me == selectedPlayer)
if (me == selectedPlayer)
{
{
console(message);
console(message);
}
}
}
}
function void dbgObj(DROID obj, string message)
function void dbgObj(DROID obj, string message)
{
{
if (obj.selected)
if (obj.selected)
{
{
console(message);
console(message);
}
}
}
}
function bool conCanHelp(DROID mydroid, int bx, int by)
function bool conCanHelp(DROID mydroid, int bx, int by)
{
{
return (mydroid.order != DORDER_HELPBUILD and mydroid.order != DORDER_BUILD and mydroid.order != DORDER_LINEBUILD and droidCanReach(mydroid, bx, by));
return (mydroid.order != DORDER_HELPBUILD and mydroid.order != DORDER_BUILD and mydroid.order != DORDER_LINEBUILD and droidCanReach(mydroid, bx, by));
}
}
// Build something in main base, grab trucks to do it within tiles range
// Build something in main base, grab trucks to do it within tiles range
function bool grabTrucksAndBuild(int range, STRUCTURESTAT bstats, int maxBlockingTiles)
function bool grabTrucksAndBuild(int range, STRUCTURESTAT bstats, int maxBlockingTiles)
{
{
local DROID mydroid, closestDroid;
local DROID mydroid, closestDroid;
local int closestDist, currDist, numHelpDroids, tilerange, bx, by;
local int closestDist, currDist, numHelpDroids, tilerange, bx, by;
initIterateGroup(buildGroup); // find idle droids in build group.
initIterateGroup(buildGroup); // find idle droids in build group.
mydroid = iterateGroup(buildGroup);
mydroid = iterateGroup(buildGroup);
closestDist = 99999;
closestDist = 99999;
closestDroid = NULLOBJECT;
closestDroid = NULLOBJECT;
numHelpDroids = 0;
numHelpDroids = 0;
tilerange = range * TILE;
tilerange = range * TILE;
while (mydroid != NULLOBJECT)
while (mydroid != NULLOBJECT)
{
{
if (conCanHelp(mydroid, baseX, baseY))
if (conCanHelp(mydroid, baseX, baseY))
{
{
bx = baseX;
bx = baseX;
by = baseY;
by = baseY;
if (pickDroidStructLocation(mydroid, bstats, ref bx, ref by, me, maxBlockingTiles))
if (pickDroidStructLocation(mydroid, bstats, ref bx, ref by, me, maxBlockingTiles))
{
{
currDist = distBetweenTwoPoints(bx, by, mydroid.x, mydroid.y);
currDist = distBetweenTwoPoints(bx, by, mydroid.x, mydroid.y);
if (currDist < tilerange)
if (currDist < tilerange)
{
{
orderDroidStatsLoc(mydroid, DORDER_BUILD, bstats, bx, by); // close, so help build it
orderDroidStatsLoc(mydroid, DORDER_BUILD, bstats, bx, by); // close, so help build it
numHelpDroids = numHelpDroids + 1;
numHelpDroids = numHelpDroids + 1;
}
}
else if (currDist < closestDist)
else if (currDist < closestDist)
{
{
closestDroid = mydroid; // record this droid as being closest so far
closestDroid = mydroid; // record this droid as being closest so far
closestDist = currDist;
closestDist = currDist;
}
}
}
}
}
}
mydroid = iterateGroup(buildGroup);
mydroid = iterateGroup(buildGroup);
}
}
if (numHelpDroids == 0 and closestDroid != NULLOBJECT) // found none within help radius, so force someone to go long distance traveling
if (numHelpDroids == 0 and closestDroid != NULLOBJECT) // found none within help radius, so force someone to go long distance traveling
{
{
orderDroidStatsLoc(closestDroid, DORDER_BUILD, bstats, bx, by); // you, book a plane ticket and go!
orderDroidStatsLoc(closestDroid, DORDER_BUILD, bstats, bx, by); // you, book a plane ticket and go!
return true;
return true;
}
}
return (numHelpDroids > 0);
return (numHelpDroids > 0);
}
}
event arrived(reachedTr)
event arrived(reachedTr)
{
{
local bool found;
local bool found;
local STRUCTURESTAT myChoice;
local STRUCTURESTAT myChoice;
if (droid.droidType == DROID_CONSTRUCT or droid.droidType == DROID_CYBORG_CONSTRUCT)
if (droid.droidType == DROID_CONSTRUCT or droid.droidType == DROID_CYBORG_CONSTRUCT)
{
{
dbgObj(droid, "Failed to build where we should - attempt to screw up enemy oil derrick");
dbgObj(droid, "Failed to build where we should - attempt to screw up enemy oil derrick");
// Check if at oil well, and it was taken by enemy
// Check if at oil well, and it was taken by enemy
structure = structureBuiltInRange(derrick, droid.x, droid.y, (5 * 128), -1);
structure = structureBuiltInRange(derrick, droid.x, droid.y, (5 * 128), -1);
if (structure != NULLOBJECT)
if (structure != NULLOBJECT)
{
{
if (not friendlyPlayer(structure.player) and droid.health == 100)
if (not friendlyPlayer(structure.player) and droid.health == 100)
{
{
// Ok, at enemy derrick, and nobody has hurt us yet. Start being nasty.
// Ok, at enemy derrick, and nobody has hurt us yet. Start being nasty.
count = 0;
count = 0;
found = false;
found = false;
// find simplest/cheapest one available to build
// find simplest/cheapest one available to build
while (count < numDefStructs and not found)
while (count < numDefStructs and not found)
{
{
if (isStructureAvailable(defStructs[count], me))
if (isStructureAvailable(defStructs[count], me))
{
{
found = true;
found = true;
}
}
else
else
{
{
count++;
count++;
}
}
}
}
if (found)
if (found)
{
{
buildX = droid.x;
buildX = droid.x;
buildY = droid.y;
buildY = droid.y;
if (pickDroidStructLocation(droid, defStructs[count], ref buildX, ref buildY, me, -1))
if (pickDroidStructLocation(droid, defStructs[count], ref buildX, ref buildY, me, -1))
{
{
orderDroidStatsLoc(droid, DORDER_BUILD, defStructs[count], buildX, buildY);
orderDroidStatsLoc(droid, DORDER_BUILD, defStructs[count], buildX, buildY);
}
}
else
else
{
{
dbgObj(droid, "Wanted to be nasty, but found nowhere to build defense");
dbgObj(droid, "Wanted to be nasty, but found nowhere to build defense");
orderDroid(droid, DORDER_RTB); // nothing more to do here.
orderDroid(droid, DORDER_RTB); // nothing more to do here.
}
}
}
}
else
else
{
{
dbgObj(droid, "Wanted to be nasty, but had nothing nasty to build - returning to base");
dbgObj(droid, "Wanted to be nasty, but had nothing nasty to build - returning to base");
orderDroid(droid, DORDER_RTB); // oh, well. nothing more to do here.
orderDroid(droid, DORDER_RTB); // oh, well. nothing more to do here.
}
}
exit;
exit;
}
}
else if (droid.health < 100 and !insideBase(droid.x, droid.y))
else if (droid.health < 100 and !insideBase(droid.x, droid.y))
{
{
orderDroid(droid, DORDER_RTR); // bolt back to base now!
orderDroid(droid, DORDER_RTR); // bolt back to base now!
exit;
exit;
}
}
}
}
}
}
}
}
event buildFundamentals(inactive)
event buildFundamentals(inactive)
{
{
count = 0;
count = 0;
while (count < numFundamental)
while (count < numFundamental)
{
{
// check that struct.
// check that struct.
structure = getStructure(structs[count], me);
structure = getStructure(structs[count], me);
if (structure == NULLOBJECT) // if missing build it.
if (structure == NULLOBJECT) // if missing build it.
{
{
if (isStructureAvailable(structs[count], me))
if (isStructureAvailable(structs[count], me))
{
{
if (grabTrucksAndBuild(12, structs[count], 0))
if (grabTrucksAndBuild(12, structs[count], 0))
{
{
exit; // no need to check more
exit; // no need to check more
}
}
}
}
}
}
count = count + 1;
count = count + 1;
}
}
fundamentalBeingBuilt = derrick;
fundamentalBeingBuilt = derrick;
setEventTrigger(buildFundamentals, inactive);
setEventTrigger(buildFundamentals, inactive);
}
}
event startLevel(startLevelTr)
event startLevel(startLevelTr)
{
{
setEventTrigger(buildFundamentals, slowloadTr);
setEventTrigger(buildFundamentals, slowloadTr);
setEventTrigger(conDroids, chainloadTr);
setEventTrigger(conDroids, chainloadTr);
setEventTrigger(doResearch, chainloadTr);
setEventTrigger(doResearch, chainloadTr);
setEventTrigger(buildDerrick, slowloadTr);
setEventTrigger(buildDerrick, slowloadTr);
setEventTrigger(startLevel, inactive);
setEventTrigger(startLevel, inactive);
}
}
// decide what technology branch we will use
// decide what technology branch we will use
function void setTechBranch(int _tech)
function void setTechBranch(int _tech)
{
{
local float _y2,_y1,_x2,_x1,_a,_y,_m,_rnd,_mapSize;
local float _y2,_y1,_x2,_x1,_a,_y,_m,_rnd,_mapSize;
_mapSize = (float)((mapWidth + mapHeight) / 2);
_mapSize = (float)((mapWidth + mapHeight) / 2);
if(_tech != -1)
if(_tech != -1)
{
{
curTech = _tech;
curTech = _tech;
}
}
else
else
{
{
//probability to choose vtol branch for map size 90 = 0; probability for map size 200 = 45
//probability to choose vtol branch for map size 90 = 0; probability for map size 200 = 45
//build a linear function: y = ((y2 - y1) / (x2 - x1)) * x + a depending on two values given (short: y = mx+a)
//build a linear function: y = ((y2 - y1) / (x2 - x1)) * x + a depending on two values given (short: y = mx+a)
_x1 = 90.0; _y1 = 0.0;
_x1 = 90.0; _y1 = 0.0;
_x2 = 200.0; _y2 = 45.0;
_x2 = 200.0; _y2 = 45.0;
_m = ((_y2 - _y1) / (_x2 - _x1));
_m = ((_y2 - _y1) / (_x2 - _x1));
_a = -(_m * _x1);
_a = -(_m * _x1);
//calculate probability for the current map
//calculate probability for the current map
_y = _m * _mapSize + _a;
_y = _m * _mapSize + _a;
dbg("_m = " & _m & ", a = " & _a, me);
dbg("_m = " & _m & ", a = " & _a, me);
_rnd = (float)random(100);
_rnd = (float)random(100);
if(_rnd < _y)
if(_rnd < _y)
{
{
curTech = branchVTOL;
curTech = branchVTOL;
dbg("going air (" & _y & "/" & _rnd & ")", me);
dbg("going air (" & _y & "/" & _rnd & ")", me);
}
}
else
else
{
{
curTech = branchDefault;
curTech = branchDefault;
dbg("going land (" & _y & "/" & _rnd & ")", me);
dbg("going land (" & _y & "/" & _rnd & ")", me);
}
}
}
}
}
}
/* returns TRUE if AI is responsible for the _player */
/* returns TRUE if AI is responsible for the _player */
function bool aiResponsibleForPlayer(int _player)
function bool aiResponsibleForPlayer(int _player)
{
{
if(not _DEBUG and ((_player == selectedPlayer) or not myResponsibility(_player)))
if(not _DEBUG and ((_player == selectedPlayer) or not myResponsibility(_player)))
{
{
return FALSE;
return FALSE;
}
}
return TRUE;
return TRUE;
}
}
/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
// keep details about the size and postion of the ai players base
// keep details about the size and postion of the ai players base
event basedetails(basedetailsTr)
event basedetails(basedetailsTr)
{
{
// clear old extremities.
// clear old extremities.
maxy = 0;
maxy = 0;
maxx = 0;
maxx = 0;
miny = (mapHeight*128);
miny = (mapHeight*128);
minx = (mapWidth*128);
minx = (mapWidth*128);
baseRange = 4 * TILE;
baseRange = 4 * TILE;
// now find the extremities of our vital structures.
// now find the extremities of our vital structures.
count = 0;
count = 0;
while(count < numBaseStruct)
while(count < numBaseStruct)
{
{
initEnumStruct(FALSE,baseStruct[count],me,me);
initEnumStruct(FALSE,baseStruct[count],me,me);
structure= enumStruct();
structure= enumStruct();
while(structure != NULLOBJECT)
while(structure != NULLOBJECT)
{
{
if(structure.x < minx)
if(structure.x < minx)
{
{
minx = structure.x;
minx = structure.x;
}
}
if(structure.x > maxx)
if(structure.x > maxx)
{
{
maxx = structure.x;
maxx = structure.x;
}
}
if(structure.y < miny)
if(structure.y < miny)
{
{
miny = structure.y;
miny = structure.y;
}
}
if(structure.y > maxy)
if(structure.y > maxy)
{
{
maxy = structure.y;
maxy = structure.y;
}
}
result = distBetweenTwoPoints(baseX, baseY, structure.x, structure.y);
result = distBetweenTwoPoints(baseX, baseY, structure.x, structure.y);
if(result > baseRange){
if(result > baseRange){
baseRange = result;
baseRange = result;
}
}
structure= enumStruct();
structure= enumStruct();
}
}
count = count + 1;
count = count + 1;
}
}
result = 3 * 128;
result = 3 * 128;
minx = minx - result;
minx = minx - result;
maxx = maxx + result;
maxx = maxx + result;
miny = miny - result;
miny = miny - result;
maxy = maxy + result;
maxy = maxy + result;
baseRange = baseRange + (4 * 128);
baseRange = baseRange + (4 * 128);
}
}
/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
// structure building rules
// structure building rules
// build derricks on oil.
// build derricks on oil.
event buildDerrick(buildDerrickTr)
event buildDerrick(buildDerrickTr)
{
{
local bool foundOne, _same;
local bool foundOne, _same;
local FEATURE _oil, _closestOil;
local FEATURE _oil, _closestOil;
local int _bestDist, _newDist;
local int _bestDist, _newDist;
local DROID _search;
local DROID _search;
// what if we can't waste power on building derricks because we don't have a gen yet?
// what if we can't waste power on building derricks because we don't have a gen yet?
if (playerPower(me) < 300 and haveStructure(derrick) and not haveStructure(powGen))
if (playerPower(me) < 300 and haveStructure(derrick) and not haveStructure(powGen))
{
{
setEventTrigger(buildDerrick, slowloadTr);
setEventTrigger(buildDerrick, slowloadTr);
exit;
exit;
}
}
_bestDist = 99999;
_bestDist = 99999;
_closestOil = NULLOBJECT;
_closestOil = NULLOBJECT;
foundOne = false;
foundOne = false;
initIterateGroup(buildGroup); // find all units in build group
initIterateGroup(buildGroup); // find all units in build group
droid = iterateGroup(buildGroup);
droid = iterateGroup(buildGroup);
while (droid != NULLOBJECT && !foundOne)
while (droid != NULLOBJECT && !foundOne)
{
{
if (droid.order != DORDER_BUILD and droid.order != DORDER_LINEBUILD and droid.order != DORDER_HELPBUILD)
if (droid.order != DORDER_BUILD and droid.order != DORDER_LINEBUILD and droid.order != DORDER_HELPBUILD)
{
{
foundOne = true;
foundOne = true;
}
}
else
else
{
{
droid = iterateGroup(buildGroup);
droid = iterateGroup(buildGroup);
}
}
}
}
if (droid != NULLOBJECT)
if (droid != NULLOBJECT)
{
{
initGetFeature(oilRes, -1, me);
initGetFeature(oilRes, -1, me);
_oil = getFeatureB(me);
_oil = getFeatureB(me);
while (_oil != NULLOBJECT)
while (_oil != NULLOBJECT)
{
{
_newDist = distBetweenTwoPoints(droid.x, droid.y, _oil.x, _oil.y);
_newDist = distBetweenTwoPoints(droid.x, droid.y, _oil.x, _oil.y);
_same = false;
_same = false;
if (_newDist < _bestDist and droidCanReach(droid, _oil.x, _oil.y)) // this one is closer
if (_newDist < _bestDist and droidCanReach(droid, _oil.x, _oil.y)) // this one is closer
{
{
if (!threatInRange(me, _oil.x, _oil.y, OIL_THREAT_RANGE, FALSE))
if (!threatInRange(me, _oil.x, _oil.y, OIL_THREAT_RANGE, FALSE))
{
{
initIterateGroup(buildGroup); // find all units in build group.
initIterateGroup(buildGroup); // find all units in build group.
_search = iterateGroup(buildGroup);
_search = iterateGroup(buildGroup);
foundOne = false;
foundOne = false;
while (_search != NULLOBJECT && !foundOne)
while (_search != NULLOBJECT && !foundOne)
{
{
if (_search.orderx == _oil.x and _search.ordery == _oil.y and _search != droid)
if (_search.orderx == _oil.x and _search.ordery == _oil.y and _search != droid)
{
{
_same = true;
_same = true;
foundOne = true;
foundOne = true;
}
}
_search = iterateGroup(buildGroup);
_search = iterateGroup(buildGroup);
}
}
if (!_same) // do not go to same spot as another droid
if (!_same) // do not go to same spot as another droid
{
{
_bestDist = _newDist;
_bestDist = _newDist;
_closestOil = _oil;
_closestOil = _oil;
}
}
}
}
}
}
_oil = getFeatureB(me);
_oil = getFeatureB(me);
}
}
if (_closestOil != NULLOBJECT)
if (_closestOil != NULLOBJECT)
{
{
orderDroidStatsLoc(droid, DORDER_BUILD, derrick, _closestOil.x, _closestOil.y); // build a derick
orderDroidStatsLoc(droid, DORDER_BUILD, derrick, _closestOil.x, _closestOil.y); // build a derick
if (idleGroup(buildGroup) > 0)
if (idleGroup(buildGroup) > 0)
{
{
setEventTrigger(buildDerrick, slowloadTr); // do it again for next droid
setEventTrigger(buildDerrick, slowloadTr); // do it again for next droid
exit;
exit;
}
}
}
}
}
}
setEventTrigger(buildDerrick, buildDerrickTr);
setEventTrigger(buildDerrick, buildDerrickTr);
}
}
/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
// if idle and derrick in range and no defense then build defense, else ret to base .
// if idle and derrick in range and no defense then build defense, else ret to base .
event buildOilDefenseOrRetreat(buildOilDefenseOrRetreatTr)
event buildOilDefenseOrRetreat(buildOilDefenseOrRetreatTr)
{
{
local int _numBuilders,_maxBuilders;
local int _numBuilders,_maxBuilders;
_maxBuilders = 1;
_maxBuilders = 1;
// check idle.
// check idle.
initIterateGroup(buildGroup); // find idle droids in build group.
initIterateGroup(buildGroup); // find idle droids in build group.
droid = iterateGroup(buildGroup);
droid = iterateGroup(buildGroup);
while(droid != NULLOBJECT)
while(droid != NULLOBJECT)
{
{
if (droid.order != DORDER_BUILD and droid.order != DORDER_LINEBUILD and droid.order != DORDER_HELPBUILD)
if (droid.order != DORDER_BUILD and droid.order != DORDER_LINEBUILD and droid.order != DORDER_HELPBUILD)
{
{
// if in range of a derrick
// if in range of a derrick
structure = structureBuiltInRange(derrick, droid.x, droid.y, (5*128), me);
structure = structureBuiltInRange(derrick, droid.x, droid.y, (5*128), me);
// if inside base limits then presume ok..
// if inside base limits then presume ok..
if( structure != NULLOBJECT)
if( structure != NULLOBJECT)
{
{
if((structure.x > minx) and (structure.y > miny) and (structure.x < maxx) and (structure.y <maxy))
if((structure.x > minx) and (structure.y > miny) and (structure.x < maxx) and (structure.y <maxy))
{
{
structure = NULLOBJECT;
structure = NULLOBJECT;
}
}
}
}
if(structure != NULLOBJECT)
if(structure != NULLOBJECT)
{
{
buildX = structure.x;
buildX = structure.x;
buildY = structure.y;
buildY = structure.y;
// not many defenses nearby
// not many defenses nearby
if(numFriendlyWeapStructsInRange(me, buildX, buildY, (3*128), FALSE) < 2)
if(numFriendlyWeapStructsInRange(me, buildX, buildY, (3*128), FALSE) < 2)
{
{
count = numDefStructs - 1; //pick a struct to build..
count = numDefStructs - 1; //pick a struct to build..
count2 = 0;
count2 = 0;
while( (count2 < 5) and (count >= 0) )
while( (count2 < 5) and (count >= 0) )
{
{
if( isStructureAvailable(defStructs[count],me))
if( isStructureAvailable(defStructs[count],me))
{
{
structChoice[count2] = defStructs[count];
structChoice[count2] = defStructs[count];
count2 = count2 + 1;
count2 = count2 + 1;
}
}
count = count - 1;
count = count - 1;
}
}
count =0;
count =0;
if(count2 > 0)
if(count2 > 0)
{
{
count = random(count2); //count = choice!
count = random(count2); //count = choice!
// pick a location
// pick a location
boolResult = pickDroidStructLocation(droid, structChoice[count], ref buildX, ref buildY, me, -1);
boolResult = pickDroidStructLocation(droid, structChoice[count], ref buildX, ref buildY, me, -1);
_numBuilders = numBuildSameBuilding(NULLSTRUCTURESTAT, buildX, buildY);
_numBuilders = numBuildSameBuilding(NULLSTRUCTURESTAT, buildX, buildY);
if((boolResult == TRUE) and (_numBuilders < _maxBuilders) and droidCanReach(droid, buildX, buildY))
if((boolResult == TRUE) and (_numBuilders < _maxBuilders) and droidCanReach(droid, buildX, buildY))
{
{
// build it.
// build it.
orderDroidStatsLoc(droid, DORDER_BUILD,structChoice[count], buildX,buildY);
orderDroidStatsLoc(droid, DORDER_BUILD,structChoice[count], buildX,buildY);
_numBuilders++;
_numBuilders++;
}
}
}
}
}
}
else
else
{
{
structure = structureBuiltInRange(playerHQ, droid.x, droid.y, (5*128), me);
structure = structureBuiltInRange(playerHQ, droid.x, droid.y, (5*128), me);
if(structure == NULLOBJECT)
if(structure == NULLOBJECT)
{
{
if(!insideBase(droid.x, droid.y))
if(!insideBase(droid.x, droid.y))
{
{
orderDroid(droid,DORDER_RTB); // return to base;
orderDroid(droid,DORDER_RTB); // return to base;
}
}
}
}
}
}
}
}
else
else
{
{
コピー
コピー済み
コピー
コピー済み
structure = structureBuiltInRange(playerHQ,
droid.x, droid.y, (5*128), me);
structure = structureBuiltInRange(playerHQ,
dr
if(structure == NULLOBJECT)
{
if(!insideBase(droid.x, droid.y))
{
orderD
保存された差分
原文
ファイルを開く
///////////////////////////////////////////////////////////////////// // general ai for skirmish game ///////////////////////////////////////////////////////////////////// // Warzone2100, Pumpkin Studios, // alex lee.98/99. // ///////////////////////////////////////////////////////////////////// //Tile in world units #define TILE 128 #define NONE (-1) // These are final rules of the lexical parser #define R_REQUEST_HELP "help me" #define R_REQUEST_BEACON "drop a beacon" #define R_REPORT_SAFETY "i'm ok" #define R_REQUEST_ALLY "ally me" // These are our own messages - lexical parser should be able to handle them #define M_REQUEST_HELP "help me!!" #define M_REQUEST_BEACON "drop a beacon" #define M_AFFIRMATIVE_OK "ok" #define M_AFFIRMATIVE_ROGER "roger" #define M_ANNOYED "bug off" #define M_HELPERS_KILLED "that was all I had.." #define M_HELP_NO_UNITS "I don't have anything" #define MAX_PROBABILITY 100 // Base threat range in world units #define W_BASE_THREAT_RANGE ((17 + (mapWidth + mapHeight) / 2 / 35) * TILE) #define ALL_ALLIES -1 #define BASE_DEFEND_DURATION (3 * 60) // Delay before we repeat our request, in seconds #define HELP_REQUEST_INTERVAL (3 * 60) //in secs #define BEACON_TIMEOUT 30 #define MAX_DROIDS 150 //range for trucks to look for more oil #define MORE_OIL_RANGE (10 * TILE) //don't try to build on oil if there's threat within this range #define OIL_THREAT_RANGE (9 * TILE) #define MAX_TRUCKS 12 #define MIN_TRUCKS 5 //Enter power saving mode when lower than this #define LOW_POWER 250 //Target type values #define NO_TARGET_VALUE 0 #define DROID_TARGET_VALUE 1 #define OTHER_TARGET_VALUE 2 #define DEFENSE_TARGET_VALUE 3 #define RESEARCH_TARGET_VALUE 4 #define HQ_TARGET_VALUE 5 #define OIL_TARGET_VALUE 6 #define FACTORY_TARGET_VALUE 7 #define UNLIMITED (-1) #define AA_THREAT_RANGE (TILE * 12) #define MAX_DEFENDERS_RADIUS (TILE * 40) #define MAX_VTOL_DEFEND_RADIUS (TILE * 25) // AI will remember max this number of structures #define MAX_REBUILD_STRUCT 100 //Total number of technology branches #define TECHS 2 //How many best templates to choose from when deciding what template to build #define MAX_RANDOM_TEMPLATES 4 private int me; // player for this instance. public int tileExpand; // rate of exploration public int numScouts[TECHS],maxScouts[TECHS]; // aim for... public int numDefenders[TECHS],maxDefenders[TECHS]; public int numAttackers[TECHS],maxAttackers[TECHS]; public int numCyborgs[TECHS],maxCyborgs[TECHS]; public int branchDefault,branchVTOL,techCount[TECHS],maxVtolFacs[TECHS],maxIdleRes[TECHS], maxVTOLs[TECHS],numVtolTargets,vtolTargetWeight[10],numRebuildStat[TECHS]; public RESEARCHSTAT tech[TECHS][30]; //technology for different research branches public STRUCTURESTAT vtolTarget[10],rebuildStat[TECHS][2]; // structures private int baseX,baseY,minx,miny,maxx,maxy; public int numStructs,numIncendrys,numDefStructs,numExtraStructs[TECHS],numWallWeaps,numBaseStruct,numLightCyborgs,numFundamental; private STRUCTURESTAT structChoice[5]; public STRUCTURESTAT incendrys[8],structs[13],defStructs[26],extraStructs[TECHS][6],wallWeaps[11]; public STRUCTURESTAT sensorTower,wall,cornerWall,resLab,powGen,playerHQ,lassat,factory,derrick,cybFactory, vtolDefStruct[5],vtolPad,vtolFactory,uplink,baseStruct[8]; public STRUCTURESTAT powModule,facModule,resModule,vtolModule; public int extraStruct; // unit templates public int numTemplates[TECHS]; public TEMPLATE tmpl[TECHS][70]; private TEMPLATE tmplChoice[5]; public TEMPLATE cybTempl[10],superCyb[4],cybMechanic,cybEngineer,hovertruck; public TEMPLATE vtols[18]; public int numVtolTemplates; public TEMPLATE sense[11]; public int numSenseTemplates; public TEMPLATE constructor,repair; public int numRepairUnits; //defend private GROUP defendGroup; private bool defendbusy; private BASEOBJ defendObj; public RESEARCHSTAT nexusDefence; private RESEARCHSTAT research; //build private GROUP buildGroup; private int buildX,buildY,buildX2,buildY2; public FEATURESTAT oilRes; // scout private GROUP scoutGroup; private int scoutX,scoutY; private int scoutTLX,scoutTLY,scoutW,scoutH; // attack private GROUP attackGroup; private BASEOBJ attackObj,allOutAttack,vtolGrAttackObj[10]; // vtols private GROUP vtolDefendGr,vtolAttackGr[10]; // generic private STRUCTURE structure,structure2,rebuildObj[100]; private DROID droid; private FEATURE feature; private BASEOBJ baseobj,baseobj2; private int count,count2,result,result2,tempx,tempy; private bool boolResult,boolResult2; private bool powerSave,_DEBUG,bRunning; // Hopefully this will be at least as large as MAX_PLAYERS... Why can't I just use MAX_PLAYERS as the array size?! // P.S. And why can't I put a comment on the same line as a #define??!! Gah, who cares if the lua2 branch works, lets switch to it, anyway. #define MAX_PLAYERS_HACK 17 private int allianceTime[MAX_PLAYERS_HACK]; private int sender,x,y,beaconX[8],beaconY[8],tBeacon[8], tLastHelpRequest,lastHelpPlayer,tHelp,tHelpTimeout,helpX,helpY; private string message; private int defendX,defendY,__defendRadiusUnused,tDefendStart,tDefendTimeout, defendMoveType,baseRange,curTech,numVtolAttackGroups,numAttackVtols, numDefendVtols,rebuildStructX[MAX_REBUILD_STRUCT],rebuildStructY[MAX_REBUILD_STRUCT],countRebuildStruct; private STRUCTURESTAT rebuildStructStat[MAX_REBUILD_STRUCT]; private STRUCTURESTAT fundamentalBeingBuilt; private int order; // callback global ///////////////////////////////////////////////////////////////////// // triggers. #region triggers trigger reachedTr (CALL_DROID_REACH_LOCATION, me, ref droid, ref order); trigger buildExpandTr (every, 600); trigger fortifyTr (every, 1000); trigger upgradeStructuresTr (every, 360); trigger conDroidsTr (every, 900); // was 1400 trigger repairDroidsTr (every, 2600); trigger basedetailsTr (every, 600 ); trigger buildDerrickTr (every, 80 ); trigger buildOilDefenseOrRetreatTr (every, 120 ); trigger incendryTr (every, 250 ); trigger buildPowerGeneratorsTr (every, 80 ); trigger buildBaseTr (every, 150 ); trigger finishStructsTr (every, 210); trigger droidBuiltTr (CALL_NEWDROID,me, ref droid,ref structure); trigger structBuiltTr (CALL_STRUCTBUILT, me, ref droid, ref structure); trigger droidDestroyedTr (CALL_DROID_DESTROYED, me, ref droid); trigger structureDestroyedTr (CALL_STRUCT_DESTROYED, me, ref structure); trigger rebuildStructureTr (every, 50); trigger consolidateEventTr (every, 3100); trigger factoryEventTr (every, 170 ); trigger cyborgFactoryEventTr (every, 170 ); trigger chooseScoutAreaTr (every, 200 ); trigger expandScoutAreaTr (every, 600 ); trigger scoutMainTr (every, 150 ); trigger newObjectReportTr (CALL_OBJ_SEEN, me, ref baseobj, ref baseobj2); trigger attackStuffTr (every, 300 ); trigger allOutAttackTr (every, 4000); trigger defendWatchTr (CALL_STRUCT_ATTACKED, me, ref structure, ref baseobj); trigger defendReturnTr (every, 500 ); trigger doResearchTr (CALL_RESEARCHCOMPLETED, ref research, ref structure, me); trigger vtolDefendTr (CALL_STRUCT_ATTACKED, me, ref structure, ref baseobj); trigger vtolStructsTr (every, 290); trigger buildVtolsTr (every, 360); trigger vtolAttackTr (every, 150); trigger vtolEnablerTr (every, 700); trigger takeoverTr (CALL_UNITTAKEOVER, ref droid); trigger useLassatTr (every, 3000); trigger reassignTr (CALL_PLAYERLEFT,ref count); trigger formAllianceEventTr (every,170); trigger breakAllianceEventTr (every,3000); trigger difficultyModifierTr (every,600); trigger humanAllianceTr (CALL_ALLIANCEOFFER,ref count, ref count2); trigger multiMsgTr (CALL_AI_MSG, me, ref sender, ref message); trigger beaconTr (CALL_BEACON, me, ref sender, ref x, ref y, ref message); trigger consoleTr (CALL_CONSOLE, ref sender, ref message); trigger watchBaseThreatTr (every, 120); trigger manageAllyHelpTr (every, 80); trigger everySec (every, 10); trigger manageDefendLocationTr (every, 70); trigger startLevelTr (CALL_START_NEXT_LEVEL); trigger chainloadTr (wait, 1); trigger slowloadTr (wait, 13); trigger checkResearchTr (every, 400); /* Events */ event conDroids; event multiMsgEv; event beaconEv; event watchBaseThreat; event manageAllyHelp; event everySecEv; event manageDefendLocationEv; event structureDestroyed; event rebuildStructureEv; event doResearch; event buildDerrick; /* Function prototypes */ function bool haveBeacon(int _player); function bool beaconTimeout(int _player); function void processCommand(string _message, int _sender, bool _bBlipMessage); function bool haveHelpers(); function bool attemptToHelp(int _playerToHelp, int _x, int _y); function void helpPlayer(int _playerToHelp, int _helpX, int _helpY); function bool canStopHelpingAlly(); function void stopHelpingAlly(); function bool helpingAlly(); function bool helpAllyTimeout(); function void requestHelp(int _helpX, int _helpY); function void doRequestHelp(int _helpX, int _helpY); function bool allyBaseAtLoc(int _ally, int _x, int _y); function void messagePlayer(int _playerToMessage, string _message, int _probability); function void messagePlayerAddressed(int _playerToMessage, int _playersToAddress, string _message); function bool canSeeAllies(); function bool baseInTrouble(); function string m_affirmative(); function void defendLocation(int _defendX, int _defendY, int _tDefendTimeout, bool _bMove); function void stopDefendingLocation(); function bool defendingLocation(); function bool defendLocationTimeout(); function bool friendlyPlayer(int _playerToCheck); function void factoryBuildDroid(STRUCTURE _factory); function void cybFactorBuildCyborg(STRUCTURE _factory); function void vtolFactoryBuildVtol(STRUCTURE _factory); function bool insideBase(int _x, int _y); function int numAlliesInBase(bool _bVtols); function int numEnemiesInBase(bool _bVtols); function bool defendingOwnBase(); function int targetTypeValue(BASEOBJ _target); function int numBitsSet(int _integer); function int findResearch(int _searchStart, int _techTree); function bool upgradeFactory(DROID _truck, int _maxBuilders); function bool upgradeVtolFactory(DROID _truck, int _maxBuilders); function bool upgradeResearch(DROID _truck, int _maxBuilders); function bool upgradePowGen(DROID _truck, int _maxBuilders); function void buildRearmPads(); function int numEnemyAAInRange(int _x, int _y, int _range); function BASEOBJ chooseVtolTarget(bool bExclusiveTarget); function int getVtolTargetWeight(BASEOBJ _target); function bool vtolTargetAssigned(BASEOBJ _target); function int numBuildSameBuilding(STRUCTURESTAT _checkStat, int _x, int _y); function int totalVtols(); function bool needTank(); function void setTechBranch(int _tech); function DROID closestIdleTruck(int _x, int _y); function void buildOnExactLocation(DROID _truck, int _x, int _y, STRUCTURESTAT _stat); function void rebuildStructures(); function BASEOBJ chooseVtolDefenceTarget(int _x, int _y, int _range, bool bExclusiveTarget); function int numGroupSameOrder(GROUP _group, int _orderIndex); function void rearrangeAttackVtols(); function int numStructBusyByType(STRUCTURESTAT _busyStructType); function bool aiResponsibleForPlayer(int _player); function void reassignAI(); function void shutDownAI(); function bool buildUnit(TEMPLATE _tankTemplate, STRUCTURE _factory, STRUCTURESTAT _factoryType, bool _bIdleOnly); function STRUCTURE findIdleStructure(STRUCTURESTAT _structType, bool _bIdleOnly); #endregion triggers ///////////////////////////////////////////////////////////////////// // HouseKeeping event initialisedEvent(CALL_GAMEINIT) { local int player; // initialise me = getPlayer("Nexus"); _DEBUG = FALSE; dbgMsgOn(me, _DEBUG); extraStruct = 0; numRepairUnits = 0; allOutAttack = NULLOBJECT; tLastHelpRequest = -1; //when we requested help for the last time lastHelpPlayer = -1; //we are not currently helping anyone tHelp = -1; //when we started helping last time tHelpTimeout = -1; //time when help times out helpX = -1; helpY = -1; defendX = -1; defendY = -1; tDefendStart = -1; tDefendTimeout = -1; defendMoveType = -1; //move or scout baseRange = 4 * TILE; // set current research branch setTechBranch(-1); numVtolAttackGroups = 10; numAttackVtols = 10; //num vtols in an attack group numDefendVtols = 5; //num vtols in an attack group // setup build group - all initial droids are in buildgroup! groupAddArea(buildGroup, me, 0, 0, (mapWidth*128), (mapHeight*128)); // note where our base is. getPlayerStartPosition(me, ref baseX, ref baseY); // defence. defendbusy = FALSE; // setup scouts structure = getStructure(factory, me); if(structure != NULLOBJECT) { scoutTLX = structure.x; scoutTLY = structure.y; } else { scoutTLX = baseX; scoutTLY = baseY; } scoutW = 256; scoutH = 256; scoutX = scoutTLX; scoutY = scoutTLY; // clear the alliance array... player = 0; while (player != MAX_PLAYERS) { allianceTime[player] = 0; player = player + 1; } fundamentalBeingBuilt = derrick; // to avoid ever being null if(aiResponsibleForPlayer(me)) { bRunning = true; } else { bRunning = false; shutDownAI(); } } // check whether we have at least one structure of that type function bool haveStructure(STRUCTURESTAT type) { return getStructure(type, me) != NULLOBJECT; } // check if we are getting any income function bool havePowerSource() { // we don't check buildings being finished here return haveStructure(powGen) and haveStructure(derrick); } // I am not sure why we need this hack, but the AI can still end up not researching anything at times event checkResearch(checkResearchTr) { setEventTrigger(doResearch, chainloadTr); } function void dbgPlr(string message) { setEventTrigger(doResearch, chainloadTr); if (me == selectedPlayer) { console(message); } } function void dbgObj(DROID obj, string message) { if (obj.selected) { console(message); } } function bool conCanHelp(DROID mydroid, int bx, int by) { return (mydroid.order != DORDER_HELPBUILD and mydroid.order != DORDER_BUILD and mydroid.order != DORDER_LINEBUILD and droidCanReach(mydroid, bx, by)); } // Build something in main base, grab trucks to do it within tiles range function bool grabTrucksAndBuild(int range, STRUCTURESTAT bstats, int maxBlockingTiles) { local DROID mydroid, closestDroid; local int closestDist, currDist, numHelpDroids, tilerange, bx, by; initIterateGroup(buildGroup); // find idle droids in build group. mydroid = iterateGroup(buildGroup); closestDist = 99999; closestDroid = NULLOBJECT; numHelpDroids = 0; tilerange = range * TILE; while (mydroid != NULLOBJECT) { if (conCanHelp(mydroid, baseX, baseY)) { bx = baseX; by = baseY; if (pickDroidStructLocation(mydroid, bstats, ref bx, ref by, me, maxBlockingTiles)) { currDist = distBetweenTwoPoints(bx, by, mydroid.x, mydroid.y); if (currDist < tilerange) { orderDroidStatsLoc(mydroid, DORDER_BUILD, bstats, bx, by); // close, so help build it numHelpDroids = numHelpDroids + 1; } else if (currDist < closestDist) { closestDroid = mydroid; // record this droid as being closest so far closestDist = currDist; } } } mydroid = iterateGroup(buildGroup); } if (numHelpDroids == 0 and closestDroid != NULLOBJECT) // found none within help radius, so force someone to go long distance traveling { orderDroidStatsLoc(closestDroid, DORDER_BUILD, bstats, bx, by); // you, book a plane ticket and go! return true; } return (numHelpDroids > 0); } event arrived(reachedTr) { local bool found; local STRUCTURESTAT myChoice; if (droid.droidType == DROID_CONSTRUCT or droid.droidType == DROID_CYBORG_CONSTRUCT) { dbgObj(droid, "Failed to build where we should - attempt to screw up enemy oil derrick"); // Check if at oil well, and it was taken by enemy structure = structureBuiltInRange(derrick, droid.x, droid.y, (5 * 128), -1); if (structure != NULLOBJECT) { if (not friendlyPlayer(structure.player) and droid.health == 100) { // Ok, at enemy derrick, and nobody has hurt us yet. Start being nasty. count = 0; found = false; // find simplest/cheapest one available to build while (count < numDefStructs and not found) { if (isStructureAvailable(defStructs[count], me)) { found = true; } else { count++; } } if (found) { buildX = droid.x; buildY = droid.y; if (pickDroidStructLocation(droid, defStructs[count], ref buildX, ref buildY, me, -1)) { orderDroidStatsLoc(droid, DORDER_BUILD, defStructs[count], buildX, buildY); } else { dbgObj(droid, "Wanted to be nasty, but found nowhere to build defense"); orderDroid(droid, DORDER_RTB); // nothing more to do here. } } else { dbgObj(droid, "Wanted to be nasty, but had nothing nasty to build - returning to base"); orderDroid(droid, DORDER_RTB); // oh, well. nothing more to do here. } exit; } else if (droid.health < 100 and !insideBase(droid.x, droid.y)) { orderDroid(droid, DORDER_RTR); // bolt back to base now! exit; } } } } event buildFundamentals(inactive) { count = 0; while (count < numFundamental) { // check that struct. structure = getStructure(structs[count], me); if (structure == NULLOBJECT) // if missing build it. { if (isStructureAvailable(structs[count], me)) { if (grabTrucksAndBuild(12, structs[count], 0)) { exit; // no need to check more } } } count = count + 1; } fundamentalBeingBuilt = derrick; setEventTrigger(buildFundamentals, inactive); } event startLevel(startLevelTr) { setEventTrigger(buildFundamentals, slowloadTr); setEventTrigger(conDroids, chainloadTr); setEventTrigger(doResearch, chainloadTr); setEventTrigger(buildDerrick, slowloadTr); setEventTrigger(startLevel, inactive); } // decide what technology branch we will use function void setTechBranch(int _tech) { local float _y2,_y1,_x2,_x1,_a,_y,_m,_rnd,_mapSize; _mapSize = (float)((mapWidth + mapHeight) / 2); if(_tech != -1) { curTech = _tech; } else { //probability to choose vtol branch for map size 90 = 0; probability for map size 200 = 45 //build a linear function: y = ((y2 - y1) / (x2 - x1)) * x + a depending on two values given (short: y = mx+a) _x1 = 90.0; _y1 = 0.0; _x2 = 200.0; _y2 = 45.0; _m = ((_y2 - _y1) / (_x2 - _x1)); _a = -(_m * _x1); //calculate probability for the current map _y = _m * _mapSize + _a; dbg("_m = " & _m & ", a = " & _a, me); _rnd = (float)random(100); if(_rnd < _y) { curTech = branchVTOL; dbg("going air (" & _y & "/" & _rnd & ")", me); } else { curTech = branchDefault; dbg("going land (" & _y & "/" & _rnd & ")", me); } } } /* returns TRUE if AI is responsible for the _player */ function bool aiResponsibleForPlayer(int _player) { if(not _DEBUG and ((_player == selectedPlayer) or not myResponsibility(_player))) { return FALSE; } return TRUE; } ///////////////////////////////////////////////////////////////////// // keep details about the size and postion of the ai players base event basedetails(basedetailsTr) { // clear old extremities. maxy = 0; maxx = 0; miny = (mapHeight*128); minx = (mapWidth*128); baseRange = 4 * TILE; // now find the extremities of our vital structures. count = 0; while(count < numBaseStruct) { initEnumStruct(FALSE,baseStruct[count],me,me); structure= enumStruct(); while(structure != NULLOBJECT) { if(structure.x < minx) { minx = structure.x; } if(structure.x > maxx) { maxx = structure.x; } if(structure.y < miny) { miny = structure.y; } if(structure.y > maxy) { maxy = structure.y; } result = distBetweenTwoPoints(baseX, baseY, structure.x, structure.y); if(result > baseRange){ baseRange = result; } structure= enumStruct(); } count = count + 1; } result = 3 * 128; minx = minx - result; maxx = maxx + result; miny = miny - result; maxy = maxy + result; baseRange = baseRange + (4 * 128); } ///////////////////////////////////////////////////////////////////// // structure building rules // build derricks on oil. event buildDerrick(buildDerrickTr) { local bool foundOne, _same; local FEATURE _oil, _closestOil; local int _bestDist, _newDist; local DROID _search; // what if we can't waste power on building derricks because we don't have a gen yet? if (playerPower(me) < 300 and haveStructure(derrick) and not haveStructure(powGen)) { setEventTrigger(buildDerrick, slowloadTr); exit; } _bestDist = 99999; _closestOil = NULLOBJECT; foundOne = false; initIterateGroup(buildGroup); // find all units in build group droid = iterateGroup(buildGroup); while (droid != NULLOBJECT && !foundOne) { if (droid.order != DORDER_BUILD and droid.order != DORDER_LINEBUILD and droid.order != DORDER_HELPBUILD) { foundOne = true; } else { droid = iterateGroup(buildGroup); } } if (droid != NULLOBJECT) { initGetFeature(oilRes, -1, me); _oil = getFeatureB(me); while (_oil != NULLOBJECT) { _newDist = distBetweenTwoPoints(droid.x, droid.y, _oil.x, _oil.y); _same = false; if (_newDist < _bestDist and droidCanReach(droid, _oil.x, _oil.y)) // this one is closer { if (!threatInRange(me, _oil.x, _oil.y, OIL_THREAT_RANGE, FALSE)) { initIterateGroup(buildGroup); // find all units in build group. _search = iterateGroup(buildGroup); foundOne = false; while (_search != NULLOBJECT && !foundOne) { if (_search.orderx == _oil.x and _search.ordery == _oil.y and _search != droid) { _same = true; foundOne = true; } _search = iterateGroup(buildGroup); } if (!_same) // do not go to same spot as another droid { _bestDist = _newDist; _closestOil = _oil; } } } _oil = getFeatureB(me); } if (_closestOil != NULLOBJECT) { orderDroidStatsLoc(droid, DORDER_BUILD, derrick, _closestOil.x, _closestOil.y); // build a derick if (idleGroup(buildGroup) > 0) { setEventTrigger(buildDerrick, slowloadTr); // do it again for next droid exit; } } } setEventTrigger(buildDerrick, buildDerrickTr); } ///////////////////////////////////////////////////////////////////// // if idle and derrick in range and no defense then build defense, else ret to base . event buildOilDefenseOrRetreat(buildOilDefenseOrRetreatTr) { local int _numBuilders,_maxBuilders; _maxBuilders = 1; // check idle. initIterateGroup(buildGroup); // find idle droids in build group. droid = iterateGroup(buildGroup); while(droid != NULLOBJECT) { if (droid.order != DORDER_BUILD and droid.order != DORDER_LINEBUILD and droid.order != DORDER_HELPBUILD) { // if in range of a derrick structure = structureBuiltInRange(derrick, droid.x, droid.y, (5*128), me); // if inside base limits then presume ok.. if( structure != NULLOBJECT) { if((structure.x > minx) and (structure.y > miny) and (structure.x < maxx) and (structure.y <maxy)) { structure = NULLOBJECT; } } if(structure != NULLOBJECT) { buildX = structure.x; buildY = structure.y; // not many defenses nearby if(numFriendlyWeapStructsInRange(me, buildX, buildY, (3*128), FALSE) < 2) { count = numDefStructs - 1; //pick a struct to build.. count2 = 0; while( (count2 < 5) and (count >= 0) ) { if( isStructureAvailable(defStructs[count],me)) { structChoice[count2] = defStructs[count]; count2 = count2 + 1; } count = count - 1; } count =0; if(count2 > 0) { count = random(count2); //count = choice! // pick a location boolResult = pickDroidStructLocation(droid, structChoice[count], ref buildX, ref buildY, me, -1); _numBuilders = numBuildSameBuilding(NULLSTRUCTURESTAT, buildX, buildY); if((boolResult == TRUE) and (_numBuilders < _maxBuilders) and droidCanReach(droid, buildX, buildY)) { // build it. orderDroidStatsLoc(droid, DORDER_BUILD,structChoice[count], buildX,buildY); _numBuilders++; } } } else { structure = structureBuiltInRange(playerHQ, droid.x, droid.y, (5*128), me); if(structure == NULLOBJECT) { if(!insideBase(droid.x, droid.y)) { orderDroid(droid,DORDER_RTB); // return to base; } } } } else { structure = structureBuiltInRange(playerHQ, droid.x, droid.y, (5*128), me); if(structure == NULLOBJECT) { if(!insideBase(droid.x, droid.y)) { orderDroid(droid,DORDER_RTB); // return to base; } } } } droid = iterateGroup(buildGroup); } } ///////////////////////////////////////////////////////////////////// //mortar etc.. rules. build sensor towers and emplacements. event incendry(incendryTr) { if (not isStructureAvailable(sensorTower, me)) { exit; } initEnumStruct(FALSE,sensorTower,me,me); count = 0; structure = enumStruct(); while(structure != NULLOBJECT) { count = count + 1; structure = enumStruct(); } if (count < (gameTime/4200)) // every 7 mins { // if not found build a sensor tower. // find a place to build. buildX = 0; buildY = 0; initEnumStruct(FALSE,derrick,me,me); structure= enumStruct(); while(structure != NULLOBJECT) { count = 0; result = 0; while(count < numDefStructs) { structure2 = structureBuiltInRange(defStructs[count], structure.x, structure.y,(4*128), me); if(structure2 != NULLOBJECT) { result = result + 1; } count = count + 1; } // check for sensor nearby, structure2 = structureBuiltInRange(sensorTower, structure.x, structure.y,(5*128), me); if(structure2 != NULLOBJECT) { result = 4; } if(result < 3) { buildX = structure.x; buildY = structure.y; structure = NULLOBJECT; } else { structure = enumStruct(); } } if(buildX != 0) { boolResult = pickStructLocation(sensorTower, ref buildX, ref buildY,me); // pick spot. if(boolResult == TRUE) { // find unit initIterateGroup(buildGroup); droid = iterateGroup(buildGroup); while(droid != NULLOBJECT) { if ((droid.order == DORDER_NONE or droid.order == DORDER_RTB) and droidCanReach(droid, buildX, buildY)) { orderDroidStatsLoc(droid, DORDER_BUILD, sensorTower, buildX, buildY); droid = NULLOBJECT; } else { droid = iterateGroup(buildGroup); } } } } } else { // find a sensor tower with least incencdry structs around it.. buildX = 0; buildY = 0; initEnumStruct(FALSE,sensorTower,me,me); structure= enumStruct(); count = 999; while(structure != NULLOBJECT) { // count incendrys near this tower. result = 0; count2 = 0; while(count2 < numIncendrys) { structure2 = structureBuiltInRange(incendrys[count2], structure.x, structure.y,(4*128), me); if(structure2 != NULLOBJECT) { result = result + 1; } count2 = count2 + 1; } if((result < 6) and (result < count)) // lowest found yet. only sites with <6 too. { buildX = structure.x; buildY = structure.y; count = result; } structure = enumStruct(); } if(buildX != 0) { // choose a device count = numIncendrys - 1; result = 99; while(count >= 0 ) { if(isStructureAvailable(incendrys[count],me)) { result = count; count = -1; } else { count = count - 1; } } // find a unit and build an incendry device. if(result != 99) { boolResult = pickStructLocation(incendrys[result], ref buildX, ref buildY,me); // pick spot. if(boolResult == TRUE) { initIterateGroup(buildGroup); droid = iterateGroup(buildGroup); boolResult = (numBuildSameBuilding(incendrys[result], buildX, buildY) > 0); //anyone building there already? while(droid != NULLOBJECT and (not boolResult)) { if ((droid.order == DORDER_NONE or droid.order == DORDER_RTB) and droidCanReach(droid, buildX, buildY)) { orderDroidStatsLoc(droid, DORDER_BUILD,incendrys[result], buildX,buildY); boolResult = TRUE; //only 1 truck } droid = iterateGroup(buildGroup); } } } } } } ///////////////////////////////////////////////////////////////////// // build a power gen for every 4 derricks. VITAL! event buildPowerGenerators(buildPowerGeneratorsTr) { if (!isStructureAvailable(powGen, me)) { exit; } initEnumStruct(FALSE,derrick,me,me); // count = numderricks structure= enumStruct(); count = 0; while(structure != NULLOBJECT) { count = count + 1; structure= enumStruct(); } initEnumStruct(FALSE,powGen,me,me); // count2 = numpowgens structure= enumStruct(); count2 = 0; while(structure != NULLOBJECT) { count2 = count2 + 1; structure= enumStruct(); } if( (count2 * 4) < count ) // if we need powergen { initIterateGroup(buildGroup); droid = iterateGroup(buildGroup); while(droid != NULLOBJECT) { if (droid.order != DORDER_HELPBUILD and droid.order != DORDER_BUILD and droid.order != DORDER_LINEBUILD) { buildX = baseX; // try build powergen. buildY = baseY; if (pickDroidStructLocation(droid, powGen, ref buildX, ref buildY, me, 1)) { orderDroidStatsLoc(droid, DORDER_BUILD, powGen, buildX,buildY); } } droid = iterateGroup(buildGroup); } } } ///////////////////////////////////////////////////////////////////// // ensure we have everything in the vital structs list. event buildBase(buildBaseTr) { if (idleGroup(buildGroup) >= (buildGroup.members / 2)) { count = 0; while(count < numStructs) { // check that struct. structure = getStructure(structs[count],me); if(structure == NULLOBJECT) // if missing build it. { if(isStructureAvailable(structs[count],me)) { if (grabTrucksAndBuild(10, structs[count], 0)) { exit; // done here } } } count = count + 1; } } } ///////////////////////////////////////////////////////////////////// // build other stuff, grow the base slowly... event buildExpand( buildExpandTr ) { if (playerPower(me) < LOW_POWER) { exit; // do not expand base with low power } if(extraStruct == numExtraStructs[curTech]) // loop round { extraStruct = 0; } if(isStructureAvailable(extraStructs[curTech][extraStruct],me)) { if (not grabTrucksAndBuild(10, extraStructs[curTech][extraStruct], 0)) { dbg("Failed to build expand", me); } } extraStruct = extraStruct + 1; } ///////////////////////////////////////////////////////////////////// // Structure (fac/res/pow) upgrades event upgradeStructures(upgradeStructuresTr ) { if (not havePowerSource()) { exit; } initIterateGroup(buildGroup); // find idle droids in build group. droid = iterateGroup(buildGroup); while(droid != NULLOBJECT) { if ((droid.order != DORDER_BUILD) and (droid.order != DORDER_LINEBUILD)) { boolResult = FALSE; if(curTech == branchDefault) { //powergen boolResult = upgradePowGen(droid, 2); //factory if(droid.order != DORDER_BUILD){ boolResult = upgradeFactory(droid, 3); } //research if(droid.order != DORDER_BUILD){ boolResult = upgradeResearch(droid, 1); } //vtol Factory if(droid.order != DORDER_BUILD){ boolResult = upgradeVtolFactory(droid, 1); } } else if(curTech == branchVTOL) { //powergen boolResult = upgradePowGen(droid, 2); //vtol Factory if(droid.order != DORDER_BUILD){ boolResult = upgradeVtolFactory(droid, 3); } //factory if(droid.order != DORDER_BUILD){ boolResult = upgradeFactory(droid, 2); } //research if(droid.order != DORDER_BUILD){ boolResult = upgradeResearch(droid, 1); } } } droid = iterateGroup(buildGroup); } } function bool upgradeFactory(DROID _truck, int _maxBuilders) { local STRUCTURE _factory; initEnumStruct(FALSE,factory,me,me); _factory = enumStruct(); while(_factory != NULLOBJECT) { // if upgrade is available && struct is not upgraded if( isStructureAvailable(facModule,me) and (skGetFactoryCapacity(_factory) < 2 ) and droidCanReach(_truck, _factory.x, _factory.y)) { if((numBuildSameBuilding(facModule, _factory.x, _factory.y) + numBuildSameBuilding(vtolFactory, _factory.x, _factory.y)) < _maxBuilders) { orderDroidStatsLoc(_truck, DORDER_BUILD,facModule, _factory.x,_factory.y); // upgrade it. return TRUE; } } _factory = enumStruct(); } return FALSE; } function bool upgradeVtolFactory(DROID _truck, int _maxBuilders) { local STRUCTURE _factory; initEnumStruct(FALSE,vtolFactory,me,me); _factory = enumStruct(); while(_factory != NULLOBJECT) { // if upgrade is available && struct is not upgraded if( isStructureAvailable(facModule,me) and (skGetFactoryCapacity(_factory) < 2 ) and droidCanReach(_truck, _factory.x, _factory.y)) { if((numBuildSameBuilding(facModule, _factory.x, _factory.y) + numBuildSameBuilding(factory, _factory.x, _factory.y)) < _maxBuilders) { orderDroidStatsLoc(_truck, DORDER_BUILD,facModule, _factory.x,_factory.y); // upgrade it. return TRUE; } } _factory = enumStruct(); } return FALSE; } function bool upgradeResearch(DROID _truck, int _maxBuilders) { local STRUCTURE _resFac; initEnumStruct(FALSE,resLab,me,me); _resFac = enumStruct(); while(_resFac != NULLOBJECT) { // if upgrade is available && struct is not upgraded if( isStructureAvailable(resModule,me) and (not testStructureModule(me, _resFac, 0)) and droidCanReach(_truck, _resFac.x, _resFac.y)) { if((numBuildSameBuilding(resModule, _resFac.x, _resFac.y) + numBuildSameBuilding(resLab, _resFac.x, _resFac.y)) < _maxBuilders) { orderDroidStatsLoc(_truck, DORDER_BUILD,resModule, _resFac.x,_resFac.y); // upgrade it. return TRUE; } } _resFac = enumStruct(); } return FALSE; } function bool upgradePowGen(DROID _truck, int _maxBuilders) { local STRUCTURE _powGen; initEnumStruct(FALSE,powGen,me,me); _powGen = enumStruct(); while(_powGen != NULLOBJECT) { // if upgrade is available && struct is not upgraded if( isStructureAvailable(powModule,me) and (not testStructureModule(me, _powGen, 0)) and droidCanReach(_truck, _powGen.x, _powGen.y)) { if((numBuildSameBuilding(powModule, _powGen.x,_powGen.y) + numBuildSameBuilding(powGen, _powGen.x,_powGen.y)) < _maxBuilders) { orderDroidStatsLoc(_truck, DORDER_BUILD, powModule, _powGen.x,_powGen.y); // upgrade it. return TRUE; } } _powGen = enumStruct(); } return FALSE; } ///////////////////////////////////////////////////////////////////// // Finish Building Part Built Structures event finishStructs(finishStructsTr) { initEnumStruct(TRUE,factory,me,me); structure= enumStruct(); while(structure != NULLOBJECT) { if(not structureComplete(structure)) { initIterateGroup(buildGroup); // find idle droids in build group. droid = iterateGroup(buildGroup); while(droid != NULLOBJECT) { if (droid.order != DORDER_BUILD and droid.order != DORDER_LINEBUILD and droidCanReach(droid, structure.x, structure.y) and distBetweenTwoPoints(droid.x, droid.y, structure.x, structure.y) < 20 * TILE) { orderDroidObj(droid,DORDER_HELPBUILD,structure); } droid = iterateGroup(buildGroup); } } structure= enumStruct(); } } ///////////////////////////////////////////////////////////////////// // fortify base by builiding defensive structs on the edge of the base. // rewrote fortify to use scrSkDefenseLocation(baseX,baseY,me); event newfortify(fortifyTr) { local int _numBuilders,_maxBuilders; _maxBuilders = 1; if(numGroupSameOrder(buildGroup, DORDER_LINEBUILD) >= _maxBuilders) { exit; } boolResult = FALSE; initIterateGroup(buildGroup); // find idle an idle veh.in build group. droid = iterateGroup(buildGroup); while((boolResult == FALSE) and (droid != NULLOBJECT)) { if (droid.order != DORDER_BUILD and droid.order != DORDER_LINEBUILD and droid.order != DORDER_HELPBUILD) { boolResult = TRUE; // dont do this again! tempx = baseX; tempy = baseY; // choose a suitable turret. count = numWallWeaps - 1; count2 = 0; while( (count2 < 3) and (count >= 0) ) { if( isStructureAvailable(wallWeaps[count],me)) { structChoice[count2] = wallWeaps[count]; count2 = count2 + 1; } count = count - 1; } count =0; if((count2 > 0) and (_numBuilders < _maxBuilders)) { count = random(count2); skDefenseLocationB(ref tempx,ref tempy,wall,structChoice[count],droid,me); _numBuilders++; } } droid = iterateGroup(buildGroup); } } ///////////////////////////////////////////////////////////////////// // droid building rules ///////////////////////////////////////////////////////////////////// // deal with a droid being built event droidBuiltAssign(droidBuiltTr) { if(isVtol(droid)) { if(vtolDefendGr.members < numDefendVtols) { groupAddDroid(vtolDefendGr, droid); } else { count = 0; while(count < numVtolAttackGroups) { if(vtolAttackGr[count].members < numAttackVtols) { dbg("added new vtol to group " & count, me); groupAddDroid(vtolAttackGr[count], droid); count = numVtolAttackGroups; } count++; } } } else if((droid.droidType != DROID_TRANSPORTER) and (droid.droidType != DROID_COMMAND)) { if((droid.droidType == DROID_REPAIR) or (droid.droidType == DROID_CYBORG_REPAIR)) { numRepairUnits = numRepairUnits + 1; } if((droid.droidType == DROID_CONSTRUCT) or (droid.droidType == DROID_CYBORG_CONSTRUCT)) // if constructor droid { groupAddDroid(buildGroup, droid); } else { if(droid.droidType == DROID_CYBORG) { groupAddDroid(defendGroup, droid); } else { if(scoutGroup.members < numScouts[curTech]) { groupAddDroid(scoutGroup, droid); } else if(attackGroup.members < numAttackers[curTech]) { groupAddDroid(attackGroup, droid); } else if( defendGroup.members < numDefenders[curTech]) { groupAddDroid(defendGroup, droid); } else { if(scoutGroup.members < maxScouts[curTech]) { groupAddDroid(scoutGroup, droid); } else if(attackGroup.members < maxAttackers[curTech]) { groupAddDroid(attackGroup, droid); } else if( defendGroup.members < maxDefenders[curTech]) { groupAddDroid(defendGroup, droid); } else //make them attack { groupAddDroid(attackGroup, droid); } } } } } } //When droid built: check emergency jobs, start building next droid event droidBuilt(droidBuiltTr) { local STRUCTURE _fundie; /* Start building next droid */ if(structure != NULLOBJECT) { // derrick works as NULL here, as NULLSTAT does not seem to work if (droid.droidType == DROID_CONSTRUCT and fundamentalBeingBuilt != derrick) { _fundie = getStructure(fundamentalBeingBuilt, me); if (_fundie != NULLOBJECT) { if (not structureComplete(_fundie)) { orderDroidObj(droid, DORDER_HELPBUILD, _fundie); } } } if (droid.droidType == DROID_CONSTRUCT && structure.stattype == REF_FACTORY) { setEventTrigger(conDroids, chainloadTr); // consider building more } // Continue building new droids right away else if(structure.stattype == REF_FACTORY) { factoryBuildDroid(structure); } else if(structure.stattype == REF_CYBORG_FACTORY) { cybFactorBuildCyborg(structure); } else if(structure.stattype == REF_VTOL_FACTORY) { vtolFactoryBuildVtol(structure); } } } /* Gets triggered when structure was built */ event structBuilt(structBuiltTr) { local FEATURE _oilResource; local int _count,_count2; if (structure == NULLOBJECT || droid == NULLOBJECT) { exit; } /* factory or factory module */ if(structure.stattype == REF_FACTORY) { if (isStructureAvailable(facModule, me) and (skGetFactoryCapacity(structure) < 2 ) and (getDroidCount(me) > 4)) { orderDroidStatsLoc(droid, DORDER_BUILD,facModule, structure.x,structure.y); // upgrade it. } else { setEventTrigger(conDroids, chainloadTr); } } /* vtol factory or vtol factory module */ else if(structure.stattype == REF_VTOL_FACTORY) { if( isStructureAvailable(facModule,me) and (skGetFactoryCapacity(structure) < 2 )) { orderDroidStatsLoc(droid, DORDER_BUILD,facModule, structure.x,structure.y); // upgrade it. } } else if(structure.stattype == REF_RESOURCE_EXTRACTOR) { setEventTrigger(buildDerrick, chainloadTr); exit; } else if (structure.stattype == REF_RESEARCH) { if (isStructureAvailable(resModule, me)) { orderDroidStatsLoc(droid, DORDER_BUILD, resModule, structure.x, structure.y); // upgrade it. } else { setEventTrigger(doResearch, chainloadTr); } } else if (structure.stattype == REF_POWER_GEN) { if (isStructureAvailable(powModule, me)) { orderDroidStatsLoc(droid, DORDER_BUILD, powModule, structure.x, structure.y); // upgrade it. } } // Check if available trucks need to build more absolute necessities right away. We need a trigger here because // droids involved in building have not yet come out of their build orders. setEventTrigger(buildFundamentals, slowloadTr); //see if we have just rebuilt a destroyed structure _count = 0; while(_count < countRebuildStruct) { if(structure.x == rebuildStructX[_count] and structure.y == rebuildStructY[_count] and ( (structure.stat == rebuildStructStat[_count]) or //walls can end up as corner walls ( (structure.stat == wall or structure.stat == cornerWall) and (rebuildStructStat[_count] == wall or rebuildStructStat[_count] == cornerWall)) )) { dbg("finished rebuilding destroyed structure - " & _count, me); //resort destroyed structures _count2 = _count; while(_count2 < (countRebuildStruct - 1)) { rebuildStructX[_count2] = rebuildStructX[_count2 + 1]; rebuildStructY[_count2] = rebuildStructY[_count2 + 1]; rebuildStructStat[_count2] = rebuildStructStat[_count2 + 1]; _count2++; } //clear last entry rebuildStructX[countRebuildStruct - 1] = 0; rebuildStructY[countRebuildStruct - 1] = 0; rebuildStructStat[countRebuildStruct - 1] = NULLSTRUCTURESTAT; countRebuildStruct--; //we just built one structure //_count = countRebuildStruct; //exit outer loop } _count++; } } ///////////////////////////////////////////////////////////////////// // deal with attacks. event droidDestroyed(droidDestroyedTr) { if(droid.droidType == DROID_REPAIR) { numRepairUnits = numRepairUnits - 1; } if(droid.droidType == DROID_CONSTRUCT) // if constructor droid { initEnumStruct(FALSE,factory,me,me); structure= enumStruct(); // find factory. if( (structure != NULLOBJECT) and (getDroidCount(me) < MAX_DROIDS) ) { buildDroid(constructor, structure, me, 1); // build constructor } } } ///////////////////////////////////////////////////////////////////// // build more con droids. event conDroids(conDroidsTr) { local int _maxTrucks; local STRUCTURE _factory; local int _numBuilding,_haveTrucks,_maxTruckFactories,_totalTrucks; local bool _bStartedBuilding; _maxTrucks = MAX_TRUCKS; if (playerPower(me) < LOW_POWER) { _maxTrucks = MIN_TRUCKS; } _maxTruckFactories = 3; //max factories to use for truck production _haveTrucks = buildGroup.members; //Find out how many trucks and combat engineers are already in production _numBuilding = numTemplatesInProduction(constructor,me); //trucks _numBuilding = _numBuilding + numTemplatesInProduction(cybEngineer,me); //engineers _totalTrucks = _numBuilding + _haveTrucks; initEnumStruct(FALSE,factory,me,me); _factory = enumStruct(); while ((_factory != NULLOBJECT) and (_numBuilding < _maxTruckFactories) and (_totalTrucks < _maxTrucks)) { //Try to build a truck if (skCanBuildTemplate(me, _factory, hovertruck)) { _bStartedBuilding = buildUnit(hovertruck, _factory, factory, FALSE); //build truck even if not idle } else { _bStartedBuilding = buildUnit(constructor, _factory, factory, FALSE); //build truck even if not idle } //Update statistics if started building a truck if(_bStartedBuilding) { _numBuilding++; _totalTrucks++; } _factory = enumStruct(); } //build cyborg engineers if needed, no building structure limit here initEnumStruct(FALSE,cybFactory,me,me); _factory = enumStruct(); while((_factory != NULLOBJECT) and (_totalTrucks < _maxTrucks)) { //Try to build a truck if( skCanBuildTemplate(me,_factory, cybEngineer) ) //make sure we have researched cyb engineer { _bStartedBuilding = buildUnit(cybEngineer, _factory, cybFactory, FALSE); //build a cyb eng even if not idle //Update statistics if started building a cyborg engineer if(_bStartedBuilding) { _numBuilding++; _totalTrucks++; } } _factory = enumStruct(); } setEventTrigger(conDroids, conDroidsTr); } //Build a droid function bool buildUnit(TEMPLATE _tankTemplate, STRUCTURE _factory, STRUCTURESTAT _factoryType, bool _bIdleOnly) { //Factory was not provided, find an factory if(_factory == NULLOBJECT) { _factory = findIdleStructure(_factoryType, _bIdleOnly); } //Build if got a factory if(_factory != NULLOBJECT) { if(structureComplete(_factory) and (getDroidCount(me) < MAX_DROIDS)) { if( !(_bIdleOnly and !structureIdle(_factory)) ) //don't build if only allowed to build whe idle and fac is not idle { buildDroid(_tankTemplate, _factory, me, 1); // build a tank return TRUE; //success } } } return FALSE; //failed } //Returns an idle structure of the provided type or NULLOBJECT if none found function STRUCTURE findIdleStructure(STRUCTURESTAT _structType, bool _bIdleOnly) { local STRUCTURE _structure; initEnumStruct(FALSE,_structType,me,me); _structure = enumStruct(); while(_structure != NULLOBJECT) { if(structureComplete(_structure)) { if( !(_bIdleOnly and !structureIdle(_structure)) ) { return _structure; } } _structure = enumStruct(); } return NULLOBJECT; //none found } ///////////////////////////////////////////////////////////////////// // build repair droids. event repairDroids(repairDroidsTr) { // if we're running low on repair droids, build some.. if(numRepairUnits <3) { initEnumStruct(FALSE,factory,me,me); structure= enumStruct(); // find factory. if (structure != NULLOBJECT) { if ((getDroidCount(me) < MAX_DROIDS) and (skCanBuildTemplate(me, structure, repairUnit))) { buildDroid(repairUnit, structure, me, 1); // build repairunit. } } } } ///////////////////////////////////////////////////////////////////// event factoryEvent(factoryEventTr) { // for each factory.... initEnumStruct(FALSE,factory,me,me); structure = enumStruct(); // find factory. if(getDroidCount(me) < MAX_DROIDS) { while(structure != NULLOBJECT) { if( structureIdle(structure) ) { factoryBuildDroid(structure); } structure = enumStruct(); } } } function bool needTank() { if(not havePowerSource()) { return FALSE; } if((defendGroup.members < maxDefenders[curTech]) or (maxDefenders[curTech] == UNLIMITED)) { return TRUE; } if((scoutGroup.members < maxScouts[curTech]) or (maxScouts[curTech] == UNLIMITED)) { return TRUE; } if((attackGroup.members < maxAttackers[curTech]) or (maxAttackers[curTech] == UNLIMITED)) { return TRUE; } return FALSE; } function void factoryBuildDroid(STRUCTURE _factory) { local int _count,_count2; if(_factory == NULLOBJECT){ dbg("factoryBuildDroid: factory is NULLOBJECT", me); return; } if(not needTank()) { //dbg("NEED NO TANKS!! " & maxDefenders[curTech], me); return; } if( structureIdle(_factory) ) { _count = numTemplates[curTech] - 1; _count2 = 0; while( (_count2 < MAX_RANDOM_TEMPLATES) and (_count >= 0) ) { if( skCanBuildTemplate(me,_factory, tmpl[curTech][_count]) ) { tmplChoice[_count2] = tmpl[curTech][_count]; _count2 = _count2 + 1; } _count = _count - 1; } if(_count2 > 0) { buildDroid(tmplChoice[random(_count2)],_factory,me,1); } } else { dbg("factoryBuildDroid: factory is busy", me); } } ///////////////////////////////////////////////////////////////////// // put cyborg factories to work event cyborgFactoryEvent(cyborgFactoryEventTr) { if(not ((defendGroup.members < maxCyborgs[curTech]) or (maxCyborgs[curTech] == UNLIMITED))) { exit; //we need no cyborgs } initEnumStruct(FALSE,cybFactory,me,me); structure= enumStruct(); // find factory. while(structure != NULLOBJECT) { if( structureIdle(structure) == TRUE) { cybFactorBuildCyborg(structure); } structure= enumStruct(); // find factory. } } function void cybFactorBuildCyborg(STRUCTURE _factory) { if(_factory == NULLOBJECT){ dbg("cybFactorBuildCyborg: factory is NULLOBJECT", me); return; } if( structureIdle(_factory) ) { if( (defendGroup.members < maxCyborgs[curTech]) and (getDroidCount(me) < MAX_DROIDS) ) { if(random(5) == 1) { buildDroid(cybMechanic,_factory,me,1); } else { count = 3; count2 = 0; while( count >= 0 ) { if( skCanBuildTemplate(me,_factory, superCyb[count]) ) { tmplChoice[count2] = superCyb[count]; count2 = count2 + 1; } count = count - 1; } if(count2 > 0) { buildDroid(tmplChoice[random(count2)],_factory,me,1); } else //try light cyborgs { count = numLightCyborgs - 1; count2 = 0; while( (count >= 0) and (count2 < 2) ) { if( skCanBuildTemplate(me,_factory, cybTempl[count]) ) { tmplChoice[count2] = cybTempl[count]; count2++; } count--; } if(count2 > 0) { buildDroid(tmplChoice[random(count2)], _factory, me, 1); } } } } } } ///////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////// // scouting rules // scout an area event chooseScoutArea(chooseScoutAreaTr) { scoutX = scoutTLX + random(scoutW); scoutY = scoutTLY + random(scoutH); } ///////////////////////////////////////////////////////////////////// // visit new places event expandScoutArea(expandScoutAreaTr) { //expand the scouting area slightly scoutTLX = scoutTLX - ((mapWidth*128)/ tileExpand); scoutTLY = scoutTLY - ((mapHeight*128)/ tileExpand); scoutW = scoutW + (2*((mapWidth*128)/ tileExpand)); scoutH = scoutH + (2*((mapHeight*128)/ tileExpand)); // check & restrain. if(scoutTLX <1) { scoutTLX = 1; } if(scoutTLY <1) { scoutTLY = 1; } if(scoutTLX >(mapWidth*128)) { scoutTLX = (mapWidth*128) - 128; } if(scoutTLY >(mapHeight*128)) { scoutTLY = (128*mapHeight) - 128; } if( (scoutTLX + scoutW) > (128 * mapWidth) ) { scoutW = ( (128 * mapWidth) - scoutTLX) - 128; } if( (scoutTLY + scoutH) > (128 *mapHeight) ) { scoutH = ( (128*mapHeight) - scoutTLY) - 128; } } ///////////////////////////////////////////////////////////////////// // order scouts event scoutMain(scoutMainTr) { // find any new scouts // if scouts aren't busy, send them to a new spot. if( idleGroup(scoutGroup) >= (scoutGroup.members /2) ) { orderGroupLoc(scoutGroup, DORDER_MOVE,scoutX,scoutY); } } ///////////////////////////////////////////////////////////////////// // process new visibility reports event newObjectReport(newObjectReportTr) { if(!friendlyPlayer(baseobj.player)) { if(targetTypeValue(baseobj) > targetTypeValue(attackObj)) { attackObj = baseobj;// got a new unseen target from a scout. if( attackObj.type == OBJ_STRUCTURE) { if(not allianceExistsBetween(attackObj.player,me)) // an enemy { structure = objToStructure(attackObj); if(structure.stat == factory) { allOutAttack = attackObj; } } } } } } function int targetTypeValue(BASEOBJ _target) { local STRUCTURE _strTarget; if(_target == NULLOBJECT){ return NO_TARGET_VALUE; } if(_target.type == OBJ_DROID) { return DROID_TARGET_VALUE; } else if(_target.type == OBJ_STRUCTURE) { _strTarget = objToStructure(_target); if(_strTarget.stattype == REF_DEFENSE) { return DEFENSE_TARGET_VALUE; } else if(_strTarget.stattype == REF_RESEARCH or _strTarget.stattype == REF_POWER_GEN) { return RESEARCH_TARGET_VALUE; } else if(_strTarget.stattype == REF_HQ or _strTarget.stattype == REF_COMMAND_CONTROL) { return HQ_TARGET_VALUE; } else if(_strTarget.stattype == REF_RESOURCE_EXTRACTOR) { return OIL_TARGET_VALUE; } else if(_strTarget.stattype == REF_FACTORY or _strTarget.stattype == REF_CYBORG_FACTORY or _strTarget.stattype == REF_VTOL_FACTORY) { return FACTORY_TARGET_VALUE; } else //walls, rearm pads etc { return OTHER_TARGET_VALUE; } } return NO_TARGET_VALUE; } ///////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////// // spy technologies //event takeover( CALL_UNITTAKEOVER , ref droid ) event takeover(takeoverTr) { if( droid.player == me ) { if(droid.droidType == DROID_CONSTRUCT or droid.droidType == DROID_CYBORG_CONSTRUCT) { groupAddDroid( buildGroup, droid ); } else if (droid.droidType != DROID_TRANSPORTER && droid.droidType != DROID_COMMAND) { groupAddDroid( attackGroup, droid ); } } } event takeoverDefend(takeoverTr) { if( droid.player != me ) { completeResearch(nexusDefence,me); setEventTrigger(takeoverDefend, inactive); } } event useLassat(useLassatTr) { // find my lassat // fire it at my attack objective. if(allOutAttack != NULLOBJECT) { initEnumStruct(FALSE,lassat,me,me); structure= enumStruct(); while(structure != NULLOBJECT) { if(structureComplete(structure) == TRUE) { skFireLassat(me,allOutAttack); } structure= enumStruct(); } } } ///////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////// // attack rules event findEnemy(attackStuffTr) { if(attackObj == NULLOBJECT) { count = random(8); count2 = 100; while( friendlyPlayer(count) && (count2 > 0) ) { count = random(8); count2--; } if(!friendlyPlayer(count)) { baseobj = skLocateEnemy(count); if(baseobj != NULLOBJECT) { attackObj = baseobj; // set allOutAttack to attackObj only if attackObj is a more valuable target than allOutAttack if(targetTypeValue(attackObj) > targetTypeValue(allOutAttack)) { allOutAttack = attackObj; } } } } } ///////////////////////////////////////////////////////////////////// // send attack team out to cause trouble near things scout found. event attackStuff(attackStuffTr) { if( idleGroup(attackGroup) >= (attackGroup.members / 2)) { if( (attackObj != NULLOBJECT) and (not helpingAlly()) ) { if (not allianceExistsBetween(me, attackObj.player)) { if(attackGroup.members > (6 + random(6)) ) { orderGroupLoc(attackGroup, DORDER_SCOUT, attackObj.x, attackObj.y); } // make scouts attack too if( idleGroup(scoutGroup) >= (scoutGroup.members / 2) ) { orderGroupLoc(scoutGroup, DORDER_SCOUT, attackObj.x, attackObj.y); } } } } } ///////////////////////////////////////////////////////////////////// event doAllOutAttack(allOutAttackTr) { if (idleGroup(attackGroup) >= (attackGroup.members / 3)) // make sure at least 30% are idle { if ((allOutAttack != NULLOBJECT) and (not helpingAlly())) { if (!friendlyPlayer(allOutAttack.player)) { if (getDroidCount(me) > 40) // plenty of units. { orderGroupObj(attackGroup, DORDER_ATTACK, allOutAttack); orderGroupLoc(scoutGroup, DORDER_SCOUT, allOutAttack.x, allOutAttack.y); } } else { allOutAttack = NULLOBJECT; } } } } ///////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////// // defending rules // defend attacked objects. event defendWatch(defendWatchTr) { if (baseobj != NULLOBJECT) { if(!friendlyPlayer(baseobj.player)) { if(distBetweenTwoPoints(baseobj.x, baseobj.y, baseX, baseY) <= MAX_DEFENDERS_RADIUS) //don't go too far away from the base { defendObj = baseobj; defendbusy = TRUE; // if not too busy, attack. if (idleGroup(defendGroup) >= (defendGroup.members / 2)) { orderGroupLoc(defendGroup, DORDER_MOVE,defendObj.x,defendObj.y); //cyborg mechanics can't attack (won't move) } if (idleGroup(scoutGroup) >= (scoutGroup.members / 2)) { orderGroupLoc(scoutGroup, DORDER_MOVE,scoutX,scoutY); } } } } } ///////////////////////////////////////////////////////////////////// // defenders return after they are finished. event defendReturn(defendReturnTr) { if( defendbusy and (idleGroup(defendGroup) == (defendGroup.members - defendGroup.members / 12))) { // find a place with no structures nearby buildX = baseX; buildY = baseY; pickStructLocationB(powGen, ref buildX, ref buildY, me, 0); orderGroupLoc(defendGroup, DORDER_MOVE,buildX,buildY); defendbusy = FALSE; } } //returns number of non-idle structures of a certain type function int numStructBusyByType(STRUCTURESTAT _busyStructType) { local int _result; initEnumStruct(FALSE,_busyStructType,me,me); structure = enumStruct(); _result = 0; while(structure != NULLOBJECT) { if(structureComplete(structure)) { if(not structureIdle(structure)) { _result++; } } structure = enumStruct(); } return _result; } ///////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////// // Research Rules Now does true research. // do research event doResearch(doResearchTr) { local int _techIndex,_numResearching; // don't throw in half of your money on research in T3 no bases when we don't have any income yet if (isStructureAvailable(facModule,me) and not havePowerSource()) { setEventTrigger(doResearch, doResearchTr); exit; } _techIndex = 0; //research start _numResearching = numStructBusyByType(resLab); // for every research lab do this.. initEnumStruct(FALSE,resLab,me,me); structure= enumStruct(); count = 0; while(structure != NULLOBJECT) { boolResult = FALSE; //haven't started research for the current resFac if(structureIdle(structure)) { if(structureComplete(structure)) { // first research all technologies necessary for the current research branch while(not boolResult and _techIndex != NONE) //not started researching and still branch tech left to try { _techIndex = findResearch(_techIndex, curTech); if(_techIndex > NONE) { boolResult = pursueResearch(structure,me,tech[curTech][_techIndex]); _techIndex++; //try nect research next time if needed _numResearching++; } } // do common research if(not boolResult) //didn't start branch research { if((maxIdleRes[curTech] == UNLIMITED) or (_numResearching < maxIdleRes[curTech])) { skDoResearch(structure,me,0); _numResearching++; } } } } structure = enumStruct(); } setEventTrigger(doResearch, doResearchTr); } // find next available research of our research branch function int findResearch(int _searchStart, int _techTree) { local int _result; ASSERT(_searchStart >= 0, "findResearch: _searchStart < 0", me); ASSERT(_techTree >= 0, "findResearch: _techTree < 0", me); _result = _searchStart; while(_result < techCount[_techTree]) { if((not researchFinished(tech[_techTree][_result], me)) and (not researchStarted(tech[_techTree][_result], me))) { return _result; //found research } _result++; } return NONE; //not found } ///////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////// // Alliance Rules // form alliances event formAllianceEvent(formAllianceEventTr) { count = 0; while(count < MAX_PLAYERS) { if( count != me ) // if not the only other player and rand2 { if((getDroidCount(me) > 1) and (getDroidCount(count) > 1) ) // not dead { if(random(28) == 1) // bit random { if(not isHumanPlayer(count)) // not human { createAlliance(me,count); allianceTime[count] = gameTime; } } } } count = count + 1; } } ///////////////////////////////////////////////////////////////////// // break the alliance too. event breakAllianceEvent(breakAllianceEventTr) { count = 0; while(count<multiPlayerMaxPlayers) { if( count != me) { if((getDroidCount(me) > 1) and (getDroidCount(count) > 1) ) // not dead { if(allianceExistsBetween(me,count) ) { // check if we're in alliance with any other players. if( (random(30) == 1) and ( (gameTime - allianceTime[count]) > 6000) ) // rand and more than 10 minutes. { allianceTime[count] = gameTime; breakAlliance(me,count); } // rules for breaking alliances with humans. // built within my base if(numStructsInArea(count,minx,miny,maxx,maxy) > 1) { allianceTime[count] = gameTime; breakAlliance(me,count); } // you've got lots of units in my area. if(numDroidsInArea(count,minx,miny,maxx,maxy) > 3) { allianceTime[count] = gameTime; breakAlliance(me,count); } // you've wiped out one of my allies ??. } } } count = count + 1; } } ///////////////////////////////////////////////////////////////////// event formHumanAlliances(humanAllianceTr) { if(count2 == me) // offered to me. { result = 0; result2 = 0; while(result < multiPlayerMaxPlayers) { if(allianceExistsBetween(count,result)) { result2 = result2 + 1; } result = result + 1; } if( result2 < ((multiPlayerMaxPlayers / 2) - 1) ) // not too many already { //not too soon. if((allianceTime[count] == 0) or (gameTime - allianceTime[count] > 1200)) { result = 0; // check forming wont end the game result2 = 0; while(result < multiPlayerMaxPlayers) { while(result2 < multiPlayerMaxPlayers) { if((not allianceExistsBetween(result,result2)) and (getDroidCount(result) > 0) and (getDroidCount(result2) > 0) and (result != result2) ) { if( ((result == count and result2 == count2) or (result2 == count2 and result == count)) ) // ignore the outcome of this alliance { createAlliance(me,count); allianceTime[count] = gameTime; } } result2 = result2 + 1; } result = result + 1; } } } } } ///////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////// // Consolidate Rules // bring forces back together to consolidate attacks event consolidateEvent(consolidateEventTr) { if(not helpingAlly()) { if(random(3) == 1) // order all droids home to rejoin forces.! { // find a place with no structures nearby buildX = baseX; buildY = baseY; pickStructLocationB(powGen, ref buildX, ref buildY, me, 0); orderGroupLoc(scoutGroup, DORDER_MOVE,buildX,buildY); orderGroupLoc(defendGroup, DORDER_MOVE,buildX,buildY); } /* if(attackObj != NULLOBJECT) // consolidate any ongoing attack. { if(!friendlyPlayer(attackObj.player)) { orderGroupLoc(attackGroup, DORDER_SCOUT, attackObj.x, attackObj.y); } else { attackObj = NULLOBJECT; } } else if(allOutAttack == NULLOBJECT) //make sure not allOutAttacking { // find a place with no structures nearby buildX = baseX; buildY = baseY; pickStructLocationB(powGen, ref buildX, ref buildY, me, 0); orderGroupLoc(attackGroup, DORDER_MOVE,buildX,buildY); } */ } } ///////////////////////////////////////////////////////////////////// event difficultyModifier(difficultyModifierTr) { if(not isHumanPlayer(me)) { skDifficultyModifier(me); } } ///////////////////////////////////////////////////////////////////// // vtols. ///////////////////////////////////////////////////////////////////// // build vtol strucutures. event vtolStructs(inactive) { local int _numVtolFacs,_numRearmPads; // got any idle trucks? if (idleGroup(buildGroup) < 1) { exit; } // see how many vtol factories we already have _numVtolFacs = getNumStructures(vtolFactory,me); _numRearmPads = getNumStructures(vtolPad,me); //see if we have enough rearm pads if( _numRearmPads * 4 / 3 <= totalVtols() ) { dbg("NEED REARM PADS", me); buildRearmPads(); } if (_numVtolFacs > 0 and playerPower(me) < LOW_POWER) { exit; // Throttle expansion to avoid waste } if (isStructureAvailable(vtolFactory, me) and _numVtolFacs < maxVtolFacs[curTech]) // if not enough { if (not grabTrucksAndBuild(8, vtolFactory, 1)) { dbg("Failed to build Vtol fac", me); } } } //counts vtols function int totalVtols() { local int _vtolGroup,_totalVtols; _totalVtols = 0; _vtolGroup = 0; while(_vtolGroup < numVtolAttackGroups) { _totalVtols = _totalVtols + vtolAttackGr[_vtolGroup].members; _vtolGroup++; } _totalVtols = _totalVtols + vtolDefendGr.members; return _totalVtols; } function void buildRearmPads() { if (isStructureAvailable(vtolPad, me)) { if (not grabTrucksAndBuild(4, vtolPad, -1)) { dbg("Failed to build vtol pad", me); } } } ///////////////////////////////////////////////////////////////////// // build vtols. event buildVtols(inactive) { // got enough vtols? if((vtolDefendGr.members >= maxVTOLs[curTech]) or (getDroidCount(me) >= MAX_DROIDS)){ dbg("CAN'T BUILD VTOLS - TOO MANY UNITS", me); exit; } // build vtols initEnumStruct(FALSE,vtolFactory,me,me); structure = enumStruct(); while(structure != NULLOBJECT) { if(structureIdle(structure)) // if factory idle { vtolFactoryBuildVtol(structure); } structure = enumStruct(); } } function void vtolFactoryBuildVtol(STRUCTURE _factory) { local int _numTemplates,_bestTemplates; if(_factory == NULLOBJECT){ return; } if( structureIdle(_factory) ) { _numTemplates = numVtolTemplates - 1; _bestTemplates = 0; while( (_bestTemplates < 3) and (_numTemplates >= 0) ) { if( skCanBuildTemplate(me,_factory, vtols[_numTemplates]) ) { tmplChoice[_bestTemplates] = vtols[_numTemplates]; _bestTemplates++; } _numTemplates--; } if(_bestTemplates > 0) { buildDroid(tmplChoice[random(_bestTemplates)],_factory,me,1); } } } ///////////////////////////////////////////////////////////////////// // attack with vtols. event vtolAttack(inactive) { local int _groupIndex,_newTargetWeight,_oldTargetWeight; local BASEOBJ _newTarget; local bool _bHaveDefendTarget; local DROID _droid; // if vtol group is not busy.. if( (idleGroup(vtolDefendGr) >= (vtolDefendGr.members / 2)) and (vtolDefendGr.members >= 2) ) { if(attackObj != NULLOBJECT) { if(!friendlyPlayer(attackObj.player)) { orderGroupObj(vtolDefendGr, DORDER_ATTACK, attackObj); // get the attack target. } else { attackObj = NULLOBJECT; } } else { if(defendObj != NULLOBJECT) { orderGroupObj(vtolDefendGr, DORDER_ATTACK,defendObj); // get the defend target } } } //make sure attack vtol groups are not cluttered rearrangeAttackVtols(); //attack vtols _groupIndex = 0; while(_groupIndex < numVtolAttackGroups) { if(vtolAttackGr[_groupIndex].members > 0) { // if our base is in trouble see if we have a target in the base // don't choose new target if already have one _bHaveDefendTarget = FALSE; if((vtolGrAttackObj[_groupIndex] != NULLOBJECT)) { if(defendingOwnBase() and (distBetweenTwoPoints(baseX, baseY, vtolGrAttackObj[_groupIndex].x, vtolGrAttackObj[_groupIndex].y) <= MAX_VTOL_DEFEND_RADIUS)) { _bHaveDefendTarget = TRUE; } else //reset target if it's not worth it { //we don't want to attack enemy heavy tanks outside of our base if(vtolGrAttackObj[_groupIndex].type == OBJ_DROID) { _droid = objToDroid(vtolGrAttackObj[_groupIndex]); if(_droid.droidType != DROID_CONSTRUCT) { vtolGrAttackObj[_groupIndex] = NULLOBJECT; //reset target _bHaveDefendTarget = FALSE; } } } } //find target in our base if our base is in trouble if(!_bHaveDefendTarget and defendingOwnBase()) { vtolGrAttackObj[_groupIndex] = chooseVtolDefenceTarget(baseX, baseY, MAX_VTOL_DEFEND_RADIUS, FALSE); if(vtolGrAttackObj[_groupIndex] != NULLOBJECT) { dbg("assigned new defence target for group " & _groupIndex, me); _bHaveDefendTarget = TRUE; } } //attack rules if(!_bHaveDefendTarget and (idleGroup(vtolAttackGr[_groupIndex]) >= (vtolAttackGr[_groupIndex].members / 2)) and (vtolAttackGr[_groupIndex].members >= (numAttackVtols * 2 / 3))) { _newTarget = NULLOBJECT; //reset attack targets once in a while if(vtolGrAttackObj[_groupIndex] != NULLOBJECT) { if(random(10) > 7) { vtolGrAttackObj[_groupIndex] = NULLOBJECT; } } //now try to find an attack target if we have no defence target //find best attack target _newTarget = chooseVtolTarget(TRUE); //search for an exclusive target if(_newTarget == NULLOBJECT) { _newTarget = chooseVtolTarget(FALSE); //search for any target } _newTargetWeight = getVtolTargetWeight(_newTarget); _oldTargetWeight = getVtolTargetWeight(vtolGrAttackObj[_groupIndex]); // new one or a much better one if((_newTargetWeight >= (_oldTargetWeight + 20)) or (vtolGrAttackObj[_groupIndex] == NULLOBJECT )) { dbg("choosing new attack object for " & _groupIndex, me); vtolGrAttackObj[_groupIndex] = _newTarget; } } //see if this group has something to attack if(vtolGrAttackObj[_groupIndex] != NULLOBJECT) { if(!friendlyPlayer(vtolGrAttackObj[_groupIndex].player)) { dbg("VTOL Group " & _groupIndex & " attacking", me); if(_DEBUG and (_groupIndex == 0)) { dropBeacon(getPlayerName(me), me, me, vtolGrAttackObj[_groupIndex].x, vtolGrAttackObj[_groupIndex].y, 0); } orderGroupObj(vtolAttackGr[_groupIndex], DORDER_ATTACK, vtolGrAttackObj[_groupIndex]); } else { vtolGrAttackObj[_groupIndex] = NULLOBJECT; } } } _groupIndex++; } } //make sure vtol groups are not cluttered function void rearrangeAttackVtols() { local int _emptyGr,_fillGr; local DROID _droid; _emptyGr = 0; while(_emptyGr < numVtolAttackGroups) { if((vtolAttackGr[_emptyGr].members < numAttackVtols) and //this group is not full (vtolAttackGr[_emptyGr].members > 0)) { //try to make full groups by moving vtols from the last groups _fillGr = _emptyGr + 1; //start from the next group while((_fillGr < numVtolAttackGroups) and (vtolAttackGr[_emptyGr].members < numAttackVtols)) { initIterateGroup(vtolAttackGr[_fillGr]); _droid = iterateGroup(vtolAttackGr[_fillGr]); while((_droid != NULLOBJECT) and (vtolAttackGr[_emptyGr].members < numAttackVtols)) { groupAddDroid(vtolAttackGr[_emptyGr], _droid); //refill the group _droid = iterateGroup(vtolAttackGr[_fillGr]); } _fillGr++; } } _emptyGr++; } } function BASEOBJ chooseVtolDefenceTarget(int _x, int _y, int _range, bool bExclusiveTarget) { local BASEOBJ _target; _target = getClosestEnemy(_x, _y, _range, FALSE, FALSE, me); // make sure no one else is targeting it already if we want exclusive targets if(bExclusiveTarget and vtolTargetAssigned(_target)) { _target = NULLOBJECT; } return _target; } function BASEOBJ chooseVtolTarget(bool bExclusiveTarget) { local int _structTypeIndex,_enemy; local int _bestScore,_tempScore; local BASEOBJ _bestTarget; local STRUCTURE _structure; _bestScore = 0; _bestTarget = NULLOBJECT; _enemy = 0; while(_enemy < MAX_PLAYERS) { if(!friendlyPlayer(_enemy)) { _structTypeIndex = 0; while(_structTypeIndex < numVtolTargets) { initEnumStruct(FALSE,vtolTarget[_structTypeIndex],_enemy,me); _structure = enumStruct(); while(_structure != NULLOBJECT) { // in case we don't want all groups to attack the same target if(not (bExclusiveTarget and vtolTargetAssigned(_structure)) ) { _tempScore = getVtolTargetWeight(_structure); //see if this one is better if(_tempScore > _bestScore) { _bestScore = _tempScore; _bestTarget = _structure; } } _structure = enumStruct(); } _structTypeIndex++; } } _enemy++; } return _bestTarget; } function int getVtolTargetWeight(BASEOBJ _target) { local int _AAPenalty,_numAA,_range,_targetWeight; local int _targetType; local STRUCTURE _structTarget; if(_target == NULLOBJECT) { return 0; } if(_target.type != OBJ_STRUCTURE) { return 0; } _structTarget = objToStructure(_target); _targetWeight = 0; _AAPenalty = 9; //penalty per aa defense _range = AA_THREAT_RANGE; // count enemy AA _numAA = numEnemyAAInRange(_structTarget.x, _structTarget.y, _range); // find tyrget type from stats _targetType = 0; while(_targetType < numVtolTargets) { if(_structTarget.stat == vtolTarget[_targetType]) { _targetWeight = vtolTargetWeight[_targetType] - (_numAA * _AAPenalty); _targetType = numVtolTargets; //exit loop } _targetType++; } // incomplete structures get lower weight if(!structureComplete(_structTarget)) { _targetWeight = _targetWeight / 10; } return _targetWeight; } function int numEnemyAAInRange(int _x, int _y, int _range) { local int _enemy,_numAA; _numAA = 0; _enemy = 0; while(_enemy < MAX_PLAYERS) { if(!friendlyPlayer(_enemy)) { _numAA = _numAA + numAAinRange(_enemy, me, _x, _y, _range); } _enemy++; } return _numAA; } // see if a particular target is already assigned to one of the VTOL attack groups function bool vtolTargetAssigned(BASEOBJ _target) { local int _groupIndex; if(_target == NULLOBJECT) { return FALSE; } _groupIndex = 0; while(_groupIndex < numVtolAttackGroups) { if(_target == vtolGrAttackObj[_groupIndex]) { return TRUE; } _groupIndex++; } return FALSE; } ///////////////////////////////////////////////////////////////////// // watch for incoming vtols event vtolDefend(vtolDefendTr) { local int _numBuilders,_maxBuilders; if(baseobj != NULLOBJECT) { if(baseobj.type == OBJ_DROID) { if(isVtol(objToDroid(baseobj))) { _numBuilders = 0; _maxBuilders = 2; // build defenses. initIterateGroup(buildGroup); // find idle droids in build group. droid = iterateGroup(buildGroup); while( droid != NULLOBJECT) { if( (structure != NULLOBJECT) and (droid.order != DORDER_BUILD) ) { buildX = structure.x; buildY = structure.y; // if ! vtol defense already built... //find best defense we can build. count = 0; count2 = -1; while( count < 5) { if(isStructureAvailable(vtolDefStruct[count],me)) { count2 = count; } count = count + 1; } if(count2 != (-1) ) { boolResult = pickDroidStructLocation(droid, vtolDefStruct[count2], ref buildX, ref buildY, me, 1); if (boolResult == TRUE and (_numBuilders < _maxBuilders)) // build a vtol defense near the attacked struct... { orderDroidStatsLoc(droid, DORDER_BUILD,vtolDefStruct[count2],buildX,buildY); _numBuilders++; } } } droid = iterateGroup(buildGroup); } } } } } ///////////////////////////////////////////////////////////////////// event vtolEnabler(vtolEnablerTr) { if( skVtolEnableCheck(me) ) // check to see if we have vtol technologies. { setEventTrigger(vtolEnabler,inactive); // turn off this event. setEventTrigger(vtolStructs,vtolStructsTr); // activate other vtol functions.. setEventTrigger(buildVtols, buildVtolsTr); setEventTrigger(vtolAttack, vtolAttackTr); dbg("----I CAN USE VTOLS----", me); } } ///////////////////////////////////////////////////////////////////// // HouseKeeping function void shutDownAI() { bRunning = false; setEventTrigger(basedetails, inactive); setEventTrigger(buildDerrick, inactive); setEventTrigger(buildOilDefenseOrRetreat, inactive); setEventTrigger(incendry, inactive); setEventTrigger(buildPowerGenerators, inactive); setEventTrigger(buildBase, inactive); setEventTrigger(buildExpand,inactive); setEventTrigger(upgradeStructures,inactive); setEventTrigger(finishStructs, inactive); setEventTrigger(newfortify, inactive); setEventTrigger(droidBuiltAssign, inactive); setEventTrigger(droidBuilt, inactive); setEventTrigger(structBuilt,inactive); setEventTrigger(droidDestroyed,inactive); setEventTrigger(conDroids,inactive); setEventTrigger(repairDroids,inactive); setEventTrigger(factoryEvent, inactive); setEventTrigger(cyborgFactoryEvent, inactive); setEventTrigger(chooseScoutArea, inactive); setEventTrigger(expandScoutArea, inactive); setEventTrigger(scoutMain, inactive); setEventTrigger(newObjectReport, inactive); setEventTrigger(takeover, inactive); setEventTrigger(takeoverDefend, inactive); setEventTrigger(useLassat, inactive); setEventTrigger(findEnemy, inactive); setEventTrigger(attackStuff, inactive); setEventTrigger(defendWatch, inactive); setEventTrigger(defendReturn, inactive); setEventTrigger(doResearch, inactive); setEventTrigger(formAllianceEvent, inactive); setEventTrigger(breakAllianceEvent, inactive); setEventTrigger(formHumanAlliances, inactive); setEventTrigger(consolidateEvent, inactive); setEventTrigger(vtolStructs,inactive); setEventTrigger(buildVtols,inactive); setEventTrigger(vtolAttack,inactive); setEventTrigger(vtolDefend,inactive); setEventTrigger(vtolEnabler,inactive); setEventTrigger(beaconEv, inactive); setEventTrigger(multiMsgEv, inactive); setEventTrigger(manageAllyHelp, inactive); setEventTrigger(everySecEv, inactive); setEventTrigger(watchBaseThreat, inactive); setEventTrigger(manageDefendLocationEv, inactive); setEventTrigger(structureDestroyed,inactive); setEventTrigger(rebuildStructureEv,inactive); setEventTrigger(startLevel, inactive); setEventTrigger(arrived, inactive); setEventTrigger(checkResearch, inactive); } function void reassignAI() { bRunning = true; setEventTrigger(basedetails,basedetailsTr); setEventTrigger(buildDerrick,buildDerrickTr); setEventTrigger(buildOilDefenseOrRetreat,buildOilDefenseOrRetreatTr); setEventTrigger(incendry,incendryTr); setEventTrigger(buildPowerGenerators,buildPowerGeneratorsTr); setEventTrigger(buildBase,buildBaseTr ); setEventTrigger(buildExpand,buildExpandTr ); setEventTrigger(upgradeStructures,upgradeStructuresTr ); setEventTrigger(finishStructs,finishStructsTr ); setEventTrigger(newfortify,fortifyTr ); setEventTrigger(droidBuiltAssign,droidBuiltTr); setEventTrigger(droidBuilt,droidBuiltTr); setEventTrigger(droidDestroyed,droidDestroyedTr); setEventTrigger(conDroids,conDroidsTr); setEventTrigger(repairDroids,repairDroidsTr); setEventTrigger(factoryEvent,factoryEventTr); setEventTrigger(cyborgFactoryEvent,cyborgFactoryEventTr); setEventTrigger(chooseScoutArea,chooseScoutAreaTr); setEventTrigger(expandScoutArea,expandScoutAreaTr); setEventTrigger(scoutMain,scoutMainTr); setEventTrigger(newObjectReport,newObjectReportTr); setEventTrigger(takeover,takeoverTr); setEventTrigger(useLassat,useLassatTr); setEventTrigger(findEnemy,attackStuffTr); setEventTrigger(attackStuff,attackStuffTr); setEventTrigger(doAllOutAttack,allOutAttackTr); setEventTrigger(defendWatch,defendWatchTr); setEventTrigger(defendReturn,defendReturnTr); setEventTrigger(doResearch,doResearchTr); setEventTrigger(formAllianceEvent,formAllianceEventTr); setEventTrigger(breakAllianceEvent,breakAllianceEventTr); setEventTrigger(consolidateEvent,consolidateEventTr); setEventTrigger(vtolStructs,inactive); setEventTrigger(buildVtols,inactive); //setEventTrigger(vtolAttack,inactive); setEventTrigger(vtolAttack, vtolAttackTr); setEventTrigger(vtolDefend,vtolDefendTr); setEventTrigger(vtolEnabler,vtolEnablerTr); setEventTrigger(formHumanAlliances,humanAllianceTr); setEventTrigger(multiMsgEv, multiMsgTr); setEventTrigger(beaconEv, beaconTr); setEventTrigger(watchBaseThreat, watchBaseThreatTr); setEventTrigger(manageAllyHelp, manageAllyHelpTr); setEventTrigger(everySecEv, everySec); //setEventTrigger(manageDefendLocationEv, manageDefendLocationTr); setEventTrigger(structBuilt, structBuiltTr); setEventTrigger(structureDestroyed, structureDestroyedTr); setEventTrigger(rebuildStructureEv, rebuildStructureTr); setEventTrigger(startLevel, startLevelTr); setEventTrigger(arrived, reachedTr); setEventTrigger(checkResearch, checkResearchTr); } /* Returns true if we just received a beacon from a certain player */ function bool haveBeacon(int _player) { if((tBeacon[_player] > 0) and (not beaconTimeout(_player))) { return TRUE; //have beacon for this player } return FALSE; } /* See if last beacon was placed long ago */ function bool beaconTimeout(int _player) { if((tBeacon[_player] > 0) and ((tBeacon[_player] + BEACON_TIMEOUT) < (gameTime / 10))) //not too long ago { return TRUE; //this beacon is still 'fresh' } return FALSE; } /* Deal with beacons */ event beaconEv(beaconTr) { local int _players; local string _processedString; if(_DEBUG) debug(me & ") beaconEv: from " & sender); ASSERT(sender >= 0 and sender < MAX_PLAYERS, "beaconEv: sender out of bounds: " & sender , me); beaconX[sender] = x; beaconY[sender] = y; tBeacon[sender] = gameTime / 10; processCommand(message, sender, TRUE); } /* Deal with a chat message */ event multiMsgEv(multiMsgTr) { if(_DEBUG) debug(me & ") multiMsgEv: from " & sender); if(not allianceExistsBetween(me, sender)){ exit; } if(sender == me){ exit; } processCommand(message, sender, FALSE); } /* Process multiplayer messages */ function void processCommand(string _message, int _sender, bool _bBlipMessage) { local int _numMsgs,_curMsg,_addressedPlayers,_x,_y; local string _msg,_processedString; /* Extract semantic information */ _curMsg = 0; _numMsgs = processChatMsg(_message); debug(me & ") processCommand: '" & _message & "' from " & _sender); dbg("processCommand: '" & _message & "' from " & _sender, me); dbg("got " & _numMsgs & " commands", me); /* Process all messages */ while(_curMsg < _numMsgs) { if(chatCmdIsPlayerAddressed(_curMsg, me)) { dbg("i'm addressed", me); _msg = getChatCmdDescription(_curMsg); /* Someone requested help */ if(_msg == R_REQUEST_HELP) { dbg("'help' command", me); if(haveBeacon(_sender)) { dbg("got beacon", me); _x = beaconX[_sender]; _y = beaconY[_sender]; if(attemptToHelp(_sender, _x, _y)) { messagePlayer(ALL_ALLIES, m_affirmative(), MAX_PROBABILITY); } } else { /* Ask player to drop a beacon so we would know where to help */ _addressedPlayers = setBit(0, _sender, TRUE); messagePlayerAddressed(ALL_ALLIES, _addressedPlayers, R_REQUEST_BEACON); } } /* Someone requested a beacon from us - * did we request help and our beacon timed out?? */ else if(_msg == M_REQUEST_BEACON) { /* If our base is really in trouble drop a beacon for the requester again */ if(baseInTrouble()){ dropBeacon(getPlayerName(me), _sender, me, baseX, baseY, 0); } } else if(_msg == R_REPORT_SAFETY) { dbg("helping " & lastHelpPlayer, me); /* Make sure we were helping him */ if(helpingAlly() and (lastHelpPlayer == _sender)) { stopHelpingAlly(); messagePlayer(ALL_ALLIES, m_affirmative(), MAX_PROBABILITY); } else if(defendingOwnBase()) //if we are in trouble re-request help { requestHelp(baseX, baseY); } } else { dbg("unknown message", me); } } else { dbg("i'm not addressed", me); } _curMsg++; } } function bool attemptToHelp(int _playerToHelp, int _x, int _y) { local bool _bHelpingMyself; if(_playerToHelp < 0 or _playerToHelp >= MAX_PLAYERS){ return FALSE; } if(_x <= 0 or _y <= 0){ return FALSE; } dbg("attemptToHelp - checking", me); _bHelpingMyself = (_playerToHelp == me); /* Can only help allies and myself */ if(not friendlyPlayer(_playerToHelp)){ return FALSE; } if(_bHelpingMyself or !helpingAlly() or (lastHelpPlayer == _playerToHelp) ) //if not helping any other ally or it's me who needs help { dbg("not busy helping", me); if(haveHelpers() or _DEBUG) { dbg("got attackers", me); //if(allyBaseAtLoc(_playerToHelp, _x, _y)) //is he just trying to misuse us? //{ helpPlayer(_playerToHelp, _x, _y); return TRUE; //} //else //{ // dbg("ally needs no help", me); // messagePlayer(ALL_ALLIES, M_ANNOYED, MAX_PROBABILITY / 2); //} } else { messagePlayer(ALL_ALLIES, M_HELP_NO_UNITS, MAX_PROBABILITY); } } else if((lastHelpPlayer >= 0) and (lastHelpPlayer < MAX_PLAYERS)) { if(!_bHelpingMyself){ messagePlayer(ALL_ALLIES, "helping " & getPlayerName(lastHelpPlayer) & " already", MAX_PROBABILITY); } } return FALSE; } /* Start helping player */ function void helpPlayer(int _playerToHelp, int _helpX, int _helpY) { local int _tTravelTime; dbg("helping " & _playerToHelp, me); if(_DEBUG) debug(me & ") helpPlayer: '" & _playerToHelp); /* Move scoutes to attackers */ groupAddGroup(attackGroup, scoutGroup); //Calculate travel time, assume ~ 150 tiles in 4 minutes if(attackGroup.members == 0){ _tTravelTime = (int)((float)(distBetweenTwoPoints(baseX, baseY, _helpX, _helpY) / 128 ) * 1.7); }else{ _tTravelTime = (int)((float)(distBetweenTwoPoints(attackGroup.x, attackGroup.y, _helpX, _helpY) / 128 ) * 1.7); } tHelp = gameTime / 10; tHelpTimeout = (gameTime / 10) + BASE_DEFEND_DURATION + _tTravelTime; lastHelpPlayer = _playerToHelp; helpX = _helpX; helpY = _helpY; /* Scouts and attackers go to help */ defendLocation(_helpX, _helpY, tHelpTimeout, (_playerToHelp == me)); } /* Returns a random affirmative responce */ function string m_affirmative() { local int _rnd; _rnd = random(4); if(_rnd == 3) { return M_AFFIRMATIVE_ROGER; } return M_AFFIRMATIVE_OK; } /* See if there are any base structures belonging to ally at a certain location */ function bool allyBaseAtLoc(int _ally, int _x, int _y) { local int _structIndex; if(_x <= 0 or _y <= 0){ return FALSE; } if(_ally < 0 or _ally >= MAX_PLAYERS){ return FALSE; } _structIndex = 0; while(_structIndex < numBaseStruct) { if(numStructsByStatInRange(baseStruct[_structIndex], _x, _y, (7 * 128), me, _ally) > 0 ) { return TRUE; } _structIndex++; } return FALSE; } event manageAllyHelp(manageAllyHelpTr) { if(helpingAlly()) { if(canStopHelpingAlly()) { stopHelpingAlly(); } } } event everySecEv(everySec) { /* Check if we were helping long enough */ if(helpingAlly()) { if(helpAllyTimeout()) { stopHelpingAlly(); } } if(defendingLocation()) { if(defendLocationTimeout()) { stopDefendingLocation(); } } } /* Do we have any units we can send to help ally ? */ function bool haveHelpers() { if(attackGroup.members == 0){ return FALSE; } return TRUE; } function bool helpingAlly() { if(lastHelpPlayer >= 0){ return TRUE; } return FALSE; } /* Returns true if we were helping long enough */ function bool helpAllyTimeout() { if(tHelpTimeout < (gameTime / 10) ){ return TRUE; } return FALSE; } function bool canStopHelpingAlly() { if(lastHelpPlayer < 0) { ASSERT(FALSE, "canStopHelpingAlly: lastHelpPlayer < 0", me); return TRUE; } /* Were helping long enough or someone's backstabbing */ if(!friendlyPlayer(lastHelpPlayer)){ return TRUE; } /* Nothing to defend anymore */ //if(!allyBaseAtLoc(lastHelpPlayer, helpX, helpY)){ // return TRUE; //} return FALSE; } function void stopHelpingAlly() { dbg("stopped helping", me); tHelp = -1; tHelpTimeout = -1; lastHelpPlayer = -1; helpX = -1; helpY = -1; stopDefendingLocation(); } /* Send a multiplayer message to an ally */ function void messagePlayer(int _playerToMessage, string _message, int _probability) { local int _player; ASSERT(_playerToMessage >= -1 && _playerToMessage < MAX_PLAYERS, "messagePlayer: player out of bounds: " & _playerToMessage, me); // throw the dice if( random(MAX_PROBABILITY) >= _probability ){ return; } _player = 0; if(_playerToMessage == ALL_ALLIES) //everyone { while(_player < MAX_PLAYERS) { /* Send message (allies only)) */ if(allianceExistsBetween(me, _player)) { msg(_message, me, _player); } _player++; } } else //a certain player { /* Send message (allies only)) */ if(allianceExistsBetween(me, _playerToMessage)) { msg(_message, me, _playerToMessage); } } } function int numBitsSet(int _integer) { local int _position,_result; _position = 0; _result = 0; while(_position < 8) { if(getBit(_integer, _position)) { _result++; } _position++; } return _result; } /* Send a multiplayer message, addressing some player(s) */ function void messagePlayerAddressed(int _playerToMessage, int _playersToAddress, string _message) { local int _player,_totalAddressed,_curAddressed; local string _adrMessage; _totalAddressed = numBitsSet(_playersToAddress); ASSERT(_totalAddressed > 0, "messagePlayerAddressed: no players addressed", me); _adrMessage = " "; _player = 0; _curAddressed = 0; while(_player < MAX_PLAYERS) { if(getBit(_playersToAddress, _player)) { _curAddressed++; _adrMessage = _adrMessage & getPlayerName(_player); //if(_totalAddressed == 1){ //one only // _adrMessage = getPlayerName(_player); //}else if(_totalAddressed > 1) { if(_curAddressed == _totalAddressed){ //end _adrMessage = _adrMessage & " and " & getPlayerName(_player); }else{ _adrMessage = _adrMessage & ", " & getPlayerName(_player); } } } _player++; } _message = _adrMessage & " " & _message; //Now send the message to all players addressed messagePlayer(_playerToMessage, _message, MAX_PROBABILITY); } /* Returns true if we can see our allies on the map */ function bool canSeeAllies() { local STRUCTURE _uplink; /* Can see allies when team mode is on */ if(multiPlayerAlliancesType == ALLIANCES_TEAMS) { return TRUE; } /* Can see whole map if we have uplink */ _uplink = getStructure(uplink, me); if(_uplink != NULLOBJECT) { /* Make sure finished building */ if(structureComplete(_uplink)) { return TRUE; } } return FALSE; } function bool defendingOwnBase() { if(helpingAlly() && lastHelpPlayer == me){ return TRUE; } return FALSE; } /* Call for help when our base is in danger */ event watchBaseThreat(watchBaseThreatTr) { /* See if we can stop defending */ if(defendingOwnBase()) { if(numEnemiesInBase(FALSE) == 0) { stopHelpingAlly(); //stop defending our own base /* Let allies know we don't need their help anymore */ messagePlayer(ALL_ALLIES, R_REPORT_SAFETY, MAX_PROBABILITY); exit; } } /* See if our base is in trouble and we need help */ if(baseInTrouble()) { if(!defendingOwnBase()) //make sure not already defending the base { if(_DEBUG) debug(me & ") watchBaseThreat: base in trouble"); dbg("watchBaseThreat: base in trouble", me); /* Bring our forces back if needed */ if(helpingAlly()) { stopHelpingAlly(); } /* Defend my own base */ helpPlayer(me, baseX, baseY); } /* Request help once in a while */ requestHelp(baseX, baseY); exit; } } function int numAlliesInBase(bool _bVtols) { local int _numAllies; _numAllies = numFriendlyWeapDroidsInRange(me, baseX, baseY, W_BASE_THREAT_RANGE, _bVtols); _numAllies = _numAllies + numFriendlyWeapStructsInRange(me, baseX, baseY, W_BASE_THREAT_RANGE, true) / 3; return _numAllies; } function int numEnemiesInBase(bool _bVtols) { local int _numEnemies; _numEnemies = numEnemyWeapDroidsInRange(me, baseX, baseY, W_BASE_THREAT_RANGE, _bVtols); _numEnemies = _numEnemies + numEnemyWeapStructsInRange(me, baseX, baseY, W_BASE_THREAT_RANGE, true) / 4; return _numEnemies; } /* Returns true if our base is in trouble */ function bool baseInTrouble() { local int _enemyForce,_friendlyForce; _friendlyForce = numAlliesInBase(FALSE); _enemyForce = numEnemiesInBase(FALSE); /* See if we are in trouble */ if((_enemyForce > 0) && (_enemyForce >= _friendlyForce)){ dbg("baseInTrouble: " & _enemyForce & " >= " & _friendlyForce, me); return TRUE; } return FALSE; } /* Request help from allies */ function void requestHelp(int _helpX, int _helpY) { /* Don't do this too frequently */ if(tLastHelpRequest + HELP_REQUEST_INTERVAL > (gameTime / 10) ){ return; } doRequestHelp(_helpX, _helpY); } function void doRequestHelp(int _helpX, int _helpY) { local int _ally; /* Remember when we requested help last time */ tLastHelpRequest = gameTime / 10; /* Drop beacon for all allies so they would know where to help */ _ally = 0; while(_ally < MAX_PLAYERS) { if(allianceExistsBetween(me, _ally)){ if(_DEBUG) debug(me & ") requestHelp: " & _ally); dropBeacon(getPlayerName(me), _ally, me, _helpX, _helpY, 0); } _ally++; } /* Now send message with help request */ messagePlayer(ALL_ALLIES, M_REQUEST_HELP, MAX_PROBABILITY); } function void defendLocation(int _defendX, int _defendY, int _tDefendTimeout, bool _bMove) { local int defendRadius; defendRadius = 15 * TILE; dbg("starting defending for " & _tDefendTimeout - (gameTime / 10) & " secs, with defend radius " & defendRadius, me); defendX = _defendX; defendY = _defendY; tDefendStart = gameTime / 10; /* Should already include travel time */ tDefendTimeout = _tDefendTimeout; /* See if we have to move or scout */ defendMoveType = DORDER_SCOUT; if(_bMove){ defendMoveType = DORDER_MOVE; } /* Send attackers */ if(attackGroup.members > 0) { if(distBetweenTwoPoints(attackGroup.x, attackGroup.y, _defendX, _defendY) > defendRadius) { orderGroupLoc(attackGroup, defendMoveType, _defendX, _defendY); } } setEventTrigger(manageDefendLocationEv, manageDefendLocationTr); } function void stopDefendingLocation() { dbg("stopped defending location", me); defendX = -1; defendY = -1; tDefendStart = -1; tDefendTimeout = -1; defendMoveType = -1; setEventTrigger(manageDefendLocationEv, inactive); orderGroupLoc(attackGroup, DORDER_SCOUT,baseX,baseY); } function bool defendingLocation() { if(defendX > 0 and defendY > 0){ return TRUE; } return FALSE; } event manageDefendLocationEv(inactive) { local int defendRadius; local DROID _droid; if (not defendingLocation()) { exit; } defendRadius = 15 * TILE; dbg("manageDefendLocationEv", me); ASSERT(defendMoveType == DORDER_MOVE || defendMoveType == DORDER_SCOUT, "manageDefendLocationEv: wrong move order:" & defendMoveType, me); ASSERT(defendX > 0 && defendY > 0, "manageDefendLocationEv: x/y coordinates:" & defendX & "/" & defendY, me); /* Collect attackers */ initIterateGroup(attackGroup); _droid = iterateGroup(attackGroup); while(_droid != NULLOBJECT) { if(distBetweenTwoPoints(_droid.x,_droid.y,defendX,defendY) > defendRadius) //too far from defend location { if(distBetweenTwoPoints(_droid.orderx,_droid.ordery,defendX,defendY) > defendRadius) //not already on its way to the defend location { orderDroidLoc(_droid, defendMoveType, defendX, defendY); } } _droid = iterateGroup(attackGroup); } } function bool defendLocationTimeout() { if(tDefendTimeout < (gameTime / 10) ){ return TRUE; } return FALSE; } /* Returns true if player in question is my ally or if it's me */ function bool friendlyPlayer(int _playerToCheck) { if(allianceExistsBetween(_playerToCheck, me) or (_playerToCheck == me)){ return TRUE; } return FALSE; } function bool insideBase(int _x, int _y) { if(_x < minx){ return FALSE; } if(_x > maxx){ return FALSE; } if(_y < miny){ return FALSE; } if(_y > maxy){ return FALSE; } return TRUE; } event watchMenu(everySec) { if(_DEBUG) { if(vtolGrAttackObj[0] == NULLOBJECT){ setDebugMenuEntry("0 - " & vtolAttackGr[0].members, 0); }else{ setDebugMenuEntry("0 " & vtolAttackGr[0].members & " - " & (vtolGrAttackObj[0].x / TILE) & "-" & (vtolGrAttackObj[0].y / TILE), 0); } if(vtolGrAttackObj[1] == NULLOBJECT){ setDebugMenuEntry("1 - " & vtolAttackGr[1].members, 1); }else{ setDebugMenuEntry("1 " & vtolAttackGr[1].members & " - " & (vtolGrAttackObj[1].x / TILE) & "-" & (vtolGrAttackObj[1].y / TILE), 1); } if(vtolGrAttackObj[2] == NULLOBJECT){ setDebugMenuEntry("2 - " & vtolAttackGr[2].members, 2); }else{ setDebugMenuEntry("2 " & vtolAttackGr[2].members & " - " & (vtolGrAttackObj[2].x / TILE) & "-" & (vtolGrAttackObj[2].y / TILE), 2); } if(vtolGrAttackObj[3] == NULLOBJECT){ setDebugMenuEntry("3 - " & vtolAttackGr[3].members, 3); }else{ setDebugMenuEntry("3 " & vtolAttackGr[3].members & " - " & (vtolGrAttackObj[3].x / TILE) & "-" & (vtolGrAttackObj[3].y / TILE), 3); } if(vtolGrAttackObj[4] == NULLOBJECT){ setDebugMenuEntry("4 - " & vtolAttackGr[4].members, 4); }else{ setDebugMenuEntry("4 " & vtolAttackGr[4].members & " - " & (vtolGrAttackObj[4].x / TILE) & "-" & (vtolGrAttackObj[4].y / TILE), 4); } if(vtolGrAttackObj[5] == NULLOBJECT){ setDebugMenuEntry("5 - " & vtolAttackGr[5].members, 5); }else{ setDebugMenuEntry("5 " & vtolAttackGr[5].members & " - " & (vtolGrAttackObj[5].x / TILE) & "-" & (vtolGrAttackObj[5].y / TILE), 5); } /* setDebugMenuEntry("total " & countRebuildStruct, 0); setDebugMenuEntry("x1=" & rebuildStructX[0], 1); setDebugMenuEntry("y1=" & rebuildStructY[0], 2); setDebugMenuEntry("x2=" & rebuildStructX[1], 3); setDebugMenuEntry("y2=" & rebuildStructY[1], 4); setDebugMenuEntry("x3=" & rebuildStructX[2], 5); setDebugMenuEntry("y3=" & rebuildStructY[2], 6); setDebugMenuEntry("x4=" & rebuildStructX[3], 7); setDebugMenuEntry("y4=" & rebuildStructY[3], 8);*/ } } //--------------------------------------------------------------- //Returns how many droids are already on the way to build the //same structure on the same spot (like helpbuild) //--------------------------------------------------------------- function int numBuildSameBuilding(STRUCTURESTAT _checkStat, int _x, int _y) { local int _numSameBuilding; local DROID _truck; _numSameBuilding = 0; initIterateGroup(buildGroup); _truck = iterateGroup(buildGroup); while(_truck != NULLOBJECT) { if((_truck.order == DORDER_BUILD) or (_truck.order == DORDER_HELPBUILD) or (_truck.order == DORDER_LINEBUILD)) { if((_checkStat == NULLSTRUCTURESTAT) or (_truck.stat == _checkStat)) //Same struct type { //Within some range if((_x < 0) or (distBetweenTwoPoints(_x, _y, _truck.orderx , _truck.ordery) <= TILE)) { _numSameBuilding++; } } } _truck = iterateGroup(buildGroup); } return _numSameBuilding; } // returns number of droids in a certain group with the same order function int numGroupSameOrder(GROUP _group, int _orderIndex) { local int _numDroids; local DROID _droid; _numDroids = 0; initIterateGroup(_group); _droid = iterateGroup(_group); while(_droid != NULLOBJECT) { if(_droid.order == _orderIndex) //right order type { _numDroids++; } _droid = iterateGroup(_group); } return _numDroids; } // Remember certain destroyed structures so we can rebuild them later event structureDestroyed(structureDestroyedTr) { local int _count; // add certain structures to the rebuild list _count = 0; while(_count < numRebuildStat[curTech]) { if(structure.stat == rebuildStat[curTech][_count]) { if(countRebuildStruct < MAX_REBUILD_STRUCT) { rebuildStructX[countRebuildStruct] = structure.x; rebuildStructY[countRebuildStruct] = structure.y; rebuildStructStat[countRebuildStruct] = structure.stat; countRebuildStruct++; dbg("remembered structure (" & countRebuildStruct & ") - " & structure.x & "/" & structure.y, me); exit; } } _count++; } } // Rebuild structures that were destroyed event rebuildStructureEv(rebuildStructureTr) { rebuildStructures(); } function void rebuildStructures() { local int _count,_threatRange,_x,_y; local DROID _truck; local STRUCTURESTAT _stat; _threatRange = (TILE * 8); _count = 0; while(_count < countRebuildStruct) { if(!threatInRange(me, rebuildStructX[_count], rebuildStructY[_count], _threatRange, FALSE)) { if(getTileStructure(_x / TILE, _y / TILE) == NULLOBJECT) { _stat = rebuildStructStat[_count]; _x = rebuildStructX[_count]; _y = rebuildStructY[_count]; if (isStructureAvailable(_stat, me)) { _truck = closestIdleTruck(_x, _y); if (_truck != NULLOBJECT) { if (numBuildSameBuilding(_stat, _x, _y) == 0) //make sure no one is building already { buildOnExactLocation(_truck, _x, _y, _stat); } } } } } _count++; } } function void buildOnExactLocation(DROID _truck, int _x, int _y, STRUCTURESTAT _stat) { local int _newX,_newY; if(_truck == NULLOBJECT) { return; } _newX = _x; _newY = _y; if (pickDroidStructLocation(_truck, _stat, ref _newX, ref _newY, me, -1)) { dbg("trying to rebuild on (" & _newX & "/" & _newY & ")", me); if ((_x != _newX) or (_y != _newY)) { return; } orderDroidStatsLoc(_truck, DORDER_BUILD, _stat, _x, _y); //dbg("rebuilding structure after!! (" & _x & "/" & _y & ")", me); } } // Get idle truck closest to some location function DROID closestIdleTruck(int _x, int _y) { local DROID _closestTruck, _tempTruck; local int _closestDist, _tempDist; _closestTruck = NULLOBJECT; _closestDist = 99999; initIterateGroup(buildGroup); _tempTruck = iterateGroup(buildGroup); while(_tempTruck != NULLOBJECT) { if((_tempTruck.order == DORDER_NONE) or (_tempTruck.order == DORDER_RTB)) { _tempDist = distBetweenTwoPoints(_x, _y, _tempTruck.x, _tempTruck.y); if(_tempDist < _closestDist) { _closestDist = _tempDist; _closestTruck = _tempTruck; } } _tempTruck = iterateGroup(buildGroup); } return _closestTruck; } event consoleEv(consoleTr) { //turn on 'autogame' if(message == "autogame on" && (sender == me)) { if(debugModeEnabled()) { if(myResponsibility(me)) { if(not bRunning) //make sure current machine is responsible for this AI and it's not already active { console(getPlayerName(me) & " is active"); reassignAI(); setEventTrigger(startLevel, chainloadTr); } } } } //turn off 'autogames' if(message == "autogame off" && debugModeEnabled() && (sender == me)) { if(bRunning) //make sure this AI is active { console(getPlayerName(me) & " is deactivated"); shutDownAI(); } } if(message == "aidebug on") { console(getPlayerName(me) & " ai debug is on"); _DEBUG = TRUE; dbgMsgOn(me, _DEBUG); } else if(message == "aidebug off") { console(getPlayerName(me) & " ai debug is off"); _DEBUG = FALSE; dbgMsgOn(me, _DEBUG); } }
変更されたテキスト
ファイルを開く
///////////////////////////////////////////////////////////////////// // general ai for skirmish game ///////////////////////////////////////////////////////////////////// // Warzone2100, Pumpkin Studios, // alex lee.98/99. // ///////////////////////////////////////////////////////////////////// //Tile in world units #define TILE 128 #define NONE (-1) // These are final rules of the lexical parser #define R_REQUEST_HELP "help me" #define R_REQUEST_BEACON "drop a beacon" #define R_REPORT_SAFETY "i'm ok" #define R_REQUEST_ALLY "ally me" // These are our own messages - lexical parser should be able to handle them #define M_REQUEST_HELP "help me!!" #define M_REQUEST_BEACON "drop a beacon" #define M_AFFIRMATIVE_OK "ok" #define M_AFFIRMATIVE_ROGER "roger" #define M_ANNOYED "bug off" #define M_HELPERS_KILLED "that was all I had.." #define M_HELP_NO_UNITS "I don't have anything" #define MAX_PROBABILITY 100 // Base threat range in world units #define W_BASE_THREAT_RANGE ((17 + (mapWidth + mapHeight) / 2 / 35) * TILE) #define ALL_ALLIES -1 #define BASE_DEFEND_DURATION (3 * 60) // Delay before we repeat our request, in seconds #define HELP_REQUEST_INTERVAL (3 * 60) //in secs #define BEACON_TIMEOUT 30 #define MAX_DROIDS 150 //range for trucks to look for more oil #define MORE_OIL_RANGE (10 * TILE) //don't try to build on oil if there's threat within this range #define OIL_THREAT_RANGE (9 * TILE) #define MAX_TRUCKS 15 #define MIN_TRUCKS 12 //Enter power saving mode when lower than this #define LOW_POWER 250 //Target type values #define NO_TARGET_VALUE 0 #define DROID_TARGET_VALUE 1 #define OTHER_TARGET_VALUE 2 #define DEFENSE_TARGET_VALUE 3 #define RESEARCH_TARGET_VALUE 4 #define HQ_TARGET_VALUE 5 #define OIL_TARGET_VALUE 6 #define FACTORY_TARGET_VALUE 7 #define UNLIMITED (-1) #define AA_THREAT_RANGE (TILE * 12) #define MAX_DEFENDERS_RADIUS (TILE * 40) #define MAX_VTOL_DEFEND_RADIUS (TILE * 25) // AI will remember max this number of structures #define MAX_REBUILD_STRUCT 100 //Total number of technology branches #define TECHS 2 //How many best templates to choose from when deciding what template to build #define MAX_RANDOM_TEMPLATES 6 private int me; // player for this instance. public int tileExpand; // rate of exploration public int numScouts[TECHS],maxScouts[TECHS]; // aim for... public int numDefenders[TECHS],maxDefenders[TECHS]; public int numAttackers[TECHS],maxAttackers[TECHS]; public int numCyborgs[TECHS],maxCyborgs[TECHS]; public int branchDefault,branchVTOL,techCount[TECHS],maxVtolFacs[TECHS],maxIdleRes[TECHS], maxVTOLs[TECHS],numVtolTargets,vtolTargetWeight[10],numRebuildStat[TECHS]; public RESEARCHSTAT tech[TECHS][30]; //technology for different research branches public STRUCTURESTAT vtolTarget[10],rebuildStat[TECHS][2]; // structures private int baseX,baseY,minx,miny,maxx,maxy; public int numStructs,numIncendrys,numDefStructs,numExtraStructs[TECHS],numWallWeaps,numBaseStruct,numLightCyborgs,numFundamental; private STRUCTURESTAT structChoice[5]; public STRUCTURESTAT incendrys[10],structs[13],defStructs[26],extraStructs[TECHS][6],wallWeaps[11]; public STRUCTURESTAT sensorTower,wall,cornerWall,resLab,powGen,playerHQ,lassat,factory,derrick,cybFactory, vtolDefStruct[9],vtolPad,vtolFactory,uplink,baseStruct[8]; public STRUCTURESTAT powModule,facModule,resModule,vtolModule; public int extraStruct; // unit templates public int numTemplates[TECHS]; public TEMPLATE tmpl[TECHS][70]; private TEMPLATE tmplChoice[67]; public TEMPLATE cybTempl[7],superCyb[21],cybMechanic,cybEngineer,hovertruck; public TEMPLATE vtols[20]; public int numVtolTemplates; public TEMPLATE sense[8]; public int numSenseTemplates; public TEMPLATE constructor,repair[7]; public int numRepairUnits; public int numSensorUnits; public int numRepairTemplates; //defend private GROUP defendGroup; private bool defendbusy; private BASEOBJ defendObj; public RESEARCHSTAT nexusDefence; private RESEARCHSTAT research; //build private GROUP buildGroup; private int buildX,buildY,buildX2,buildY2; public FEATURESTAT oilRes; // scout private GROUP scoutGroup; private int scoutX,scoutY; private int scoutTLX,scoutTLY,scoutW,scoutH; // attack private GROUP attackGroup; private BASEOBJ attackObj,allOutAttack,vtolGrAttackObj[39]; // vtols private GROUP vtolDefendGr,vtolAttackGr[10]; // generic private STRUCTURE structure,structure2,rebuildObj[100]; private DROID droid; private FEATURE feature; private BASEOBJ baseobj,baseobj2; private int count,count2,result,result2,tempx,tempy; private bool boolResult,boolResult2; private bool powerSave,_DEBUG,bRunning; // Hopefully this will be at least as large as MAX_PLAYERS... Why can't I just use MAX_PLAYERS as the array size?! // P.S. And why can't I put a comment on the same line as a #define??!! Gah, who cares if the lua2 branch works, lets switch to it, anyway. #define MAX_PLAYERS_HACK 17 private int allianceTime[MAX_PLAYERS_HACK]; private int sender,x,y,beaconX[8],beaconY[8],tBeacon[8], tLastHelpRequest,lastHelpPlayer,tHelp,tHelpTimeout,helpX,helpY; private string message; private int defendX,defendY,__defendRadiusUnused,tDefendStart,tDefendTimeout, defendMoveType,baseRange,curTech,numVtolAttackGroups,numAttackVtols, numDefendVtols,rebuildStructX[MAX_REBUILD_STRUCT],rebuildStructY[MAX_REBUILD_STRUCT],countRebuildStruct; private STRUCTURESTAT rebuildStructStat[MAX_REBUILD_STRUCT]; private STRUCTURESTAT fundamentalBeingBuilt; private int order; // callback global ///////////////////////////////////////////////////////////////////// // triggers. #region triggers trigger reachedTr (CALL_DROID_REACH_LOCATION, me, ref droid, ref order); trigger buildExpandTr (every, 300); trigger fortifyTr (every, 400); trigger upgradeStructuresTr (every, 50); trigger conDroidsTr (every, 200); // was 1400 trigger repairDroidsTr (every, 400); trigger sensorDroidsTr (every, 400); trigger basedetailsTr (every, 600 ); trigger buildDerrickTr (every, 80 ); trigger buildOilDefenseOrRetreatTr (every, 200 ); trigger incendryTr (every, 120 ); trigger buildPowerGeneratorsTr (every, 80 ); trigger buildBaseTr (every, 150 ); trigger finishStructsTr (every, 210); trigger droidBuiltTr (CALL_NEWDROID,me, ref droid,ref structure); trigger structBuiltTr (CALL_STRUCTBUILT, me, ref droid, ref structure); trigger droidDestroyedTr (CALL_DROID_DESTROYED, me, ref droid); trigger structureDestroyedTr (CALL_STRUCT_DESTROYED, me, ref structure); trigger rebuildStructureTr (every, 50); trigger consolidateEventTr (every, 3100); trigger factoryEventTr (every, 90 ); trigger cyborgFactoryEventTr (every, 90 ); trigger chooseScoutAreaTr (every, 200 ); trigger expandScoutAreaTr (every, 600 ); trigger scoutMainTr (every, 150 ); trigger newObjectReportTr (CALL_OBJ_SEEN, me, ref baseobj, ref baseobj2); trigger attackStuffTr (every, 200 ); trigger allOutAttackTr (every, 2000); trigger defendWatchTr (CALL_STRUCT_ATTACKED, me, ref structure, ref baseobj); trigger defendReturnTr (every, 100000 ); trigger doResearchTr (CALL_RESEARCHCOMPLETED, ref research, ref structure, me); trigger vtolDefendTr (CALL_STRUCT_ATTACKED, me, ref structure, ref baseobj); trigger vtolStructsTr (every, 600); trigger buildVtolsTr (every, 180); trigger vtolAttackTr (every, 10); trigger vtolEnablerTr (every, 700); trigger takeoverTr (CALL_UNITTAKEOVER, ref droid); trigger useLassatTr (every, 3000); trigger reassignTr (CALL_PLAYERLEFT,ref count); trigger formAllianceEventTr (every,170); trigger breakAllianceEventTr (every,3000); trigger difficultyModifierTr (every,600); trigger humanAllianceTr (CALL_ALLIANCEOFFER,ref count, ref count2); trigger multiMsgTr (CALL_AI_MSG, me, ref sender, ref message); trigger beaconTr (CALL_BEACON, me, ref sender, ref x, ref y, ref message); trigger consoleTr (CALL_CONSOLE, ref sender, ref message); trigger watchBaseThreatTr (every, 120); trigger manageAllyHelpTr (every, 80); trigger everySec (every, 10); trigger manageDefendLocationTr (every, 70); trigger startLevelTr (CALL_START_NEXT_LEVEL); trigger chainloadTr (wait, 1); trigger slowloadTr (wait, 13); trigger checkResearchTr (every, 50); /* Events */ event conDroids; event multiMsgEv; event beaconEv; event watchBaseThreat; event manageAllyHelp; event everySecEv; event manageDefendLocationEv; event structureDestroyed; event rebuildStructureEv; event doResearch; event buildDerrick; /* Function prototypes */ function bool haveBeacon(int _player); function bool beaconTimeout(int _player); function void processCommand(string _message, int _sender, bool _bBlipMessage); function bool haveHelpers(); function bool attemptToHelp(int _playerToHelp, int _x, int _y); function void helpPlayer(int _playerToHelp, int _helpX, int _helpY); function bool canStopHelpingAlly(); function void stopHelpingAlly(); function bool helpingAlly(); function bool helpAllyTimeout(); function void requestHelp(int _helpX, int _helpY); function void doRequestHelp(int _helpX, int _helpY); function bool allyBaseAtLoc(int _ally, int _x, int _y); function void messagePlayer(int _playerToMessage, string _message, int _probability); function void messagePlayerAddressed(int _playerToMessage, int _playersToAddress, string _message); function bool canSeeAllies(); function bool baseInTrouble(); function string m_affirmative(); function void defendLocation(int _defendX, int _defendY, int _tDefendTimeout, bool _bMove); function void stopDefendingLocation(); function bool defendingLocation(); function bool defendLocationTimeout(); function bool friendlyPlayer(int _playerToCheck); function void factoryBuildDroid(STRUCTURE _factory); function void cybFactorBuildCyborg(STRUCTURE _factory); function void vtolFactoryBuildVtol(STRUCTURE _factory); function bool insideBase(int _x, int _y); function int numAlliesInBase(bool _bVtols); function int numEnemiesInBase(bool _bVtols); function bool defendingOwnBase(); function int targetTypeValue(BASEOBJ _target); function int numBitsSet(int _integer); function int findResearch(int _searchStart, int _techTree); function bool upgradeFactory(DROID _truck, int _maxBuilders); function bool upgradeVtolFactory(DROID _truck, int _maxBuilders); function bool upgradeResearch(DROID _truck, int _maxBuilders); function bool upgradePowGen(DROID _truck, int _maxBuilders); function void buildRearmPads(); function int numEnemyAAInRange(int _x, int _y, int _range); function BASEOBJ chooseVtolTarget(bool bExclusiveTarget); function int getVtolTargetWeight(BASEOBJ _target); function bool vtolTargetAssigned(BASEOBJ _target); function int numBuildSameBuilding(STRUCTURESTAT _checkStat, int _x, int _y); function int totalVtols(); function bool needTank(); function void setTechBranch(int _tech); function DROID closestIdleTruck(int _x, int _y); function void buildOnExactLocation(DROID _truck, int _x, int _y, STRUCTURESTAT _stat); function void rebuildStructures(); function BASEOBJ chooseVtolDefenceTarget(int _x, int _y, int _range, bool bExclusiveTarget); function int numGroupSameOrder(GROUP _group, int _orderIndex); function void rearrangeAttackVtols(); function int numStructBusyByType(STRUCTURESTAT _busyStructType); function bool aiResponsibleForPlayer(int _player); function void reassignAI(); function void shutDownAI(); function bool buildUnit(TEMPLATE _tankTemplate, STRUCTURE _factory, STRUCTURESTAT _factoryType, bool _bIdleOnly); function STRUCTURE findIdleStructure(STRUCTURESTAT _structType, bool _bIdleOnly); #endregion triggers ///////////////////////////////////////////////////////////////////// // HouseKeeping event initialisedEvent(CALL_GAMEINIT) { local int player; // initialise me = getPlayer("Nexus"); _DEBUG = FALSE; dbgMsgOn(me, _DEBUG); extraStruct = 0; numRepairUnits = 0; numSensorUnits = 0; allOutAttack = NULLOBJECT; tLastHelpRequest = -1; //when we requested help for the last time lastHelpPlayer = -1; //we are not currently helping anyone tHelp = -1; //when we started helping last time tHelpTimeout = -1; //time when help times out helpX = -1; helpY = -1; defendX = -1; defendY = -1; tDefendStart = -1; tDefendTimeout = -1; defendMoveType = -1; //move or scout baseRange = 4 * TILE; // set current research branch setTechBranch(-1); numVtolAttackGroups = 10; numAttackVtols = 10; //num vtols in an attack group numDefendVtols = 5; //num vtols in an attack group // setup build group - all initial droids are in buildgroup! groupAddArea(buildGroup, me, 0, 0, (mapWidth*128), (mapHeight*128)); // note where our base is. getPlayerStartPosition(me, ref baseX, ref baseY); // defence. defendbusy = FALSE; // setup scouts structure = getStructure(factory, me); if(structure != NULLOBJECT) { scoutTLX = structure.x; scoutTLY = structure.y; } else { scoutTLX = baseX; scoutTLY = baseY; } scoutW = 256; scoutH = 256; scoutX = scoutTLX; scoutY = scoutTLY; // clear the alliance array... player = 0; while (player != MAX_PLAYERS) { allianceTime[player] = 0; player = player + 1; } fundamentalBeingBuilt = derrick; // to avoid ever being null if(aiResponsibleForPlayer(me)) { bRunning = true; } else { bRunning = false; shutDownAI(); } } // check whether we have at least one structure of that type function bool haveStructure(STRUCTURESTAT type) { return getStructure(type, me) != NULLOBJECT; } // check if we are getting any income function bool havePowerSource() { // we don't check buildings being finished here return haveStructure(powGen) and haveStructure(derrick); } // I am not sure why we need this hack, but the AI can still end up not researching anything at times event checkResearch(checkResearchTr) { setEventTrigger(doResearch, chainloadTr); } function void dbgPlr(string message) { setEventTrigger(doResearch, chainloadTr); if (me == selectedPlayer) { console(message); } } function void dbgObj(DROID obj, string message) { if (obj.selected) { console(message); } } function bool conCanHelp(DROID mydroid, int bx, int by) { return (mydroid.order != DORDER_HELPBUILD and mydroid.order != DORDER_BUILD and mydroid.order != DORDER_LINEBUILD and droidCanReach(mydroid, bx, by)); } // Build something in main base, grab trucks to do it within tiles range function bool grabTrucksAndBuild(int range, STRUCTURESTAT bstats, int maxBlockingTiles) { local DROID mydroid, closestDroid; local int closestDist, currDist, numHelpDroids, tilerange, bx, by; initIterateGroup(buildGroup); // find idle droids in build group. mydroid = iterateGroup(buildGroup); closestDist = 99999; closestDroid = NULLOBJECT; numHelpDroids = 0; tilerange = range * TILE; while (mydroid != NULLOBJECT) { if (conCanHelp(mydroid, baseX, baseY)) { bx = baseX; by = baseY; if (pickDroidStructLocation(mydroid, bstats, ref bx, ref by, me, maxBlockingTiles)) { currDist = distBetweenTwoPoints(bx, by, mydroid.x, mydroid.y); if (currDist < tilerange) { orderDroidStatsLoc(mydroid, DORDER_BUILD, bstats, bx, by); // close, so help build it numHelpDroids = numHelpDroids + 1; } else if (currDist < closestDist) { closestDroid = mydroid; // record this droid as being closest so far closestDist = currDist; } } } mydroid = iterateGroup(buildGroup); } if (numHelpDroids == 0 and closestDroid != NULLOBJECT) // found none within help radius, so force someone to go long distance traveling { orderDroidStatsLoc(closestDroid, DORDER_BUILD, bstats, bx, by); // you, book a plane ticket and go! return true; } return (numHelpDroids > 0); } event arrived(reachedTr) { local bool found; local STRUCTURESTAT myChoice; if (droid.droidType == DROID_CONSTRUCT or droid.droidType == DROID_CYBORG_CONSTRUCT) { dbgObj(droid, "Failed to build where we should - attempt to screw up enemy oil derrick"); // Check if at oil well, and it was taken by enemy structure = structureBuiltInRange(derrick, droid.x, droid.y, (5 * 128), -1); if (structure != NULLOBJECT) { if (not friendlyPlayer(structure.player) and droid.health == 100) { // Ok, at enemy derrick, and nobody has hurt us yet. Start being nasty. count = 0; found = false; // find simplest/cheapest one available to build while (count < numDefStructs and not found) { if (isStructureAvailable(defStructs[count], me)) { found = true; } else { count++; } } if (found) { buildX = droid.x; buildY = droid.y; if (pickDroidStructLocation(droid, defStructs[count], ref buildX, ref buildY, me, -1)) { orderDroidStatsLoc(droid, DORDER_BUILD, defStructs[count], buildX, buildY); } else { dbgObj(droid, "Wanted to be nasty, but found nowhere to build defense"); orderDroid(droid, DORDER_RTB); // nothing more to do here. } } else { dbgObj(droid, "Wanted to be nasty, but had nothing nasty to build - returning to base"); orderDroid(droid, DORDER_RTB); // oh, well. nothing more to do here. } exit; } else if (droid.health < 100 and !insideBase(droid.x, droid.y)) { orderDroid(droid, DORDER_RTR); // bolt back to base now! exit; } } } } event buildFundamentals(inactive) { count = 0; while (count < numFundamental) { // check that struct. structure = getStructure(structs[count], me); if (structure == NULLOBJECT) // if missing build it. { if (isStructureAvailable(structs[count], me)) { if (grabTrucksAndBuild(12, structs[count], 0)) { exit; // no need to check more } } } count = count + 1; } fundamentalBeingBuilt = derrick; setEventTrigger(buildFundamentals, inactive); } event startLevel(startLevelTr) { setEventTrigger(buildFundamentals, slowloadTr); setEventTrigger(conDroids, chainloadTr); setEventTrigger(doResearch, chainloadTr); setEventTrigger(buildDerrick, slowloadTr); setEventTrigger(startLevel, inactive); } // decide what technology branch we will use function void setTechBranch(int _tech) { local float _y2,_y1,_x2,_x1,_a,_y,_m,_rnd,_mapSize; _mapSize = (float)((mapWidth + mapHeight) / 2); if(_tech != -1) { curTech = _tech; } else { //probability to choose vtol branch for map size 90 = 0; probability for map size 200 = 45 //build a linear function: y = ((y2 - y1) / (x2 - x1)) * x + a depending on two values given (short: y = mx+a) _x1 = 90.0; _y1 = 0.0; _x2 = 200.0; _y2 = 45.0; _m = ((_y2 - _y1) / (_x2 - _x1)); _a = -(_m * _x1); //calculate probability for the current map _y = _m * _mapSize + _a; dbg("_m = " & _m & ", a = " & _a, me); _rnd = (float)random(100); if(_rnd < _y) { curTech = branchVTOL; dbg("going air (" & _y & "/" & _rnd & ")", me); } else { curTech = branchDefault; dbg("going land (" & _y & "/" & _rnd & ")", me); } } } /* returns TRUE if AI is responsible for the _player */ function bool aiResponsibleForPlayer(int _player) { if(not _DEBUG and ((_player == selectedPlayer) or not myResponsibility(_player))) { return FALSE; } return TRUE; } ///////////////////////////////////////////////////////////////////// // keep details about the size and postion of the ai players base event basedetails(basedetailsTr) { // clear old extremities. maxy = 0; maxx = 0; miny = (mapHeight*128); minx = (mapWidth*128); baseRange = 4 * TILE; // now find the extremities of our vital structures. count = 0; while(count < numBaseStruct) { initEnumStruct(FALSE,baseStruct[count],me,me); structure= enumStruct(); while(structure != NULLOBJECT) { if(structure.x < minx) { minx = structure.x; } if(structure.x > maxx) { maxx = structure.x; } if(structure.y < miny) { miny = structure.y; } if(structure.y > maxy) { maxy = structure.y; } result = distBetweenTwoPoints(baseX, baseY, structure.x, structure.y); if(result > baseRange){ baseRange = result; } structure= enumStruct(); } count = count + 1; } result = 3 * 128; minx = minx - result; maxx = maxx + result; miny = miny - result; maxy = maxy + result; baseRange = baseRange + (4 * 128); } ///////////////////////////////////////////////////////////////////// // structure building rules // build derricks on oil. event buildDerrick(buildDerrickTr) { local bool foundOne, _same; local FEATURE _oil, _closestOil; local int _bestDist, _newDist; local DROID _search; // what if we can't waste power on building derricks because we don't have a gen yet? if (playerPower(me) < 300 and haveStructure(derrick) and not haveStructure(powGen)) { setEventTrigger(buildDerrick, slowloadTr); exit; } _bestDist = 99999; _closestOil = NULLOBJECT; foundOne = false; initIterateGroup(buildGroup); // find all units in build group droid = iterateGroup(buildGroup); while (droid != NULLOBJECT && !foundOne) { if (droid.order != DORDER_BUILD and droid.order != DORDER_LINEBUILD and droid.order != DORDER_HELPBUILD) { foundOne = true; } else { droid = iterateGroup(buildGroup); } } if (droid != NULLOBJECT) { initGetFeature(oilRes, -1, me); _oil = getFeatureB(me); while (_oil != NULLOBJECT) { _newDist = distBetweenTwoPoints(droid.x, droid.y, _oil.x, _oil.y); _same = false; if (_newDist < _bestDist and droidCanReach(droid, _oil.x, _oil.y)) // this one is closer { if (!threatInRange(me, _oil.x, _oil.y, OIL_THREAT_RANGE, FALSE)) { initIterateGroup(buildGroup); // find all units in build group. _search = iterateGroup(buildGroup); foundOne = false; while (_search != NULLOBJECT && !foundOne) { if (_search.orderx == _oil.x and _search.ordery == _oil.y and _search != droid) { _same = true; foundOne = true; } _search = iterateGroup(buildGroup); } if (!_same) // do not go to same spot as another droid { _bestDist = _newDist; _closestOil = _oil; } } } _oil = getFeatureB(me); } if (_closestOil != NULLOBJECT) { orderDroidStatsLoc(droid, DORDER_BUILD, derrick, _closestOil.x, _closestOil.y); // build a derick if (idleGroup(buildGroup) > 0) { setEventTrigger(buildDerrick, slowloadTr); // do it again for next droid exit; } } } setEventTrigger(buildDerrick, buildDerrickTr); } ///////////////////////////////////////////////////////////////////// // if idle and derrick in range and no defense then build defense, else ret to base . event buildOilDefenseOrRetreat(buildOilDefenseOrRetreatTr) { local int _numBuilders,_maxBuilders; _maxBuilders = 1; // check idle. initIterateGroup(buildGroup); // find idle droids in build group. droid = iterateGroup(buildGroup); while(droid != NULLOBJECT) { if (droid.order != DORDER_BUILD and droid.order != DORDER_LINEBUILD and droid.order != DORDER_HELPBUILD) { // if in range of a derrick structure = structureBuiltInRange(derrick, droid.x, droid.y, (5*128), me); // if inside base limits then presume ok.. if( structure != NULLOBJECT) { if((structure.x > minx) and (structure.y > miny) and (structure.x < maxx) and (structure.y <maxy)) { structure = NULLOBJECT; } } if(structure != NULLOBJECT) { buildX = structure.x; buildY = structure.y; // not many defenses nearby if(numFriendlyWeapStructsInRange(me, buildX, buildY, (3*128), FALSE) < 2) { count = numDefStructs - 1; //pick a struct to build.. count2 = 0; while( (count2 < 5) and (count >= 0) ) { if( isStructureAvailable(defStructs[count],me)) { structChoice[count2] = defStructs[count]; count2 = count2 + 1; } count = count - 1; } count =0; if(count2 > 0) { count = random(count2); //count = choice! // pick a location boolResult = pickDroidStructLocation(droid, structChoice[count], ref buildX, ref buildY, me, -1); _numBuilders = numBuildSameBuilding(NULLSTRUCTURESTAT, buildX, buildY); if((boolResult == TRUE) and (_numBuilders < _maxBuilders) and droidCanReach(droid, buildX, buildY)) { // build it. orderDroidStatsLoc(droid, DORDER_BUILD,structChoice[count], buildX,buildY); _numBuilders++; } } } else { structure = structureBuiltInRange(playerHQ, droid.x, droid.y, (5*128), me); if(structure == NULLOBJECT) { if(!insideBase(droid.x, droid.y)) { orderDroid(droid,DORDER_RTB); // return to base; } } } } else { structure = structureBuiltInRange(playerHQ, droid.x, droid.y, (5*128), me); if(structure == NULLOBJECT) { if(!insideBase(droid.x, droid.y)) { orderDroid(droid,DORDER_RTB); // return to base; } } } } droid = iterateGroup(buildGroup); } } ///////////////////////////////////////////////////////////////////// //mortar etc.. rules. build sensor towers and emplacements. event incendry(incendryTr) { if (not isStructureAvailable(sensorTower, me)) { exit; } initEnumStruct(FALSE,sensorTower,me,me); count = 0; structure = enumStruct(); while(structure != NULLOBJECT) { count = count + 1; structure = enumStruct(); } if (count < (gameTime/600)) // every 7 mins { // if not found build a sensor tower. // find a place to build. buildX = 0; buildY = 0; initEnumStruct(FALSE,derrick,me,me); structure= enumStruct(); while(structure != NULLOBJECT) { count = 0; result = 0; while(count < numDefStructs) { structure2 = structureBuiltInRange(defStructs[count], structure.x, structure.y,(4*128), me); if(structure2 != NULLOBJECT) { result = result + 1; } count = count + 1; } // check for sensor nearby, structure2 = structureBuiltInRange(sensorTower, structure.x, structure.y,(5*128), me); if(structure2 != NULLOBJECT) { result = 4; } if(result < 3) { buildX = structure.x; buildY = structure.y; structure = NULLOBJECT; } else { structure = enumStruct(); } } if(buildX != 0) { boolResult = pickStructLocation(sensorTower, ref buildX, ref buildY,me); // pick spot. if(boolResult == TRUE) { // find unit initIterateGroup(buildGroup); droid = iterateGroup(buildGroup); while(droid != NULLOBJECT) { if ((droid.order == DORDER_NONE or droid.order == DORDER_RTB) and droidCanReach(droid, buildX, buildY)) { orderDroidStatsLoc(droid, DORDER_BUILD, sensorTower, buildX, buildY); droid = NULLOBJECT; } else { droid = iterateGroup(buildGroup); } } } } } else { // find a sensor tower with least incencdry structs around it.. buildX = 0; buildY = 0; initEnumStruct(FALSE,sensorTower,me,me); structure= enumStruct(); count = 999; while(structure != NULLOBJECT) { // count incendrys near this tower. result = 0; count2 = 0; while(count2 < numIncendrys) { structure2 = structureBuiltInRange(incendrys[count2], structure.x, structure.y,(4*128), me); if(structure2 != NULLOBJECT) { result = result + 1; } count2 = count2 + 1; } if((result < 6) and (result < count)) // lowest found yet. only sites with <6 too. { buildX = structure.x; buildY = structure.y; count = result; } structure = enumStruct(); } if(buildX != 0) { // choose a device count = numIncendrys - 1; result = 99; while(count >= 0 ) { if(isStructureAvailable(incendrys[count],me)) { result = count; count = -1; } else { count = count - 1; } } // find a unit and build an incendry device. if(result != 99) { boolResult = pickStructLocation(incendrys[result], ref buildX, ref buildY,me); // pick spot. if(boolResult == TRUE) { initIterateGroup(buildGroup); droid = iterateGroup(buildGroup); boolResult = (numBuildSameBuilding(incendrys[result], buildX, buildY) > 0); //anyone building there already? while(droid != NULLOBJECT and (not boolResult)) { if ((droid.order == DORDER_NONE or droid.order == DORDER_RTB) and droidCanReach(droid, buildX, buildY)) { orderDroidStatsLoc(droid, DORDER_BUILD,incendrys[result], buildX,buildY); boolResult = TRUE; //only 1 truck } droid = iterateGroup(buildGroup); } } } } } } ///////////////////////////////////////////////////////////////////// // build a power gen for every 4 derricks. VITAL! event buildPowerGenerators(buildPowerGeneratorsTr) { if (!isStructureAvailable(powGen, me)) { exit; } initEnumStruct(FALSE,derrick,me,me); // count = numderricks structure= enumStruct(); count = 0; while(structure != NULLOBJECT) { count = count + 1; structure= enumStruct(); } initEnumStruct(FALSE,powGen,me,me); // count2 = numpowgens structure= enumStruct(); count2 = 0; while(structure != NULLOBJECT) { count2 = count2 + 1; structure= enumStruct(); } if( (count2 * 4) < count ) // if we need powergen { initIterateGroup(buildGroup); droid = iterateGroup(buildGroup); while(droid != NULLOBJECT) { if (droid.order != DORDER_HELPBUILD and droid.order != DORDER_BUILD and droid.order != DORDER_LINEBUILD) { buildX = baseX; // try build powergen. buildY = baseY; if (pickDroidStructLocation(droid, powGen, ref buildX, ref buildY, me, 1)) { orderDroidStatsLoc(droid, DORDER_BUILD, powGen, buildX,buildY); } } droid = iterateGroup(buildGroup); } } } ///////////////////////////////////////////////////////////////////// // ensure we have everything in the vital structs list. event buildBase(buildBaseTr) { if (idleGroup(buildGroup) >= (buildGroup.members / 2)) { count = 0; while(count < numStructs) { // check that struct. structure = getStructure(structs[count],me); if(structure == NULLOBJECT) // if missing build it. { if(isStructureAvailable(structs[count],me)) { if (grabTrucksAndBuild(10, structs[count], 0)) { exit; // done here } } } count = count + 1; } } } ///////////////////////////////////////////////////////////////////// // build other stuff, grow the base slowly... event buildExpand( buildExpandTr ) { if (playerPower(me) < LOW_POWER) { exit; // do not expand base with low power } if(extraStruct == numExtraStructs[curTech]) // loop round { extraStruct = 0; } if(isStructureAvailable(extraStructs[curTech][extraStruct],me)) { if (not grabTrucksAndBuild(10, extraStructs[curTech][extraStruct], 0)) { dbg("Failed to build expand", me); } } extraStruct = extraStruct + 1; } ///////////////////////////////////////////////////////////////////// // Structure (fac/res/pow) upgrades event upgradeStructures(upgradeStructuresTr ) { if (not havePowerSource()) { exit; } initIterateGroup(buildGroup); // find idle droids in build group. droid = iterateGroup(buildGroup); while(droid != NULLOBJECT) { if ((droid.order != DORDER_BUILD) and (droid.order != DORDER_LINEBUILD)) { boolResult = FALSE; if(curTech == branchDefault) { //powergen boolResult = upgradePowGen(droid, 4); //factory if(droid.order != DORDER_BUILD){ boolResult = upgradeFactory(droid, 4); } //research if(droid.order != DORDER_BUILD){ boolResult = upgradeResearch(droid, 4); } //vtol Factory if(droid.order != DORDER_BUILD){ boolResult = upgradeVtolFactory(droid, 4); } } else if(curTech == branchVTOL) { //powergen boolResult = upgradePowGen(droid, 4); //vtol Factory if(droid.order != DORDER_BUILD){ boolResult = upgradeVtolFactory(droid, 4); } //factory if(droid.order != DORDER_BUILD){ boolResult = upgradeFactory(droid, 4); } //research if(droid.order != DORDER_BUILD){ boolResult = upgradeResearch(droid, 4); } } } droid = iterateGroup(buildGroup); } } function bool upgradeFactory(DROID _truck, int _maxBuilders) { local STRUCTURE _factory; initEnumStruct(FALSE,factory,me,me); _factory = enumStruct(); while(_factory != NULLOBJECT) { // if upgrade is available && struct is not upgraded if( isStructureAvailable(facModule,me) and (skGetFactoryCapacity(_factory) < 2 ) and droidCanReach(_truck, _factory.x, _factory.y)) { if((numBuildSameBuilding(facModule, _factory.x, _factory.y) + numBuildSameBuilding(vtolFactory, _factory.x, _factory.y)) < _maxBuilders) { orderDroidStatsLoc(_truck, DORDER_BUILD,facModule, _factory.x,_factory.y); // upgrade it. return TRUE; } } _factory = enumStruct(); } return FALSE; } function bool upgradeVtolFactory(DROID _truck, int _maxBuilders) { local STRUCTURE _factory; initEnumStruct(FALSE,vtolFactory,me,me); _factory = enumStruct(); while(_factory != NULLOBJECT) { // if upgrade is available && struct is not upgraded if( isStructureAvailable(facModule,me) and (skGetFactoryCapacity(_factory) < 2 ) and droidCanReach(_truck, _factory.x, _factory.y)) { if((numBuildSameBuilding(facModule, _factory.x, _factory.y) + numBuildSameBuilding(factory, _factory.x, _factory.y)) < _maxBuilders) { orderDroidStatsLoc(_truck, DORDER_BUILD,facModule, _factory.x,_factory.y); // upgrade it. return TRUE; } } _factory = enumStruct(); } return FALSE; } function bool upgradeResearch(DROID _truck, int _maxBuilders) { local STRUCTURE _resFac; initEnumStruct(FALSE,resLab,me,me); _resFac = enumStruct(); while(_resFac != NULLOBJECT) { // if upgrade is available && struct is not upgraded if( isStructureAvailable(resModule,me) and (not testStructureModule(me, _resFac, 0)) and droidCanReach(_truck, _resFac.x, _resFac.y)) { if((numBuildSameBuilding(resModule, _resFac.x, _resFac.y) + numBuildSameBuilding(resLab, _resFac.x, _resFac.y)) < _maxBuilders) { orderDroidStatsLoc(_truck, DORDER_BUILD,resModule, _resFac.x,_resFac.y); // upgrade it. return TRUE; } } _resFac = enumStruct(); } return FALSE; } function bool upgradePowGen(DROID _truck, int _maxBuilders) { local STRUCTURE _powGen; initEnumStruct(FALSE,powGen,me,me); _powGen = enumStruct(); while(_powGen != NULLOBJECT) { // if upgrade is available && struct is not upgraded if( isStructureAvailable(powModule,me) and (not testStructureModule(me, _powGen, 0)) and droidCanReach(_truck, _powGen.x, _powGen.y)) { if((numBuildSameBuilding(powModule, _powGen.x,_powGen.y) + numBuildSameBuilding(powGen, _powGen.x,_powGen.y)) < _maxBuilders) { orderDroidStatsLoc(_truck, DORDER_BUILD, powModule, _powGen.x,_powGen.y); // upgrade it. return TRUE; } } _powGen = enumStruct(); } return FALSE; } ///////////////////////////////////////////////////////////////////// // Finish Building Part Built Structures event finishStructs(finishStructsTr) { initEnumStruct(TRUE,factory,me,me); structure= enumStruct(); while(structure != NULLOBJECT) { if(not structureComplete(structure)) { initIterateGroup(buildGroup); // find idle droids in build group. droid = iterateGroup(buildGroup); while(droid != NULLOBJECT) { if (droid.order != DORDER_BUILD and droid.order != DORDER_LINEBUILD and droidCanReach(droid, structure.x, structure.y) and distBetweenTwoPoints(droid.x, droid.y, structure.x, structure.y) < 20 * TILE) { orderDroidObj(droid,DORDER_HELPBUILD,structure); } droid = iterateGroup(buildGroup); } } structure= enumStruct(); } } ///////////////////////////////////////////////////////////////////// // fortify base by builiding defensive structs on the edge of the base. // rewrote fortify to use scrSkDefenseLocation(baseX,baseY,me); event newfortify(fortifyTr) { local int _numBuilders,_maxBuilders; _maxBuilders = 1; if(numGroupSameOrder(buildGroup, DORDER_LINEBUILD) >= _maxBuilders) { exit; } boolResult = FALSE; initIterateGroup(buildGroup); // find idle an idle veh.in build group. droid = iterateGroup(buildGroup); while((boolResult == FALSE) and (droid != NULLOBJECT)) { if (droid.order != DORDER_BUILD and droid.order != DORDER_LINEBUILD and droid.order != DORDER_HELPBUILD) { boolResult = TRUE; // dont do this again! tempx = baseX; tempy = baseY; // choose a suitable turret. count = numWallWeaps - 1; count2 = 0; while( (count2 < 3) and (count >= 0) ) { if( isStructureAvailable(wallWeaps[count],me)) { structChoice[count2] = wallWeaps[count]; count2 = count2 + 1; } count = count - 1; } count =0; if((count2 > 0) and (_numBuilders < _maxBuilders)) { count = random(count2); skDefenseLocationB(ref tempx,ref tempy,wall,structChoice[count],droid,me); _numBuilders++; } } droid = iterateGroup(buildGroup); } } ///////////////////////////////////////////////////////////////////// // droid building rules ///////////////////////////////////////////////////////////////////// // deal with a droid being built event droidBuiltAssign(droidBuiltTr) { if(isVtol(droid)) { if(vtolDefendGr.members < numDefendVtols) { groupAddDroid(vtolDefendGr, droid); } else { count = 0; while(count < numVtolAttackGroups) { if(vtolAttackGr[count].members < numAttackVtols) { dbg("added new vtol to group " & count, me); groupAddDroid(vtolAttackGr[count], droid); count = numVtolAttackGroups; } count++; } } } else if((droid.droidType != DROID_TRANSPORTER) and (droid.droidType != DROID_COMMAND)) { if((droid.droidType == DROID_REPAIR) or (droid.droidType == DROID_CYBORG_REPAIR)) { numRepairUnits = numRepairUnits + 1; } if(droid.droidType == DROID_SENSOR) { numSensorUnits = numSensorUnits + 1; } if((droid.droidType == DROID_CONSTRUCT) or (droid.droidType == DROID_CYBORG_CONSTRUCT)) // if constructor droid { groupAddDroid(buildGroup, droid); } else { if(droid.droidType == DROID_CYBORG) { groupAddDroid(attackGroup, droid); } else { if(scoutGroup.members < numScouts[curTech]) { groupAddDroid(scoutGroup, droid); } else if(attackGroup.members < numAttackers[curTech]) { groupAddDroid(attackGroup, droid); } else if( defendGroup.members < numDefenders[curTech]) { groupAddDroid(defendGroup, droid); } else { if(scoutGroup.members < maxScouts[curTech]) { groupAddDroid(scoutGroup, droid); } else if(attackGroup.members < maxAttackers[curTech]) { groupAddDroid(attackGroup, droid); } else if( defendGroup.members < maxDefenders[curTech]) { groupAddDroid(defendGroup, droid); } else //make them attack { groupAddDroid(attackGroup, droid); } } } } } } //When droid built: check emergency jobs, start building next droid event droidBuilt(droidBuiltTr) { local STRUCTURE _fundie; /* Start building next droid */ if(structure != NULLOBJECT) { // derrick works as NULL here, as NULLSTAT does not seem to work if (droid.droidType == DROID_CONSTRUCT and fundamentalBeingBuilt != derrick) { _fundie = getStructure(fundamentalBeingBuilt, me); if (_fundie != NULLOBJECT) { if (not structureComplete(_fundie)) { orderDroidObj(droid, DORDER_HELPBUILD, _fundie); } } } if (droid.droidType == DROID_CONSTRUCT && structure.stattype == REF_FACTORY) { setEventTrigger(conDroids, chainloadTr); // consider building more } // Continue building new droids right away else if(structure.stattype == REF_FACTORY) { factoryBuildDroid(structure); } else if(structure.stattype == REF_CYBORG_FACTORY) { cybFactorBuildCyborg(structure); } else if(structure.stattype == REF_VTOL_FACTORY) { vtolFactoryBuildVtol(structure); } } } /* Gets triggered when structure was built */ event structBuilt(structBuiltTr) { local FEATURE _oilResource; local int _count,_count2; if (structure == NULLOBJECT || droid == NULLOBJECT) { exit; } /* factory or factory module */ if(structure.stattype == REF_FACTORY) { if (isStructureAvailable(facModule, me) and (skGetFactoryCapacity(structure) < 2 ) and (getDroidCount(me) > 4)) { orderDroidStatsLoc(droid, DORDER_BUILD,facModule, structure.x,structure.y); // upgrade it. } else { setEventTrigger(conDroids, chainloadTr); } } /* vtol factory or vtol factory module */ else if(structure.stattype == REF_VTOL_FACTORY) { if( isStructureAvailable(facModule,me) and (skGetFactoryCapacity(structure) < 2 )) { orderDroidStatsLoc(droid, DORDER_BUILD,facModule, structure.x,structure.y); // upgrade it. } } else if(structure.stattype == REF_RESOURCE_EXTRACTOR) { setEventTrigger(buildDerrick, chainloadTr); exit; } else if (structure.stattype == REF_RESEARCH) { if (isStructureAvailable(resModule, me)) { orderDroidStatsLoc(droid, DORDER_BUILD, resModule, structure.x, structure.y); // upgrade it. } else { setEventTrigger(doResearch, chainloadTr); } } else if (structure.stattype == REF_POWER_GEN) { if (isStructureAvailable(powModule, me)) { orderDroidStatsLoc(droid, DORDER_BUILD, powModule, structure.x, structure.y); // upgrade it. } } // Check if available trucks need to build more absolute necessities right away. We need a trigger here because // droids involved in building have not yet come out of their build orders. setEventTrigger(buildFundamentals, slowloadTr); //see if we have just rebuilt a destroyed structure _count = 0; while(_count < countRebuildStruct) { if(structure.x == rebuildStructX[_count] and structure.y == rebuildStructY[_count] and ( (structure.stat == rebuildStructStat[_count]) or //walls can end up as corner walls ( (structure.stat == wall or structure.stat == cornerWall) and (rebuildStructStat[_count] == wall or rebuildStructStat[_count] == cornerWall)) )) { dbg("finished rebuilding destroyed structure - " & _count, me); //resort destroyed structures _count2 = _count; while(_count2 < (countRebuildStruct - 1)) { rebuildStructX[_count2] = rebuildStructX[_count2 + 1]; rebuildStructY[_count2] = rebuildStructY[_count2 + 1]; rebuildStructStat[_count2] = rebuildStructStat[_count2 + 1]; _count2++; } //clear last entry rebuildStructX[countRebuildStruct - 1] = 0; rebuildStructY[countRebuildStruct - 1] = 0; rebuildStructStat[countRebuildStruct - 1] = NULLSTRUCTURESTAT; countRebuildStruct--; //we just built one structure //_count = countRebuildStruct; //exit outer loop } _count++; } } ///////////////////////////////////////////////////////////////////// // deal with attacks. event droidDestroyed(droidDestroyedTr) { if(droid.droidType == DROID_REPAIR) { numRepairUnits = numRepairUnits - 1; } if(droid.droidType == DROID_SENSOR) { numSensorUnits = numSensorUnits - 1; } if(droid.droidType == DROID_CONSTRUCT) // if constructor droid { initEnumStruct(FALSE,factory,me,me); structure= enumStruct(); // find factory. if( (structure != NULLOBJECT) and (getDroidCount(me) < MAX_DROIDS) ) { buildDroid(constructor, structure, me, 1); // build constructor } } } ///////////////////////////////////////////////////////////////////// // build more con droids. event conDroids(conDroidsTr) { local int _maxTrucks; local STRUCTURE _factory; local int _numBuilding,_haveTrucks,_maxTruckFactories,_totalTrucks; local bool _bStartedBuilding; _maxTrucks = MAX_TRUCKS; if (playerPower(me) < LOW_POWER) { _maxTrucks = MIN_TRUCKS; } _maxTruckFactories = 3; //max factories to use for truck production _haveTrucks = buildGroup.members; //Find out how many trucks and combat engineers are already in production _numBuilding = numTemplatesInProduction(constructor,me); //trucks _numBuilding = _numBuilding + numTemplatesInProduction(cybEngineer,me); //engineers _totalTrucks = _numBuilding + _haveTrucks; initEnumStruct(FALSE,factory,me,me); _factory = enumStruct(); while ((_factory != NULLOBJECT) and (_numBuilding < _maxTruckFactories) and (_totalTrucks < _maxTrucks)) { //Try to build a truck if (skCanBuildTemplate(me, _factory, hovertruck)) { _bStartedBuilding = buildUnit(hovertruck, _factory, factory, FALSE); //build truck even if not idle } else { _bStartedBuilding = buildUnit(constructor, _factory, factory, FALSE); //build truck even if not idle } //Update statistics if started building a truck if(_bStartedBuilding) { _numBuilding++; _totalTrucks++; } _factory = enumStruct(); } //build cyborg engineers if needed, no building structure limit here initEnumStruct(FALSE,cybFactory,me,me); _factory = enumStruct(); while((_factory != NULLOBJECT) and (_totalTrucks < _maxTrucks)) { //Try to build a truck if( skCanBuildTemplate(me,_factory, cybEngineer) ) //make sure we have researched cyb engineer { _bStartedBuilding = buildUnit(cybEngineer, _factory, cybFactory, FALSE); //build a cyb eng even if not idle //Update statistics if started building a cyborg engineer if(_bStartedBuilding) { _numBuilding++; _totalTrucks++; } } _factory = enumStruct(); } setEventTrigger(conDroids, conDroidsTr); } //Build a droid function bool buildUnit(TEMPLATE _tankTemplate, STRUCTURE _factory, STRUCTURESTAT _factoryType, bool _bIdleOnly) { //Factory was not provided, find an factory if(_factory == NULLOBJECT) { _factory = findIdleStructure(_factoryType, _bIdleOnly); } //Build if got a factory if(_factory != NULLOBJECT) { if(structureComplete(_factory) and (getDroidCount(me) < MAX_DROIDS)) { if( !(_bIdleOnly and !structureIdle(_factory)) ) //don't build if only allowed to build whe idle and fac is not idle { buildDroid(_tankTemplate, _factory, me, 1); // build a tank return TRUE; //success } } } return FALSE; //failed } //Returns an idle structure of the provided type or NULLOBJECT if none found function STRUCTURE findIdleStructure(STRUCTURESTAT _structType, bool _bIdleOnly) { local STRUCTURE _structure; initEnumStruct(FALSE,_structType,me,me); _structure = enumStruct(); while(_structure != NULLOBJECT) { if(structureComplete(_structure)) { if( !(_bIdleOnly and !structureIdle(_structure)) ) { return _structure; } } _structure = enumStruct(); } return NULLOBJECT; //none found } ///////////////////////////////////////////////////////////////////// // build repair droids. event repairDroids(repairDroidsTr) { // if we're running low on repair droids, build some.. if(numRepairUnits <8 and (playerPower(me) > LOW_POWER)) { if(random(10) <= 3) { initEnumStruct(FALSE,factory,me,me); structure= enumStruct(); // find factory. if (structure != NULLOBJECT) { count = 6; while( count >= 0 ) { if ((getDroidCount(me) < MAX_DROIDS) and (skCanBuildTemplate(me, structure, repair[count])) ) { buildDroid(repair[count], structure, me, 1); // build repairunit. count = -1; } count = count - 1; } } } else { initEnumStruct(FALSE,cybFactory,me,me); structure= enumStruct(); // find factory. if (structure != NULLOBJECT) { count = 6; while( count >= 0 ) { if ((getDroidCount(me) < MAX_DROIDS) and (skCanBuildTemplate(me, structure, repair[count])) ) { buildDroid(repair[count], structure, me, 1); // build repairunit. count = -1; } count = count - 1; } } } } } ///////////////////////////////////////////////////////////////////// // build sensor droids. event sensorDroids(sensorDroidsTr) { if(numSensorUnits <3 and (playerPower(me) > LOW_POWER)) { initEnumStruct(FALSE,factory,me,me); structure= enumStruct(); if(structure != NULLOBJECT) { count = 7; while( count >= 0 ) { if((getDroidCount(me) < MAX_DROIDS) and (skCanBuildTemplate(me, structure, sense[count])) ) { count2 = 0; count2 = count - 1; if(random(10) <= 5 and count2 >= 0) { if(skCanBuildTemplate(me, structure, sense[count2])) { buildDroid(sense[count2], structure, me, 1); count = -1; } else { buildDroid(sense[count], structure, me, 1); count = -1; } } else { buildDroid(sense[count], structure, me, 1); count = -1; } } count = count - 1; } } } } ///////////////////////////////////////////////////////////////////// event factoryEvent(factoryEventTr) { // for each factory.... initEnumStruct(FALSE,factory,me,me); structure = enumStruct(); // find factory. if(getDroidCount(me) < MAX_DROIDS) { while(structure != NULLOBJECT) { if( structureIdle(structure) ) { factoryBuildDroid(structure); } structure = enumStruct(); } } } function bool needTank() { if(not havePowerSource()) { return FALSE; } if((defendGroup.members < maxDefenders[curTech]) or (maxDefenders[curTech] == UNLIMITED)) { return TRUE; } if((scoutGroup.members < maxScouts[curTech]) or (maxScouts[curTech] == UNLIMITED)) { return TRUE; } if((attackGroup.members < maxAttackers[curTech]) or (maxAttackers[curTech] == UNLIMITED)) { return TRUE; } return FALSE; } function void factoryBuildDroid(STRUCTURE _factory) { local int _count,_count2; if(_factory == NULLOBJECT){ dbg("factoryBuildDroid: factory is NULLOBJECT", me); return; } if(not needTank()) { //dbg("NEED NO TANKS!! " & maxDefenders[curTech], me); return; } if( structureIdle(_factory) and (playerPower(me) > LOW_POWER)) { _count = numTemplates[curTech] - 1; _count2 = 0; while( (_count2 < MAX_RANDOM_TEMPLATES) and (_count >= 0) ) { if( skCanBuildTemplate(me,_factory, tmpl[curTech][_count]) ) { tmplChoice[_count2] = tmpl[curTech][_count]; _count2 = _count2 + 1; } _count = _count - 1; } if(_count2 > 0) { buildDroid(tmplChoice[random(_count2)],_factory,me,1); } } else { dbg("factoryBuildDroid: factory is busy", me); } } ///////////////////////////////////////////////////////////////////// // put cyborg factories to work event cyborgFactoryEvent(cyborgFactoryEventTr) { if(not ((defendGroup.members < maxCyborgs[curTech]) or (maxCyborgs[curTech] == UNLIMITED))) { exit; //we need no cyborgs } initEnumStruct(FALSE,cybFactory,me,me); structure= enumStruct(); // find factory. while(structure != NULLOBJECT) { if( structureIdle(structure) == TRUE) { cybFactorBuildCyborg(structure); } structure= enumStruct(); // find factory. } } function void cybFactorBuildCyborg(STRUCTURE _factory) { if(_factory == NULLOBJECT){ dbg("cybFactorBuildCyborg: factory is NULLOBJECT", me); return; } if( structureIdle(_factory) and (playerPower(me) > LOW_POWER)) { if( (defendGroup.members < maxCyborgs[curTech]) and (getDroidCount(me) < MAX_DROIDS) ) { count = 20; count2 = 0; while( count >= 0 ) { if( skCanBuildTemplate(me,_factory, superCyb[count]) ) { tmplChoice[count2] = superCyb[count]; count2 = count2 + 1; } count = count - 1; } if(count2 > 0) { buildDroid(tmplChoice[random(count2)],_factory,me,1); } else //try light cyborgs { count = numLightCyborgs - 1; count2 = 0; while( (count >= 0) and (count2 < 2) ) { if( skCanBuildTemplate(me,_factory, cybTempl[count]) ) { tmplChoice[count2] = cybTempl[count]; count2++; } count--; } if(count2 > 0) { buildDroid(tmplChoice[random(count2)], _factory, me, 1); } } } } } ///////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////// // scouting rules // scout an area event chooseScoutArea(chooseScoutAreaTr) { scoutX = scoutTLX + random(scoutW); scoutY = scoutTLY + random(scoutH); } ///////////////////////////////////////////////////////////////////// // visit new places event expandScoutArea(expandScoutAreaTr) { //expand the scouting area slightly scoutTLX = scoutTLX - ((mapWidth*128)/ tileExpand); scoutTLY = scoutTLY - ((mapHeight*128)/ tileExpand); scoutW = scoutW + (2*((mapWidth*128)/ tileExpand)); scoutH = scoutH + (2*((mapHeight*128)/ tileExpand)); // check & restrain. if(scoutTLX <1) { scoutTLX = 1; } if(scoutTLY <1) { scoutTLY = 1; } if(scoutTLX >(mapWidth*128)) { scoutTLX = (mapWidth*128) - 128; } if(scoutTLY >(mapHeight*128)) { scoutTLY = (128*mapHeight) - 128; } if( (scoutTLX + scoutW) > (128 * mapWidth) ) { scoutW = ( (128 * mapWidth) - scoutTLX) - 128; } if( (scoutTLY + scoutH) > (128 *mapHeight) ) { scoutH = ( (128*mapHeight) - scoutTLY) - 128; } } ///////////////////////////////////////////////////////////////////// // order scouts event scoutMain(scoutMainTr) { // find any new scouts // if scouts aren't busy, send them to a new spot. if( idleGroup(scoutGroup) >= (scoutGroup.members /2) ) { orderGroupLoc(scoutGroup, DORDER_MOVE,scoutX,scoutY); } } ///////////////////////////////////////////////////////////////////// // process new visibility reports event newObjectReport(newObjectReportTr) { if(!friendlyPlayer(baseobj.player)) { if(targetTypeValue(baseobj) > targetTypeValue(attackObj)) { attackObj = baseobj;// got a new unseen target from a scout. if( attackObj.type == OBJ_STRUCTURE) { if(not allianceExistsBetween(attackObj.player,me)) // an enemy { structure = objToStructure(attackObj); if(structure.stat == factory) { allOutAttack = attackObj; } } } } } } function int targetTypeValue(BASEOBJ _target) { local STRUCTURE _strTarget; if(_target == NULLOBJECT){ return NO_TARGET_VALUE; } if(_target.type == OBJ_DROID) { return DROID_TARGET_VALUE; } else if(_target.type == OBJ_STRUCTURE) { _strTarget = objToStructure(_target); if(_strTarget.stattype == REF_DEFENSE) { return DEFENSE_TARGET_VALUE; } else if(_strTarget.stattype == REF_RESEARCH or _strTarget.stattype == REF_POWER_GEN) { return RESEARCH_TARGET_VALUE; } else if(_strTarget.stattype == REF_HQ or _strTarget.stattype == REF_COMMAND_CONTROL) { return HQ_TARGET_VALUE; } else if(_strTarget.stattype == REF_RESOURCE_EXTRACTOR) { return OIL_TARGET_VALUE; } else if(_strTarget.stattype == REF_FACTORY or _strTarget.stattype == REF_CYBORG_FACTORY or _strTarget.stattype == REF_VTOL_FACTORY) { return FACTORY_TARGET_VALUE; } else //walls, rearm pads etc { return OTHER_TARGET_VALUE; } } return NO_TARGET_VALUE; } ///////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////// // spy technologies //event takeover( CALL_UNITTAKEOVER , ref droid ) event takeover(takeoverTr) { if( droid.player == me ) { if(droid.droidType == DROID_CONSTRUCT or droid.droidType == DROID_CYBORG_CONSTRUCT) { groupAddDroid( buildGroup, droid ); } else if (droid.droidType != DROID_TRANSPORTER && droid.droidType != DROID_COMMAND) { groupAddDroid( attackGroup, droid ); } } } event takeoverDefend(takeoverTr) { if( droid.player != me ) { completeResearch(nexusDefence,me); setEventTrigger(takeoverDefend, inactive); } } event useLassat(useLassatTr) { // find my lassat // fire it at my attack objective. if(allOutAttack != NULLOBJECT) { initEnumStruct(FALSE,lassat,me,me); structure= enumStruct(); while(structure != NULLOBJECT) { if(structureComplete(structure) == TRUE) { skFireLassat(me,allOutAttack); } structure= enumStruct(); } } } ///////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////// // attack rules event findEnemy(attackStuffTr) { if(attackObj == NULLOBJECT) { count = random(8); count2 = 100; while( friendlyPlayer(count) && (count2 > 0) ) { count = random(8); count2--; } if(!friendlyPlayer(count)) { baseobj = skLocateEnemy(count); if(baseobj != NULLOBJECT) { attackObj = baseobj; // set allOutAttack to attackObj only if attackObj is a more valuable target than allOutAttack if(targetTypeValue(attackObj) > targetTypeValue(allOutAttack)) { allOutAttack = attackObj; } } } } } ///////////////////////////////////////////////////////////////////// // send attack team out to cause trouble near things scout found. event attackStuff(attackStuffTr) { if( idleGroup(attackGroup) >= (attackGroup.members / 2)) { if( (attackObj != NULLOBJECT) and (not helpingAlly()) ) { if (not allianceExistsBetween(me, attackObj.player)) { if(attackGroup.members > (6 + random(6)) ) { orderGroupLoc(attackGroup, DORDER_SCOUT, attackObj.x, attackObj.y); } // make scouts attack too if( idleGroup(scoutGroup) >= (scoutGroup.members / 2) ) { orderGroupLoc(scoutGroup, DORDER_SCOUT, attackObj.x, attackObj.y); } } } } } ///////////////////////////////////////////////////////////////////// event doAllOutAttack(allOutAttackTr) { if (idleGroup(attackGroup) >= (attackGroup.members / 3)) // make sure at least 30% are idle { if ((allOutAttack != NULLOBJECT) and (not helpingAlly())) { if (!friendlyPlayer(allOutAttack.player)) { if (getDroidCount(me) > 40) // plenty of units. { orderGroupObj(attackGroup, DORDER_ATTACK, allOutAttack); orderGroupLoc(scoutGroup, DORDER_SCOUT, allOutAttack.x, allOutAttack.y); } } else { allOutAttack = NULLOBJECT; } } } } ///////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////// // defending rules // defend attacked objects. event defendWatch(defendWatchTr) { if (baseobj != NULLOBJECT) { if(!friendlyPlayer(baseobj.player)) { if(distBetweenTwoPoints(baseobj.x, baseobj.y, baseX, baseY) <= MAX_DEFENDERS_RADIUS) //don't go too far away from the base { defendObj = baseobj; defendbusy = TRUE; // if not too busy, attack. if (idleGroup(defendGroup) >= (defendGroup.members / 2)) { orderGroupLoc(defendGroup, DORDER_MOVE,defendObj.x,defendObj.y); //cyborg mechanics can't attack (won't move) } if (idleGroup(scoutGroup) >= (scoutGroup.members / 2)) { orderGroupLoc(scoutGroup, DORDER_MOVE,scoutX,scoutY); } } } } } ///////////////////////////////////////////////////////////////////// // defenders return after they are finished. event defendReturn(defendReturnTr) { if( defendbusy and (idleGroup(defendGroup) == (defendGroup.members - defendGroup.members / 12))) { // find a place with no structures nearby buildX = baseX; buildY = baseY; pickStructLocationB(powGen, ref buildX, ref buildY, me, 0); orderGroupLoc(defendGroup, DORDER_MOVE,buildX,buildY); defendbusy = FALSE; } } //returns number of non-idle structures of a certain type function int numStructBusyByType(STRUCTURESTAT _busyStructType) { local int _result; initEnumStruct(FALSE,_busyStructType,me,me); structure = enumStruct(); _result = 0; while(structure != NULLOBJECT) { if(structureComplete(structure)) { if(not structureIdle(structure)) { _result++; } } structure = enumStruct(); } return _result; } ///////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////// // Research Rules Now does true research. // do research event doResearch(doResearchTr) { local int _techIndex,_numResearching; // don't throw in half of your money on research in T3 no bases when we don't have any income yet if (isStructureAvailable(facModule,me) and not havePowerSource()) { setEventTrigger(doResearch, doResearchTr); exit; } _techIndex = 0; //research start _numResearching = numStructBusyByType(resLab); // for every research lab do this.. initEnumStruct(FALSE,resLab,me,me); structure= enumStruct(); count = 0; while(structure != NULLOBJECT) { boolResult = FALSE; //haven't started research for the current resFac if(structureIdle(structure)) { if(structureComplete(structure)) { // first research all technologies necessary for the current research branch while(not boolResult and _techIndex != NONE) //not started researching and still branch tech left to try { _techIndex = findResearch(_techIndex, curTech); if(_techIndex > NONE) { boolResult = pursueResearch(structure,me,tech[curTech][_techIndex]); _techIndex++; //try nect research next time if needed _numResearching++; } } // do common research if(not boolResult) //didn't start branch research { if((maxIdleRes[curTech] == UNLIMITED) or (_numResearching < maxIdleRes[curTech])) { skDoResearch(structure,me,0); _numResearching++; } } } } structure = enumStruct(); } setEventTrigger(doResearch, doResearchTr); } // find next available research of our research branch function int findResearch(int _searchStart, int _techTree) { local int _result; ASSERT(_searchStart >= 0, "findResearch: _searchStart < 0", me); ASSERT(_techTree >= 0, "findResearch: _techTree < 0", me); _result = _searchStart; while(_result < techCount[_techTree]) { if((not researchFinished(tech[_techTree][_result], me)) and (not researchStarted(tech[_techTree][_result], me))) { return _result; //found research } _result++; } return NONE; //not found } ///////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////// // Alliance Rules // form alliances event formAllianceEvent(formAllianceEventTr) { count = 0; while(count < MAX_PLAYERS) { if( count != me ) // if not the only other player and rand2 { if((getDroidCount(me) > 1) and (getDroidCount(count) > 1) ) // not dead { if(random(28) == 1) // bit random { if(not isHumanPlayer(count)) // not human { createAlliance(me,count); allianceTime[count] = gameTime; } } } } count = count + 1; } } ///////////////////////////////////////////////////////////////////// // break the alliance too. event breakAllianceEvent(breakAllianceEventTr) { count = 0; while(count<multiPlayerMaxPlayers) { if( count != me) { if((getDroidCount(me) > 1) and (getDroidCount(count) > 1) ) // not dead { if(allianceExistsBetween(me,count) ) { // check if we're in alliance with any other players. if( (random(30) == 1) and ( (gameTime - allianceTime[count]) > 6000) ) // rand and more than 10 minutes. { allianceTime[count] = gameTime; breakAlliance(me,count); } // rules for breaking alliances with humans. // built within my base if(numStructsInArea(count,minx,miny,maxx,maxy) > 1) { allianceTime[count] = gameTime; breakAlliance(me,count); } // you've got lots of units in my area. if(numDroidsInArea(count,minx,miny,maxx,maxy) > 3) { allianceTime[count] = gameTime; breakAlliance(me,count); } // you've wiped out one of my allies ??. } } } count = count + 1; } } ///////////////////////////////////////////////////////////////////// event formHumanAlliances(humanAllianceTr) { if(count2 == me) // offered to me. { result = 0; result2 = 0; while(result < multiPlayerMaxPlayers) { if(allianceExistsBetween(count,result)) { result2 = result2 + 1; } result = result + 1; } if( result2 < ((multiPlayerMaxPlayers / 2) - 1) ) // not too many already { //not too soon. if((allianceTime[count] == 0) or (gameTime - allianceTime[count] > 1200)) { result = 0; // check forming wont end the game result2 = 0; while(result < multiPlayerMaxPlayers) { while(result2 < multiPlayerMaxPlayers) { if((not allianceExistsBetween(result,result2)) and (getDroidCount(result) > 0) and (getDroidCount(result2) > 0) and (result != result2) ) { if( ((result == count and result2 == count2) or (result2 == count2 and result == count)) ) // ignore the outcome of this alliance { createAlliance(me,count); allianceTime[count] = gameTime; } } result2 = result2 + 1; } result = result + 1; } } } } } ///////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////// // Consolidate Rules // bring forces back together to consolidate attacks event consolidateEvent(consolidateEventTr) { if(not helpingAlly()) { if(random(7) == 1) // order all droids home to rejoin forces.! { // find a place with no structures nearby buildX = baseX; buildY = baseY; pickStructLocationB(powGen, ref buildX, ref buildY, me, 0); orderGroupLoc(scoutGroup, DORDER_MOVE,buildX,buildY); orderGroupLoc(defendGroup, DORDER_MOVE,buildX,buildY); } /* if(attackObj != NULLOBJECT) // consolidate any ongoing attack. { if(!friendlyPlayer(attackObj.player)) { orderGroupLoc(attackGroup, DORDER_SCOUT, attackObj.x, attackObj.y); } else { attackObj = NULLOBJECT; } } else if(allOutAttack == NULLOBJECT) //make sure not allOutAttacking { // find a place with no structures nearby buildX = baseX; buildY = baseY; pickStructLocationB(powGen, ref buildX, ref buildY, me, 0); orderGroupLoc(attackGroup, DORDER_MOVE,buildX,buildY); } */ } } ///////////////////////////////////////////////////////////////////// event difficultyModifier(difficultyModifierTr) { if(not isHumanPlayer(me)) { skDifficultyModifier(me); } } ///////////////////////////////////////////////////////////////////// // vtols. ///////////////////////////////////////////////////////////////////// // build vtol strucutures. event vtolStructs(inactive) { local int _numVtolFacs,_numRearmPads; // got any idle trucks? if (idleGroup(buildGroup) < 1) { exit; } // see how many vtol factories we already have _numVtolFacs = getNumStructures(vtolFactory,me); _numRearmPads = getNumStructures(vtolPad,me); //see if we have enough rearm pads if( _numRearmPads * 4 / 3 <= totalVtols() ) { dbg("NEED REARM PADS", me); buildRearmPads(); } if (_numVtolFacs > 0 and playerPower(me) < LOW_POWER) { exit; // Throttle expansion to avoid waste } if (isStructureAvailable(vtolFactory, me) and _numVtolFacs < maxVtolFacs[curTech]) // if not enough { if (not grabTrucksAndBuild(8, vtolFactory, 1)) { dbg("Failed to build Vtol fac", me); } } } //counts vtols function int totalVtols() { local int _vtolGroup,_totalVtols; _totalVtols = 0; _vtolGroup = 0; while(_vtolGroup < numVtolAttackGroups) { _totalVtols = _totalVtols + vtolAttackGr[_vtolGroup].members; _vtolGroup++; } _totalVtols = _totalVtols + vtolDefendGr.members; return _totalVtols; } function void buildRearmPads() { if (isStructureAvailable(vtolPad, me)) { if (not grabTrucksAndBuild(4, vtolPad, -1)) { dbg("Failed to build vtol pad", me); } } } ///////////////////////////////////////////////////////////////////// // build vtols. event buildVtols(inactive) { // got enough vtols? if((vtolDefendGr.members >= maxVTOLs[curTech]) or (getDroidCount(me) >= MAX_DROIDS)){ dbg("CAN'T BUILD VTOLS - TOO MANY UNITS", me); exit; } if(playerPower(me) > LOW_POWER) { // build vtols initEnumStruct(FALSE,vtolFactory,me,me); structure = enumStruct(); while(structure != NULLOBJECT) { if(structureIdle(structure)) // if factory idle { vtolFactoryBuildVtol(structure); } structure = enumStruct(); } } } function void vtolFactoryBuildVtol(STRUCTURE _factory) { local int _numTemplates,_bestTemplates; if(_factory == NULLOBJECT){ return; } if( structureIdle(_factory) ) { _numTemplates = numVtolTemplates - 1; _bestTemplates = 0; while( (_bestTemplates < 3) and (_numTemplates >= 0) ) { if( skCanBuildTemplate(me,_factory, vtols[_numTemplates]) ) { tmplChoice[_bestTemplates] = vtols[_numTemplates]; _bestTemplates++; } _numTemplates--; } if(_bestTemplates > 0) { buildDroid(tmplChoice[random(_bestTemplates)],_factory,me,1); } } } ///////////////////////////////////////////////////////////////////// // attack with vtols. event vtolAttack(inactive) { local int _groupIndex,_newTargetWeight,_oldTargetWeight; local BASEOBJ _newTarget; local bool _bHaveDefendTarget; local DROID _droid; // if vtol group is not busy.. if( (idleGroup(vtolDefendGr) >= (vtolDefendGr.members / 2)) and (vtolDefendGr.members >= 2) ) { if(attackObj != NULLOBJECT) { if(!friendlyPlayer(attackObj.player)) { orderGroupObj(vtolDefendGr, DORDER_ATTACK, attackObj); // get the attack target. } else { attackObj = NULLOBJECT; } } else { if(defendObj != NULLOBJECT) { orderGroupObj(vtolDefendGr, DORDER_ATTACK,defendObj); // get the defend target } } } //make sure attack vtol groups are not cluttered rearrangeAttackVtols(); //attack vtols _groupIndex = 0; while(_groupIndex < numVtolAttackGroups) { if(vtolAttackGr[_groupIndex].members > 0) { // if our base is in trouble see if we have a target in the base // don't choose new target if already have one _bHaveDefendTarget = FALSE; if((vtolGrAttackObj[_groupIndex] != NULLOBJECT)) { if(defendingOwnBase() and (distBetweenTwoPoints(baseX, baseY, vtolGrAttackObj[_groupIndex].x, vtolGrAttackObj[_groupIndex].y) <= MAX_VTOL_DEFEND_RADIUS)) { _bHaveDefendTarget = TRUE; } // else //reset target if it's not worth it // { // //we don't want to attack enemy heavy tanks outside of our base // if(vtolGrAttackObj[_groupIndex].type == OBJ_DROID) // { // _droid = objToDroid(vtolGrAttackObj[_groupIndex]); // if(_droid.droidType != DROID_CONSTRUCT) // { // vtolGrAttackObj[_groupIndex] = NULLOBJECT; //reset target // _bHaveDefendTarget = FALSE; // } // } // } } //find target in our base if our base is in trouble if(!_bHaveDefendTarget and defendingOwnBase()) { vtolGrAttackObj[_groupIndex] = chooseVtolDefenceTarget(baseX, baseY, MAX_VTOL_DEFEND_RADIUS, FALSE); if(vtolGrAttackObj[_groupIndex] != NULLOBJECT) { dbg("assigned new defence target for group " & _groupIndex, me); _bHaveDefendTarget = TRUE; } } //attack rules if(!_bHaveDefendTarget and (idleGroup(vtolAttackGr[_groupIndex]) >= (vtolAttackGr[_groupIndex].members / 2)) and (vtolAttackGr[_groupIndex].members >= (numAttackVtols * 2 / 3))) { _newTarget = NULLOBJECT; //reset attack targets once in a while if(vtolGrAttackObj[_groupIndex] != NULLOBJECT) { if(random(10) > 7) { vtolGrAttackObj[_groupIndex] = NULLOBJECT; } } //now try to find an attack target if we have no defence target //find best attack target _newTarget = chooseVtolTarget(TRUE); //search for an exclusive target if(_newTarget == NULLOBJECT) { _newTarget = chooseVtolTarget(FALSE); //search for any target } _newTargetWeight = getVtolTargetWeight(_newTarget); _oldTargetWeight = getVtolTargetWeight(vtolGrAttackObj[_groupIndex]); // new one or a much better one if((_newTargetWeight >= (_oldTargetWeight + 20)) or (vtolGrAttackObj[_groupIndex] == NULLOBJECT )) { dbg("choosing new attack object for " & _groupIndex, me); vtolGrAttackObj[_groupIndex] = _newTarget; } } //see if this group has something to attack if(vtolGrAttackObj[_groupIndex] != NULLOBJECT) { if(!friendlyPlayer(vtolGrAttackObj[_groupIndex].player)) { dbg("VTOL Group " & _groupIndex & " attacking", me); if(_DEBUG and (_groupIndex == 0)) { dropBeacon(getPlayerName(me), me, me, vtolGrAttackObj[_groupIndex].x, vtolGrAttackObj[_groupIndex].y, 0); } orderGroupObj(vtolAttackGr[_groupIndex], DORDER_ATTACK, vtolGrAttackObj[_groupIndex]); } else { vtolGrAttackObj[_groupIndex] = NULLOBJECT; } } } _groupIndex++; } } //make sure vtol groups are not cluttered function void rearrangeAttackVtols() { local int _emptyGr,_fillGr; local DROID _droid; _emptyGr = 0; while(_emptyGr < numVtolAttackGroups) { if((vtolAttackGr[_emptyGr].members < numAttackVtols) and //this group is not full (vtolAttackGr[_emptyGr].members > 0)) { //try to make full groups by moving vtols from the last groups _fillGr = _emptyGr + 1; //start from the next group while((_fillGr < numVtolAttackGroups) and (vtolAttackGr[_emptyGr].members < numAttackVtols)) { initIterateGroup(vtolAttackGr[_fillGr]); _droid = iterateGroup(vtolAttackGr[_fillGr]); while((_droid != NULLOBJECT) and (vtolAttackGr[_emptyGr].members < numAttackVtols)) { groupAddDroid(vtolAttackGr[_emptyGr], _droid); //refill the group _droid = iterateGroup(vtolAttackGr[_fillGr]); } _fillGr++; } } _emptyGr++; } } function BASEOBJ chooseVtolDefenceTarget(int _x, int _y, int _range, bool bExclusiveTarget) { local BASEOBJ _target; _target = getClosestEnemy(_x, _y, _range, FALSE, FALSE, me); // make sure no one else is targeting it already if we want exclusive targets if(bExclusiveTarget and vtolTargetAssigned(_target)) { _target = NULLOBJECT; } return _target; } function BASEOBJ chooseVtolTarget(bool bExclusiveTarget) { local int _structTypeIndex,_enemy; local int _bestScore,_tempScore; local BASEOBJ _bestTarget; local STRUCTURE _structure; _bestScore = 0; _bestTarget = NULLOBJECT; _enemy = 0; while(_enemy < MAX_PLAYERS) { if(!friendlyPlayer(_enemy)) { _structTypeIndex = 0; while(_structTypeIndex < numVtolTargets) { initEnumStruct(FALSE,vtolTarget[_structTypeIndex],_enemy,me); _structure = enumStruct(); while(_structure != NULLOBJECT) { // in case we don't want all groups to attack the same target if(not (bExclusiveTarget and vtolTargetAssigned(_structure)) ) { _tempScore = getVtolTargetWeight(_structure); //see if this one is better if(_tempScore > _bestScore) { _bestScore = _tempScore; _bestTarget = _structure; } } _structure = enumStruct(); } _structTypeIndex++; } } _enemy++; } return _bestTarget; } function int getVtolTargetWeight(BASEOBJ _target) { local int _AAPenalty,_numAA,_range,_targetWeight; local int _targetType; local STRUCTURE _structTarget; if(_target == NULLOBJECT) { return 0; } if(_target.type != OBJ_STRUCTURE) { return 0; } _structTarget = objToStructure(_target); _targetWeight = 0; _AAPenalty = 9; //penalty per aa defense _range = AA_THREAT_RANGE; // count enemy AA _numAA = numEnemyAAInRange(_structTarget.x, _structTarget.y, _range); // find tyrget type from stats _targetType = 0; while(_targetType < numVtolTargets) { if(_structTarget.stat == vtolTarget[_targetType]) { _targetWeight = vtolTargetWeight[_targetType] - (_numAA * _AAPenalty); _targetType = numVtolTargets; //exit loop } _targetType++; } // incomplete structures get lower weight if(!structureComplete(_structTarget)) { _targetWeight = _targetWeight / 10; } return _targetWeight; } function int numEnemyAAInRange(int _x, int _y, int _range) { local int _enemy,_numAA; _numAA = 0; _enemy = 0; while(_enemy < MAX_PLAYERS) { if(!friendlyPlayer(_enemy)) { _numAA = _numAA + numAAinRange(_enemy, me, _x, _y, _range); } _enemy++; } return _numAA; } // see if a particular target is already assigned to one of the VTOL attack groups function bool vtolTargetAssigned(BASEOBJ _target) { local int _groupIndex; if(_target == NULLOBJECT) { return FALSE; } _groupIndex = 0; while(_groupIndex < numVtolAttackGroups) { if(_target == vtolGrAttackObj[_groupIndex]) { return TRUE; } _groupIndex++; } return FALSE; } ///////////////////////////////////////////////////////////////////// // watch for incoming vtols event vtolDefend(vtolDefendTr) { local int _numBuilders,_maxBuilders; if(baseobj != NULLOBJECT) { if(baseobj.type == OBJ_DROID) { if(isVtol(objToDroid(baseobj))) { _numBuilders = 0; _maxBuilders = 2; // build defenses. initIterateGroup(buildGroup); // find idle droids in build group. droid = iterateGroup(buildGroup); while( droid != NULLOBJECT) { if( (structure != NULLOBJECT) and (droid.order != DORDER_BUILD) ) { buildX = structure.x; buildY = structure.y; // if ! vtol defense already built... //find best defense we can build. count = 0; count2 = -1; while( count < 9) { if(isStructureAvailable(vtolDefStruct[count],me)) { count2 = count; } count = count + 1; } if(count2 != (-1) ) { boolResult = pickDroidStructLocation(droid, vtolDefStruct[count2], ref buildX, ref buildY, me, 1); if (boolResult == TRUE and (_numBuilders < _maxBuilders)) // build a vtol defense near the attacked struct... { orderDroidStatsLoc(droid, DORDER_BUILD,vtolDefStruct[count2],buildX,buildY); _numBuilders++; } } } droid = iterateGroup(buildGroup); } } } } } ///////////////////////////////////////////////////////////////////// event vtolEnabler(vtolEnablerTr) { if( skVtolEnableCheck(me) ) // check to see if we have vtol technologies. { setEventTrigger(vtolEnabler,inactive); // turn off this event. setEventTrigger(vtolStructs,vtolStructsTr); // activate other vtol functions.. setEventTrigger(buildVtols, buildVtolsTr); setEventTrigger(vtolAttack, vtolAttackTr); dbg("----I CAN USE VTOLS----", me); } } ///////////////////////////////////////////////////////////////////// // HouseKeeping function void shutDownAI() { bRunning = false; setEventTrigger(basedetails, inactive); setEventTrigger(buildDerrick, inactive); setEventTrigger(buildOilDefenseOrRetreat, inactive); setEventTrigger(incendry, inactive); setEventTrigger(buildPowerGenerators, inactive); setEventTrigger(buildBase, inactive); setEventTrigger(buildExpand,inactive); setEventTrigger(upgradeStructures,inactive); setEventTrigger(finishStructs, inactive); setEventTrigger(newfortify, inactive); setEventTrigger(droidBuiltAssign, inactive); setEventTrigger(droidBuilt, inactive); setEventTrigger(structBuilt,inactive); setEventTrigger(droidDestroyed,inactive); setEventTrigger(conDroids,inactive); setEventTrigger(repairDroids,inactive); setEventTrigger(sensorDroids,inactive); setEventTrigger(factoryEvent, inactive); setEventTrigger(cyborgFactoryEvent, inactive); setEventTrigger(chooseScoutArea, inactive); setEventTrigger(expandScoutArea, inactive); setEventTrigger(scoutMain, inactive); setEventTrigger(newObjectReport, inactive); setEventTrigger(takeover, inactive); setEventTrigger(takeoverDefend, inactive); setEventTrigger(useLassat, inactive); setEventTrigger(findEnemy, inactive); setEventTrigger(attackStuff, inactive); setEventTrigger(defendWatch, inactive); setEventTrigger(defendReturn, inactive); setEventTrigger(doResearch, inactive); setEventTrigger(formAllianceEvent, inactive); setEventTrigger(breakAllianceEvent, inactive); setEventTrigger(formHumanAlliances, inactive); setEventTrigger(consolidateEvent, inactive); setEventTrigger(vtolStructs,inactive); setEventTrigger(buildVtols,inactive); setEventTrigger(vtolAttack,inactive); setEventTrigger(vtolDefend,inactive); setEventTrigger(vtolEnabler,inactive); setEventTrigger(beaconEv, inactive); setEventTrigger(multiMsgEv, inactive); setEventTrigger(manageAllyHelp, inactive); setEventTrigger(everySecEv, inactive); setEventTrigger(watchBaseThreat, inactive); setEventTrigger(manageDefendLocationEv, inactive); setEventTrigger(structureDestroyed,inactive); setEventTrigger(rebuildStructureEv,inactive); setEventTrigger(startLevel, inactive); setEventTrigger(arrived, inactive); setEventTrigger(checkResearch, inactive); } function void reassignAI() { bRunning = true; setEventTrigger(basedetails,basedetailsTr); setEventTrigger(buildDerrick,buildDerrickTr); setEventTrigger(buildOilDefenseOrRetreat,buildOilDefenseOrRetreatTr); setEventTrigger(incendry,incendryTr); setEventTrigger(buildPowerGenerators,buildPowerGeneratorsTr); setEventTrigger(buildBase,buildBaseTr ); setEventTrigger(buildExpand,buildExpandTr ); setEventTrigger(upgradeStructures,upgradeStructuresTr ); setEventTrigger(finishStructs,finishStructsTr ); setEventTrigger(newfortify,fortifyTr ); setEventTrigger(droidBuiltAssign,droidBuiltTr); setEventTrigger(droidBuilt,droidBuiltTr); setEventTrigger(droidDestroyed,droidDestroyedTr); setEventTrigger(conDroids,conDroidsTr); setEventTrigger(repairDroids,repairDroidsTr); setEventTrigger(sensorDroids,sensorDroidsTr); setEventTrigger(factoryEvent,factoryEventTr); setEventTrigger(cyborgFactoryEvent,cyborgFactoryEventTr); setEventTrigger(chooseScoutArea,chooseScoutAreaTr); setEventTrigger(expandScoutArea,expandScoutAreaTr); setEventTrigger(scoutMain,scoutMainTr); setEventTrigger(newObjectReport,newObjectReportTr); setEventTrigger(takeover,takeoverTr); setEventTrigger(useLassat,useLassatTr); setEventTrigger(findEnemy,attackStuffTr); setEventTrigger(attackStuff,attackStuffTr); setEventTrigger(doAllOutAttack,allOutAttackTr); setEventTrigger(defendWatch,defendWatchTr); setEventTrigger(defendReturn,defendReturnTr); setEventTrigger(doResearch,doResearchTr); setEventTrigger(formAllianceEvent,formAllianceEventTr); setEventTrigger(breakAllianceEvent,breakAllianceEventTr); setEventTrigger(consolidateEvent,consolidateEventTr); setEventTrigger(vtolStructs,inactive); setEventTrigger(buildVtols,inactive); setEventTrigger(vtolAttack,inactive); setEventTrigger(vtolAttack, vtolAttackTr); setEventTrigger(vtolDefend,vtolDefendTr); setEventTrigger(vtolEnabler,vtolEnablerTr); setEventTrigger(formHumanAlliances,humanAllianceTr); setEventTrigger(multiMsgEv, multiMsgTr); setEventTrigger(beaconEv, beaconTr); setEventTrigger(watchBaseThreat, watchBaseThreatTr); setEventTrigger(manageAllyHelp, manageAllyHelpTr); setEventTrigger(everySecEv, everySec); setEventTrigger(manageDefendLocationEv, manageDefendLocationTr); setEventTrigger(structBuilt, structBuiltTr); setEventTrigger(structureDestroyed, structureDestroyedTr); setEventTrigger(rebuildStructureEv, rebuildStructureTr); setEventTrigger(startLevel, startLevelTr); setEventTrigger(arrived, reachedTr); setEventTrigger(checkResearch, checkResearchTr); } /* Returns true if we just received a beacon from a certain player */ function bool haveBeacon(int _player) { if((tBeacon[_player] > 0) and (not beaconTimeout(_player))) { return TRUE; //have beacon for this player } return FALSE; } /* See if last beacon was placed long ago */ function bool beaconTimeout(int _player) { if((tBeacon[_player] > 0) and ((tBeacon[_player] + BEACON_TIMEOUT) < (gameTime / 10))) //not too long ago { return TRUE; //this beacon is still 'fresh' } return FALSE; } /* Deal with beacons */ event beaconEv(beaconTr) { local int _players; local string _processedString; if(_DEBUG) debug(me & ") beaconEv: from " & sender); ASSERT(sender >= 0 and sender < MAX_PLAYERS, "beaconEv: sender out of bounds: " & sender , me); beaconX[sender] = x; beaconY[sender] = y; tBeacon[sender] = gameTime / 10; processCommand(message, sender, TRUE); } /* Deal with a chat message */ event multiMsgEv(multiMsgTr) { if(_DEBUG) debug(me & ") multiMsgEv: from " & sender); if(not allianceExistsBetween(me, sender)){ exit; } if(sender == me){ exit; } processCommand(message, sender, FALSE); } /* Process multiplayer messages */ function void processCommand(string _message, int _sender, bool _bBlipMessage) { local int _numMsgs,_curMsg,_addressedPlayers,_x,_y; local string _msg,_processedString; /* Extract semantic information */ _curMsg = 0; _numMsgs = processChatMsg(_message); debug(me & ") processCommand: '" & _message & "' from " & _sender); dbg("processCommand: '" & _message & "' from " & _sender, me); dbg("got " & _numMsgs & " commands", me); /* Process all messages */ while(_curMsg < _numMsgs) { if(chatCmdIsPlayerAddressed(_curMsg, me)) { dbg("i'm addressed", me); _msg = getChatCmdDescription(_curMsg); /* Someone requested help */ if(_msg == R_REQUEST_HELP) { dbg("'help' command", me); if(haveBeacon(_sender)) { dbg("got beacon", me); _x = beaconX[_sender]; _y = beaconY[_sender]; if(attemptToHelp(_sender, _x, _y)) { messagePlayer(ALL_ALLIES, m_affirmative(), MAX_PROBABILITY); } } else { /* Ask player to drop a beacon so we would know where to help */ _addressedPlayers = setBit(0, _sender, TRUE); messagePlayerAddressed(ALL_ALLIES, _addressedPlayers, R_REQUEST_BEACON); } } /* Someone requested a beacon from us - * did we request help and our beacon timed out?? */ else if(_msg == M_REQUEST_BEACON) { /* If our base is really in trouble drop a beacon for the requester again */ if(baseInTrouble()){ dropBeacon(getPlayerName(me), _sender, me, baseX, baseY, 0); } } else if(_msg == R_REPORT_SAFETY) { dbg("helping " & lastHelpPlayer, me); /* Make sure we were helping him */ if(helpingAlly() and (lastHelpPlayer == _sender)) { stopHelpingAlly(); messagePlayer(ALL_ALLIES, m_affirmative(), MAX_PROBABILITY); } else if(defendingOwnBase()) //if we are in trouble re-request help { requestHelp(baseX, baseY); } } else { dbg("unknown message", me); } } else { dbg("i'm not addressed", me); } _curMsg++; } } function bool attemptToHelp(int _playerToHelp, int _x, int _y) { local bool _bHelpingMyself; if(_playerToHelp < 0 or _playerToHelp >= MAX_PLAYERS){ return FALSE; } if(_x <= 0 or _y <= 0){ return FALSE; } dbg("attemptToHelp - checking", me); _bHelpingMyself = (_playerToHelp == me); /* Can only help allies and myself */ if(not friendlyPlayer(_playerToHelp)){ return FALSE; } if(_bHelpingMyself or !helpingAlly() or (lastHelpPlayer == _playerToHelp) ) //if not helping any other ally or it's me who needs help { dbg("not busy helping", me); if(haveHelpers() or _DEBUG) { dbg("got attackers", me); //if(allyBaseAtLoc(_playerToHelp, _x, _y)) //is he just trying to misuse us? //{ helpPlayer(_playerToHelp, _x, _y); return TRUE; //} //else //{ // dbg("ally needs no help", me); // messagePlayer(ALL_ALLIES, M_ANNOYED, MAX_PROBABILITY / 2); //} } else { messagePlayer(ALL_ALLIES, M_HELP_NO_UNITS, MAX_PROBABILITY); } } else if((lastHelpPlayer >= 0) and (lastHelpPlayer < MAX_PLAYERS)) { if(!_bHelpingMyself){ messagePlayer(ALL_ALLIES, "helping " & getPlayerName(lastHelpPlayer) & " already", MAX_PROBABILITY); } } return FALSE; } /* Start helping player */ function void helpPlayer(int _playerToHelp, int _helpX, int _helpY) { local int _tTravelTime; dbg("helping " & _playerToHelp, me); if(_DEBUG) debug(me & ") helpPlayer: '" & _playerToHelp); /* Move scoutes to attackers */ groupAddGroup(attackGroup, scoutGroup); //Calculate travel time, assume ~ 150 tiles in 4 minutes if(attackGroup.members == 0){ _tTravelTime = (int)((float)(distBetweenTwoPoints(baseX, baseY, _helpX, _helpY) / 128 ) * 1.7); }else{ _tTravelTime = (int)((float)(distBetweenTwoPoints(attackGroup.x, attackGroup.y, _helpX, _helpY) / 128 ) * 1.7); } tHelp = gameTime / 10; tHelpTimeout = (gameTime / 10) + BASE_DEFEND_DURATION + _tTravelTime; lastHelpPlayer = _playerToHelp; helpX = _helpX; helpY = _helpY; /* Scouts and attackers go to help */ defendLocation(_helpX, _helpY, tHelpTimeout, (_playerToHelp == me)); } /* Returns a random affirmative responce */ function string m_affirmative() { local int _rnd; _rnd = random(4); if(_rnd == 3) { return M_AFFIRMATIVE_ROGER; } return M_AFFIRMATIVE_OK; } /* See if there are any base structures belonging to ally at a certain location */ function bool allyBaseAtLoc(int _ally, int _x, int _y) { local int _structIndex; if(_x <= 0 or _y <= 0){ return FALSE; } if(_ally < 0 or _ally >= MAX_PLAYERS){ return FALSE; } _structIndex = 0; while(_structIndex < numBaseStruct) { if(numStructsByStatInRange(baseStruct[_structIndex], _x, _y, (7 * 128), me, _ally) > 0 ) { return TRUE; } _structIndex++; } return FALSE; } event manageAllyHelp(manageAllyHelpTr) { if(helpingAlly()) { if(canStopHelpingAlly()) { stopHelpingAlly(); } } } event everySecEv(everySec) { /* Check if we were helping long enough */ if(helpingAlly()) { if(helpAllyTimeout()) { stopHelpingAlly(); } } if(defendingLocation()) { if(defendLocationTimeout()) { stopDefendingLocation(); } } } /* Do we have any units we can send to help ally ? */ function bool haveHelpers() { if(attackGroup.members == 0){ return FALSE; } return TRUE; } function bool helpingAlly() { if(lastHelpPlayer >= 0){ return TRUE; } return FALSE; } /* Returns true if we were helping long enough */ function bool helpAllyTimeout() { if(tHelpTimeout < (gameTime / 10) ){ return TRUE; } return FALSE; } function bool canStopHelpingAlly() { if(lastHelpPlayer < 0) { ASSERT(FALSE, "canStopHelpingAlly: lastHelpPlayer < 0", me); return TRUE; } /* Were helping long enough or someone's backstabbing */ if(!friendlyPlayer(lastHelpPlayer)){ return TRUE; } /* Nothing to defend anymore */ //if(!allyBaseAtLoc(lastHelpPlayer, helpX, helpY)){ // return TRUE; //} return FALSE; } function void stopHelpingAlly() { dbg("stopped helping", me); tHelp = -1; tHelpTimeout = -1; lastHelpPlayer = -1; helpX = -1; helpY = -1; stopDefendingLocation(); } /* Send a multiplayer message to an ally */ function void messagePlayer(int _playerToMessage, string _message, int _probability) { local int _player; ASSERT(_playerToMessage >= -1 && _playerToMessage < MAX_PLAYERS, "messagePlayer: player out of bounds: " & _playerToMessage, me); // throw the dice if( random(MAX_PROBABILITY) >= _probability ){ return; } _player = 0; if(_playerToMessage == ALL_ALLIES) //everyone { while(_player < MAX_PLAYERS) { /* Send message (allies only)) */ if(allianceExistsBetween(me, _player)) { msg(_message, me, _player); } _player++; } } else //a certain player { /* Send message (allies only)) */ if(allianceExistsBetween(me, _playerToMessage)) { msg(_message, me, _playerToMessage); } } } function int numBitsSet(int _integer) { local int _position,_result; _position = 0; _result = 0; while(_position < 8) { if(getBit(_integer, _position)) { _result++; } _position++; } return _result; } /* Send a multiplayer message, addressing some player(s) */ function void messagePlayerAddressed(int _playerToMessage, int _playersToAddress, string _message) { local int _player,_totalAddressed,_curAddressed; local string _adrMessage; _totalAddressed = numBitsSet(_playersToAddress); ASSERT(_totalAddressed > 0, "messagePlayerAddressed: no players addressed", me); _adrMessage = " "; _player = 0; _curAddressed = 0; while(_player < MAX_PLAYERS) { if(getBit(_playersToAddress, _player)) { _curAddressed++; _adrMessage = _adrMessage & getPlayerName(_player); //if(_totalAddressed == 1){ //one only // _adrMessage = getPlayerName(_player); //}else if(_totalAddressed > 1) { if(_curAddressed == _totalAddressed){ //end _adrMessage = _adrMessage & " and " & getPlayerName(_player); }else{ _adrMessage = _adrMessage & ", " & getPlayerName(_player); } } } _player++; } _message = _adrMessage & " " & _message; //Now send the message to all players addressed messagePlayer(_playerToMessage, _message, MAX_PROBABILITY); } /* Returns true if we can see our allies on the map */ function bool canSeeAllies() { local STRUCTURE _uplink; /* Can see allies when team mode is on */ if(multiPlayerAlliancesType == ALLIANCES_TEAMS) { return TRUE; } /* Can see whole map if we have uplink */ _uplink = getStructure(uplink, me); if(_uplink != NULLOBJECT) { /* Make sure finished building */ if(structureComplete(_uplink)) { return TRUE; } } return FALSE; } function bool defendingOwnBase() { if(helpingAlly() && lastHelpPlayer == me){ return TRUE; } return FALSE; } /* Call for help when our base is in danger */ event watchBaseThreat(watchBaseThreatTr) { /* See if we can stop defending */ if(defendingOwnBase()) { if(numEnemiesInBase(FALSE) == 0) { stopHelpingAlly(); //stop defending our own base /* Let allies know we don't need their help anymore */ messagePlayer(ALL_ALLIES, R_REPORT_SAFETY, MAX_PROBABILITY); exit; } } /* See if our base is in trouble and we need help */ if(baseInTrouble()) { if(!defendingOwnBase()) //make sure not already defending the base { if(_DEBUG) debug(me & ") watchBaseThreat: base in trouble"); dbg("watchBaseThreat: base in trouble", me); /* Bring our forces back if needed */ if(helpingAlly()) { stopHelpingAlly(); } /* Defend my own base */ helpPlayer(me, baseX, baseY); } /* Request help once in a while */ requestHelp(baseX, baseY); exit; } } function int numAlliesInBase(bool _bVtols) { local int _numAllies; _numAllies = numFriendlyWeapDroidsInRange(me, baseX, baseY, W_BASE_THREAT_RANGE, _bVtols); _numAllies = _numAllies + numFriendlyWeapStructsInRange(me, baseX, baseY, W_BASE_THREAT_RANGE, true) / 3; return _numAllies; } function int numEnemiesInBase(bool _bVtols) { local int _numEnemies; _numEnemies = numEnemyWeapDroidsInRange(me, baseX, baseY, W_BASE_THREAT_RANGE, _bVtols); _numEnemies = _numEnemies + numEnemyWeapStructsInRange(me, baseX, baseY, W_BASE_THREAT_RANGE, true) / 4; return _numEnemies; } /* Returns true if our base is in trouble */ function bool baseInTrouble() { local int _enemyForce,_friendlyForce; _friendlyForce = numAlliesInBase(FALSE); _enemyForce = numEnemiesInBase(FALSE); /* See if we are in trouble */ if((_enemyForce > 0) && (_enemyForce >= _friendlyForce)){ dbg("baseInTrouble: " & _enemyForce & " >= " & _friendlyForce, me); return TRUE; } return FALSE; } /* Request help from allies */ function void requestHelp(int _helpX, int _helpY) { /* Don't do this too frequently */ if(tLastHelpRequest + HELP_REQUEST_INTERVAL > (gameTime / 10) ){ return; } doRequestHelp(_helpX, _helpY); } function void doRequestHelp(int _helpX, int _helpY) { local int _ally; /* Remember when we requested help last time */ tLastHelpRequest = gameTime / 10; /* Drop beacon for all allies so they would know where to help */ _ally = 0; while(_ally < MAX_PLAYERS) { if(allianceExistsBetween(me, _ally)){ if(_DEBUG) debug(me & ") requestHelp: " & _ally); dropBeacon(getPlayerName(me), _ally, me, _helpX, _helpY, 0); } _ally++; } /* Now send message with help request */ messagePlayer(ALL_ALLIES, M_REQUEST_HELP, MAX_PROBABILITY); } function void defendLocation(int _defendX, int _defendY, int _tDefendTimeout, bool _bMove) { local int defendRadius; defendRadius = 25 * TILE; dbg("starting defending for " & _tDefendTimeout - (gameTime / 10) & " secs, with defend radius " & defendRadius, me); defendX = _defendX; defendY = _defendY; tDefendStart = gameTime / 10; /* Should already include travel time */ tDefendTimeout = _tDefendTimeout; /* See if we have to move or scout */ defendMoveType = DORDER_SCOUT; if(_bMove){ defendMoveType = DORDER_MOVE; } /* Send attackers */ if(attackGroup.members > 0) { if(distBetweenTwoPoints(attackGroup.x, attackGroup.y, _defendX, _defendY) > defendRadius) { orderGroupLoc(attackGroup, defendMoveType, _defendX, _defendY); } } setEventTrigger(manageDefendLocationEv, manageDefendLocationTr); } function void stopDefendingLocation() { dbg("stopped defending location", me); defendX = -1; defendY = -1; tDefendStart = -1; tDefendTimeout = -1; defendMoveType = -1; setEventTrigger(manageDefendLocationEv, inactive); orderGroupLoc(attackGroup, DORDER_SCOUT,baseX,baseY); } function bool defendingLocation() { if(defendX > 0 and defendY > 0){ return TRUE; } return FALSE; } event manageDefendLocationEv(inactive) { local int defendRadius; local DROID _droid; if (not defendingLocation()) { exit; } defendRadius = 15 * TILE; dbg("manageDefendLocationEv", me); ASSERT(defendMoveType == DORDER_MOVE || defendMoveType == DORDER_SCOUT, "manageDefendLocationEv: wrong move order:" & defendMoveType, me); ASSERT(defendX > 0 && defendY > 0, "manageDefendLocationEv: x/y coordinates:" & defendX & "/" & defendY, me); /* Collect attackers */ initIterateGroup(attackGroup); _droid = iterateGroup(attackGroup); while(_droid != NULLOBJECT) { if(distBetweenTwoPoints(_droid.x,_droid.y,defendX,defendY) > defendRadius) //too far from defend location { if(distBetweenTwoPoints(_droid.orderx,_droid.ordery,defendX,defendY) > defendRadius) //not already on its way to the defend location { orderDroidLoc(_droid, defendMoveType, defendX, defendY); } } _droid = iterateGroup(attackGroup); } } function bool defendLocationTimeout() { if(tDefendTimeout < (gameTime / 10) ){ return TRUE; } return FALSE; } /* Returns true if player in question is my ally or if it's me */ function bool friendlyPlayer(int _playerToCheck) { if(allianceExistsBetween(_playerToCheck, me) or (_playerToCheck == me)){ return TRUE; } return FALSE; } function bool insideBase(int _x, int _y) { if(_x < minx){ return FALSE; } if(_x > maxx){ return FALSE; } if(_y < miny){ return FALSE; } if(_y > maxy){ return FALSE; } return TRUE; } event watchMenu(everySec) { if(_DEBUG) { if(vtolGrAttackObj[0] == NULLOBJECT){ setDebugMenuEntry("0 - " & vtolAttackGr[0].members, 0); }else{ setDebugMenuEntry("0 " & vtolAttackGr[0].members & " - " & (vtolGrAttackObj[0].x / TILE) & "-" & (vtolGrAttackObj[0].y / TILE), 0); } if(vtolGrAttackObj[1] == NULLOBJECT){ setDebugMenuEntry("1 - " & vtolAttackGr[1].members, 1); }else{ setDebugMenuEntry("1 " & vtolAttackGr[1].members & " - " & (vtolGrAttackObj[1].x / TILE) & "-" & (vtolGrAttackObj[1].y / TILE), 1); } if(vtolGrAttackObj[2] == NULLOBJECT){ setDebugMenuEntry("2 - " & vtolAttackGr[2].members, 2); }else{ setDebugMenuEntry("2 " & vtolAttackGr[2].members & " - " & (vtolGrAttackObj[2].x / TILE) & "-" & (vtolGrAttackObj[2].y / TILE), 2); } if(vtolGrAttackObj[3] == NULLOBJECT){ setDebugMenuEntry("3 - " & vtolAttackGr[3].members, 3); }else{ setDebugMenuEntry("3 " & vtolAttackGr[3].members & " - " & (vtolGrAttackObj[3].x / TILE) & "-" & (vtolGrAttackObj[3].y / TILE), 3); } if(vtolGrAttackObj[4] == NULLOBJECT){ setDebugMenuEntry("4 - " & vtolAttackGr[4].members, 4); }else{ setDebugMenuEntry("4 " & vtolAttackGr[4].members & " - " & (vtolGrAttackObj[4].x / TILE) & "-" & (vtolGrAttackObj[4].y / TILE), 4); } if(vtolGrAttackObj[5] == NULLOBJECT){ setDebugMenuEntry("5 - " & vtolAttackGr[5].members, 5); }else{ setDebugMenuEntry("5 " & vtolAttackGr[5].members & " - " & (vtolGrAttackObj[5].x / TILE) & "-" & (vtolGrAttackObj[5].y / TILE), 5); } if(vtolGrAttackObj[6] == NULLOBJECT){ setDebugMenuEntry("6 - " & vtolAttackGr[6].members, 6); }else{ setDebugMenuEntry("6 " & vtolAttackGr[6].members & " - " & (vtolGrAttackObj[6].x / TILE) & "-" & (vtolGrAttackObj[6].y / TILE), 6); } if(vtolGrAttackObj[7] == NULLOBJECT){ setDebugMenuEntry("7 - " & vtolAttackGr[7].members, 7); }else{ setDebugMenuEntry("7 " & vtolAttackGr[7].members & " - " & (vtolGrAttackObj[7].x / TILE) & "-" & (vtolGrAttackObj[7].y / TILE), 7); } if(vtolGrAttackObj[8] == NULLOBJECT){ setDebugMenuEntry("8 - " & vtolAttackGr[8].members, 8); }else{ setDebugMenuEntry("8 " & vtolAttackGr[8].members & " - " & (vtolGrAttackObj[8].x / TILE) & "-" & (vtolGrAttackObj[8].y / TILE), 8); } if(vtolGrAttackObj[9] == NULLOBJECT){ setDebugMenuEntry("9 - " & vtolAttackGr[9].members, 9); }else{ setDebugMenuEntry("9 " & vtolAttackGr[9].members & " - " & (vtolGrAttackObj[9].x / TILE) & "-" & (vtolGrAttackObj[9].y / TILE), 9); } if(vtolGrAttackObj[10] == NULLOBJECT){ setDebugMenuEntry("10 - " & vtolAttackGr[10].members, 10); }else{ setDebugMenuEntry("10 " & vtolAttackGr[10].members & " - " & (vtolGrAttackObj[10].x / TILE) & "-" & (vtolGrAttackObj[10].y / TILE), 10); } if(vtolGrAttackObj[11] == NULLOBJECT){ setDebugMenuEntry("11 - " & vtolAttackGr[11].members, 11); }else{ setDebugMenuEntry("11 " & vtolAttackGr[11].members & " - " & (vtolGrAttackObj[11].x / TILE) & "-" & (vtolGrAttackObj[11].y / TILE), 11); } if(vtolGrAttackObj[12] == NULLOBJECT){ setDebugMenuEntry("12 - " & vtolAttackGr[12].members, 12); }else{ setDebugMenuEntry("12 " & vtolAttackGr[12].members & " - " & (vtolGrAttackObj[12].x / TILE) & "-" & (vtolGrAttackObj[12].y / TILE), 12); } if(vtolGrAttackObj[13] == NULLOBJECT){ setDebugMenuEntry("13 - " & vtolAttackGr[13].members, 13); }else{ setDebugMenuEntry("13 " & vtolAttackGr[13].members & " - " & (vtolGrAttackObj[13].x / TILE) & "-" & (vtolGrAttackObj[13].y / TILE), 13); } if(vtolGrAttackObj[14] == NULLOBJECT){ setDebugMenuEntry("14 - " & vtolAttackGr[14].members, 14); }else{ setDebugMenuEntry("14 " & vtolAttackGr[14].members & " - " & (vtolGrAttackObj[14].x / TILE) & "-" & (vtolGrAttackObj[14].y / TILE), 14); } if(vtolGrAttackObj[15] == NULLOBJECT){ setDebugMenuEntry("15 - " & vtolAttackGr[15].members, 15); }else{ setDebugMenuEntry("15 " & vtolAttackGr[15].members & " - " & (vtolGrAttackObj[15].x / TILE) & "-" & (vtolGrAttackObj[15].y / TILE), 15); } if(vtolGrAttackObj[16] == NULLOBJECT){ setDebugMenuEntry("16 - " & vtolAttackGr[16].members, 16); }else{ setDebugMenuEntry("16 " & vtolAttackGr[16].members & " - " & (vtolGrAttackObj[16].x / TILE) & "-" & (vtolGrAttackObj[16].y / TILE), 16); } if(vtolGrAttackObj[17] == NULLOBJECT){ setDebugMenuEntry("17 - " & vtolAttackGr[17].members, 17); }else{ setDebugMenuEntry("17 " & vtolAttackGr[17].members & " - " & (vtolGrAttackObj[17].x / TILE) & "-" & (vtolGrAttackObj[17].y / TILE), 17); } if(vtolGrAttackObj[18] == NULLOBJECT){ setDebugMenuEntry("18 - " & vtolAttackGr[18].members, 18); }else{ setDebugMenuEntry("18 " & vtolAttackGr[18].members & " - " & (vtolGrAttackObj[18].x / TILE) & "-" & (vtolGrAttackObj[18].y / TILE), 18); } if(vtolGrAttackObj[19] == NULLOBJECT){ setDebugMenuEntry("19 - " & vtolAttackGr[19].members, 19); }else{ setDebugMenuEntry("19 " & vtolAttackGr[19].members & " - " & (vtolGrAttackObj[19].x / TILE) & "-" & (vtolGrAttackObj[19].y / TILE), 19); } if(vtolGrAttackObj[20] == NULLOBJECT){ setDebugMenuEntry("20 - " & vtolAttackGr[20].members, 20); }else{ setDebugMenuEntry("20 " & vtolAttackGr[20].members & " - " & (vtolGrAttackObj[20].x / TILE) & "-" & (vtolGrAttackObj[20].y / TILE), 20); } if(vtolGrAttackObj[21] == NULLOBJECT){ setDebugMenuEntry("21 - " & vtolAttackGr[21].members, 21); }else{ setDebugMenuEntry("21 " & vtolAttackGr[21].members & " - " & (vtolGrAttackObj[21].x / TILE) & "-" & (vtolGrAttackObj[21].y / TILE), 21); } if(vtolGrAttackObj[22] == NULLOBJECT){ setDebugMenuEntry("22 - " & vtolAttackGr[22].members, 22); }else{ setDebugMenuEntry("22 " & vtolAttackGr[22].members & " - " & (vtolGrAttackObj[22].x / TILE) & "-" & (vtolGrAttackObj[22].y / TILE), 22); } if(vtolGrAttackObj[23] == NULLOBJECT){ setDebugMenuEntry("23 - " & vtolAttackGr[23].members, 23); }else{ setDebugMenuEntry("23 " & vtolAttackGr[23].members & " - " & (vtolGrAttackObj[23].x / TILE) & "-" & (vtolGrAttackObj[23].y / TILE), 23); } if(vtolGrAttackObj[24] == NULLOBJECT){ setDebugMenuEntry("24 - " & vtolAttackGr[24].members, 24); }else{ setDebugMenuEntry("24 " & vtolAttackGr[24].members & " - " & (vtolGrAttackObj[24].x / TILE) & "-" & (vtolGrAttackObj[24].y / TILE), 24); } if(vtolGrAttackObj[25] == NULLOBJECT){ setDebugMenuEntry("25 - " & vtolAttackGr[25].members, 25); }else{ setDebugMenuEntry("25 " & vtolAttackGr[25].members & " - " & (vtolGrAttackObj[25].x / TILE) & "-" & (vtolGrAttackObj[25].y / TILE), 25); } if(vtolGrAttackObj[26] == NULLOBJECT){ setDebugMenuEntry("26 - " & vtolAttackGr[26].members, 26); }else{ setDebugMenuEntry("26 " & vtolAttackGr[26].members & " - " & (vtolGrAttackObj[26].x / TILE) & "-" & (vtolGrAttackObj[26].y / TILE), 26); } if(vtolGrAttackObj[27] == NULLOBJECT){ setDebugMenuEntry("27 - " & vtolAttackGr[27].members, 27); }else{ setDebugMenuEntry("27 " & vtolAttackGr[27].members & " - " & (vtolGrAttackObj[27].x / TILE) & "-" & (vtolGrAttackObj[27].y / TILE), 27); } if(vtolGrAttackObj[28] == NULLOBJECT){ setDebugMenuEntry("28 - " & vtolAttackGr[28].members, 28); }else{ setDebugMenuEntry("28 " & vtolAttackGr[28].members & " - " & (vtolGrAttackObj[28].x / TILE) & "-" & (vtolGrAttackObj[28].y / TILE), 28); } if(vtolGrAttackObj[29] == NULLOBJECT){ setDebugMenuEntry("29 - " & vtolAttackGr[29].members, 29); }else{ setDebugMenuEntry("29 " & vtolAttackGr[29].members & " - " & (vtolGrAttackObj[29].x / TILE) & "-" & (vtolGrAttackObj[29].y / TILE), 29); } if(vtolGrAttackObj[30] == NULLOBJECT){ setDebugMenuEntry("30 - " & vtolAttackGr[30].members, 30); }else{ setDebugMenuEntry("30 " & vtolAttackGr[30].members & " - " & (vtolGrAttackObj[30].x / TILE) & "-" & (vtolGrAttackObj[30].y / TILE), 30); } if(vtolGrAttackObj[31] == NULLOBJECT){ setDebugMenuEntry("31 - " & vtolAttackGr[31].members, 31); }else{ setDebugMenuEntry("31 " & vtolAttackGr[31].members & " - " & (vtolGrAttackObj[31].x / TILE) & "-" & (vtolGrAttackObj[31].y / TILE), 31); } if(vtolGrAttackObj[32] == NULLOBJECT){ setDebugMenuEntry("32 - " & vtolAttackGr[32].members, 32); }else{ setDebugMenuEntry("32 " & vtolAttackGr[32].members & " - " & (vtolGrAttackObj[32].x / TILE) & "-" & (vtolGrAttackObj[32].y / TILE), 32); } if(vtolGrAttackObj[33] == NULLOBJECT){ setDebugMenuEntry("33 - " & vtolAttackGr[33].members, 33); }else{ setDebugMenuEntry("33 " & vtolAttackGr[33].members & " - " & (vtolGrAttackObj[33].x / TILE) & "-" & (vtolGrAttackObj[33].y / TILE), 33); } if(vtolGrAttackObj[34] == NULLOBJECT){ setDebugMenuEntry("34 - " & vtolAttackGr[34].members, 34); }else{ setDebugMenuEntry("34 " & vtolAttackGr[34].members & " - " & (vtolGrAttackObj[34].x / TILE) & "-" & (vtolGrAttackObj[34].y / TILE), 34); } if(vtolGrAttackObj[35] == NULLOBJECT){ setDebugMenuEntry("35 - " & vtolAttackGr[35].members, 35); }else{ setDebugMenuEntry("35 " & vtolAttackGr[35].members & " - " & (vtolGrAttackObj[35].x / TILE) & "-" & (vtolGrAttackObj[35].y / TILE), 35); } if(vtolGrAttackObj[36] == NULLOBJECT){ setDebugMenuEntry("36 - " & vtolAttackGr[36].members, 36); }else{ setDebugMenuEntry("36 " & vtolAttackGr[36].members & " - " & (vtolGrAttackObj[36].x / TILE) & "-" & (vtolGrAttackObj[36].y / TILE), 36); } if(vtolGrAttackObj[37] == NULLOBJECT){ setDebugMenuEntry("37 - " & vtolAttackGr[37].members, 37); }else{ setDebugMenuEntry("37 " & vtolAttackGr[37].members & " - " & (vtolGrAttackObj[37].x / TILE) & "-" & (vtolGrAttackObj[37].y / TILE), 37); } if(vtolGrAttackObj[38] == NULLOBJECT){ setDebugMenuEntry("38 - " & vtolAttackGr[38].members, 38); }else{ setDebugMenuEntry("38 " & vtolAttackGr[38].members & " - " & (vtolGrAttackObj[38].x / TILE) & "-" & (vtolGrAttackObj[38].y / TILE), 38); } if(vtolGrAttackObj[39] == NULLOBJECT){ setDebugMenuEntry("39 - " & vtolAttackGr[39].members, 39); }else{ setDebugMenuEntry("39 " & vtolAttackGr[39].members & " - " & (vtolGrAttackObj[39].x / TILE) & "-" & (vtolGrAttackObj[39].y / TILE), 39); } /* setDebugMenuEntry("total " & countRebuildStruct, 0); setDebugMenuEntry("x1=" & rebuildStructX[0], 1); setDebugMenuEntry("y1=" & rebuildStructY[0], 2); setDebugMenuEntry("x2=" & rebuildStructX[1], 3); setDebugMenuEntry("y2=" & rebuildStructY[1], 4); setDebugMenuEntry("x3=" & rebuildStructX[2], 5); setDebugMenuEntry("y3=" & rebuildStructY[2], 6); setDebugMenuEntry("x4=" & rebuildStructX[3], 7); setDebugMenuEntry("y4=" & rebuildStructY[3], 8);*/ } } //--------------------------------------------------------------- //Returns how many droids are already on the way to build the //same structure on the same spot (like helpbuild) //--------------------------------------------------------------- function int numBuildSameBuilding(STRUCTURESTAT _checkStat, int _x, int _y) { local int _numSameBuilding; local DROID _truck; _numSameBuilding = 0; initIterateGroup(buildGroup); _truck = iterateGroup(buildGroup); while(_truck != NULLOBJECT) { if((_truck.order == DORDER_BUILD) or (_truck.order == DORDER_HELPBUILD) or (_truck.order == DORDER_LINEBUILD)) { if((_checkStat == NULLSTRUCTURESTAT) or (_truck.stat == _checkStat)) //Same struct type { //Within some range if((_x < 0) or (distBetweenTwoPoints(_x, _y, _truck.orderx , _truck.ordery) <= TILE)) { _numSameBuilding++; } } } _truck = iterateGroup(buildGroup); } return _numSameBuilding; } // returns number of droids in a certain group with the same order function int numGroupSameOrder(GROUP _group, int _orderIndex) { local int _numDroids; local DROID _droid; _numDroids = 0; initIterateGroup(_group); _droid = iterateGroup(_group); while(_droid != NULLOBJECT) { if(_droid.order == _orderIndex) //right order type { _numDroids++; } _droid = iterateGroup(_group); } return _numDroids; } // Remember certain destroyed structures so we can rebuild them later event structureDestroyed(structureDestroyedTr) { local int _count; // add certain structures to the rebuild list _count = 0; while(_count < numRebuildStat[curTech]) { if(structure.stat == rebuildStat[curTech][_count]) { if(countRebuildStruct < MAX_REBUILD_STRUCT) { rebuildStructX[countRebuildStruct] = structure.x; rebuildStructY[countRebuildStruct] = structure.y; rebuildStructStat[countRebuildStruct] = structure.stat; countRebuildStruct++; dbg("remembered structure (" & countRebuildStruct & ") - " & structure.x & "/" & structure.y, me); exit; } } _count++; } } // Rebuild structures that were destroyed event rebuildStructureEv(rebuildStructureTr) { rebuildStructures(); } function void rebuildStructures() { local int _count,_threatRange,_x,_y; local DROID _truck; local STRUCTURESTAT _stat; _threatRange = (TILE * 8); _count = 0; while(_count < countRebuildStruct) { if(!threatInRange(me, rebuildStructX[_count], rebuildStructY[_count], _threatRange, FALSE)) { if(getTileStructure(_x / TILE, _y / TILE) == NULLOBJECT) { _stat = rebuildStructStat[_count]; _x = rebuildStructX[_count]; _y = rebuildStructY[_count]; if (isStructureAvailable(_stat, me)) { _truck = closestIdleTruck(_x, _y); if (_truck != NULLOBJECT) { if (numBuildSameBuilding(_stat, _x, _y) == 0) //make sure no one is building already { buildOnExactLocation(_truck, _x, _y, _stat); } } } } } _count++; } } function void buildOnExactLocation(DROID _truck, int _x, int _y, STRUCTURESTAT _stat) { local int _newX,_newY; if(_truck == NULLOBJECT) { return; } _newX = _x; _newY = _y; if (pickDroidStructLocation(_truck, _stat, ref _newX, ref _newY, me, -1)) { dbg("trying to rebuild on (" & _newX & "/" & _newY & ")", me); if ((_x != _newX) or (_y != _newY)) { return; } orderDroidStatsLoc(_truck, DORDER_BUILD, _stat, _x, _y); //dbg("rebuilding structure after!! (" & _x & "/" & _y & ")", me); } } // Get idle truck closest to some location function DROID closestIdleTruck(int _x, int _y) { local DROID _closestTruck, _tempTruck; local int _closestDist, _tempDist; _closestTruck = NULLOBJECT; _closestDist = 99999; initIterateGroup(buildGroup); _tempTruck = iterateGroup(buildGroup); while(_tempTruck != NULLOBJECT) { if((_tempTruck.order == DORDER_NONE) or (_tempTruck.order == DORDER_RTB)) { _tempDist = distBetweenTwoPoints(_x, _y, _tempTruck.x, _tempTruck.y); if(_tempDist < _closestDist) { _closestDist = _tempDist; _closestTruck = _tempTruck; } } _tempTruck = iterateGroup(buildGroup); } return _closestTruck; } event consoleEv(consoleTr) { //turn on 'autogame' if(message == "autogame on" && (sender == me)) { if(debugModeEnabled()) { if(myResponsibility(me)) { if(not bRunning) //make sure current machine is responsible for this AI and it's not already active { console(getPlayerName(me) & " is active"); reassignAI(); setEventTrigger(startLevel, chainloadTr); } } } } //turn off 'autogames' if(message == "autogame off" && debugModeEnabled() && (sender == me)) { if(bRunning) //make sure this AI is active { console(getPlayerName(me) & " is deactivated"); shutDownAI(); } } if(message == "aidebug on") { console(getPlayerName(me) & " ai debug is on"); _DEBUG = TRUE; dbgMsgOn(me, _DEBUG); } else if(message == "aidebug off") { console(getPlayerName(me) & " ai debug is off"); _DEBUG = FALSE; dbgMsgOn(me, _DEBUG); } }
違いを見つける