///////////////////////////////////////////////////////////////////// // 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 MAX_PLAYERS 8 #define BASE_DEFEND_DURATION (3 * 60) #define BASE_DEFEND_RADIUS (15 * TILE) // 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 public 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; public STRUCTURESTAT incendrys[8],structs[13],defStructs[26],extraStructs[TECHS][6],structChoice[5],wallWeaps[11]; public STRUCTURESTAT sensorTower,wall,cornerWall,resLab,powGen,playerHQ,lassat,factory,derrick,cybFactory, vtolDefStruct[5],vtolPad,vtolFactory,repairFacility,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; public TEMPLATE vtols[18]; public int numVtolTemplates; public TEMPLATE sense[11]; public int numSenseTemplates; public TEMPLATE constructor,repairUnit; public int numRepairUnits; //defend private GROUP defendGroup; private bool defendbusy; private BASEOBJ defendObj; public RESEARCHSTAT nexusDefence; //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; private int allianceTime[8]; private int sender,x,y,beaconX[8],beaconY[8],tBeacon[8], tLastHelpRequest,lastHelpPlayer,tHelp,tHelpTimeout,helpX,helpY; private string message; private int defendX,defendY,defendRadius,tDefendStart,tDefendTimeout, defendMoveType,baseRange,curTech,numVtolAttackGroups,numAttackVtols, numDefendVtols,rebuildStructX[MAX_REBUILD_STRUCT],rebuildStructY[MAX_REBUILD_STRUCT],countRebuildStruct; private STRUCTURESTAT rebuildStructStat[MAX_REBUILD_STRUCT]; ///////////////////////////////////////////////////////////////////// // triggers. #region triggers trigger buildExpandTr (every, 600); trigger fortifyTr (every, 1000); trigger upgradeStructuresTr (every, 400 ); trigger conDroidsTr (every, 900); // was 1400 trigger repairDroidsTr (every, 2600); trigger managePowerTr (every, 1500); 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, 400 ); 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, 2000); trigger defendWatchTr (CALL_STRUCT_ATTACKED, me, ref structure, ref baseobj); trigger defendReturnTr (every, 500 ); trigger doResearchTr (every, 400 ); 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,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); /* Events */ event multiMsgEv; event beaconEv; event watchBaseThreat; event manageAllyHelp; event everySecEv; event manageDefendLocationEv; event structureDestroyed; event rebuildStructureEv; /* 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, int _defendRadius, 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 FEATURE closestOil(int _x, int _y, bool _bAvoidThreat); 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 void buildTruck(); function int numBuildSameBuilding(STRUCTURESTAT _checkStat, int _x, int _y); function void expandBase(DROID _truck); 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) { // initialise _DEBUG = FALSE; dbgMsgOn(me, _DEBUG); extraStruct = 0; numRepairUnits = 0; allOutAttack = NULLOBJECT; powerSave = FALSE; 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; defendRadius = -1; tDefendStart = -1; tDefendTimeout = -1; defendMoveType = -1; //move or scout baseRange = 4 * TILE; // set current research branch setTechBranch(-1); //setTechBranch(branchVTOL); 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)); initGetFeature(oilRes,me,me); // use bucket = player // note where our base is. initIterateGroup(buildGroup); // find idle droids in build group. droid = iterateGroup(buildGroup); if(droid != NULLOBJECT) { baseX = droid.x; baseY = droid.y; if(aiResponsibleForPlayer(me)) { expandBase(droid); } } else { baseX = (128*mapWidth)/2; baseY = (128*mapHeight)/2; } // 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... allianceTime[0] = 0; allianceTime[1] = 0; allianceTime[2] = 0; allianceTime[3] = 0; allianceTime[4] = 0; allianceTime[5] = 0; allianceTime[6] = 0; allianceTime[7] = 0; bRunning = false; if(aiResponsibleForPlayer(me)) { bRunning = true; buildTruck(); } else { shutDownAI(); } } // 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; } ///////////////////////////////////////////////////////////////////// // initial force setup thing. plonk down a force. event givehelp(every, 100) { if(multiPlayerBaseType == CAMP_WALLS) { // free power addPower(1500, me); // free droids. /* structure = getStructure(factory, me); if(structure != NULLOBJECT) { count = 0; while(count<10) { tempx = baseX; tempy = baseY; boolResult = pickStructLocation(defStructs[0], ref tempx, ref tempy,me); if(boolResult == TRUE) { droid = addDroid(tmpl[curTech][ random(6) ] , tempx, tempy, me); } count = count + 1; } } */ } setEventTrigger(givehelp, inactive); } ///////////////////////////////////////////////////////////////////// // 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) { feature = getFeature(me); // find unoccupied oil resource. if(feature != NULLOBJECT) { buildX = feature.x; buildY = feature.y; // if no more than 2 units already trying to build initIterateGroup(buildGroup); // find all units in build group. droid = iterateGroup(buildGroup); count = 0; while(droid != NULLOBJECT) { if((droid.orderx == buildX) and (droid.ordery == buildY)) { count = count + 1; } droid = iterateGroup(buildGroup); } if(count < 3) { initIterateGroup(buildGroup); // find all units in build group. droid = iterateGroup(buildGroup); boolResult = FALSE; // only send 1 droid to each derrick while( (boolResult == FALSE) and (droid != NULLOBJECT) ) { if( (droid.order == DORDER_NONE) or (droid.order == DORDER_RTB)) { orderDroidStatsLoc(droid, DORDER_BUILD,derrick, buildX,buildY); //build a derick boolResult = TRUE; } droid = iterateGroup(buildGroup); } } } else // feature is null { initGetFeature(oilRes,me,me); // start again next time. } } ///////////////////////////////////////////////////////////////////// // 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_NONE) { // 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 = 0) ) { if( isStructureAvailable(defStructs[count],me)) { // don't build multiple sensors together. if(count == 5) { structure = structureBuiltInRange(defStructs[count], buildX, buildY,(6*128), me); if(structure != NULLOBJECT) { count = 8; } } structChoice[count2] = defStructs[count]; count2 = count2 + 1; } count = count - 1; } count =0; if(count2 > 0) { count = random(count2); //count = choice! // pick a location boolResult = pickStructLocation(structChoice[count], ref buildX, ref buildY,me); _numBuilders = numBuildSameBuilding(NULLSTRUCTURESTAT, buildX, buildY); if((boolResult == TRUE) and (_numBuilders < _maxBuilders)) { // 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) { 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) { 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) { 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) { 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 { buildX = baseX; // try build powergen. buildY = baseY; boolResult = pickStructLocation(powGen, ref buildX, ref buildY,me); if(boolResult == TRUE) { initIterateGroup(buildGroup); droid = iterateGroup(buildGroup); while(droid != NULLOBJECT) { if(droid.order == DORDER_NONE or droid.order == DORDER_RTB) { orderDroidStatsLoc(droid, DORDER_BUILD,powGen, buildX,buildY); } droid = iterateGroup(buildGroup); } } } } ///////////////////////////////////////////////////////////////////// // ensure we have everything in the vital structs list. event buildBase(buildBaseTr) { local int _numBuilders,_maxBuilders; 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)) { buildX = baseX; // pick a location buildY = baseY; boolResult = pickStructLocationB(structs[count], ref buildX, ref buildY,me,0); if(boolResult == TRUE) { _maxBuilders = 2; _numBuilders = numBuildSameBuilding(structs[count], buildX, buildY); initIterateGroup(buildGroup); // find idle droids in build group. droid = iterateGroup(buildGroup); while((droid != NULLOBJECT) and (_numBuilders < _maxBuilders)) { if((droid.order == DORDER_NONE) or (droid.order == DORDER_RTB)) { orderDroidStatsLoc(droid, DORDER_BUILD,structs[count], buildX,buildY); // build it _numBuilders++; } droid = iterateGroup(buildGroup); } } } } count = count + 1; } } } ///////////////////////////////////////////////////////////////////// // build other stuff, grow the base slowly... event buildExpand( buildExpandTr ) { expandBase(NULLOBJECT); } function void expandBase(DROID _truck) { local int _numBuilders,_maxBuilders; if(extraStruct == numExtraStructs[curTech]) // loop round { extraStruct = 0; } if(isStructureAvailable(extraStructs[curTech][extraStruct],me)) { buildX = baseX; // pick a location buildY = baseY; boolResult = pickStructLocationB(extraStructs[curTech][extraStruct], ref buildX, ref buildY,me,0); if(boolResult == TRUE) { _numBuilders = numBuildSameBuilding(extraStructs[curTech][extraStruct], buildX, buildY); _maxBuilders = 2; if(_truck != NULLOBJECT) { if((_truck.order != DORDER_BUILD) and (_truck.order != DORDER_LINEBUILD)) { orderDroidStatsLoc(_truck, DORDER_BUILD,extraStructs[curTech][extraStruct], buildX,buildY);// build it. _numBuilders++; } } else { initIterateGroup(buildGroup); // find idle droids in build group. droid = iterateGroup(buildGroup); while((droid != NULLOBJECT) and (_numBuilders < _maxBuilders)) { if((droid.order != DORDER_BUILD) and (droid.order != DORDER_LINEBUILD)) { orderDroidStatsLoc(droid, DORDER_BUILD,extraStructs[curTech][extraStruct], buildX,buildY);// build it. _numBuilders++; } droid = iterateGroup(buildGroup); } } } } extraStruct = extraStruct + 1; } ///////////////////////////////////////////////////////////////////// // Structure (fac/res/pow) upgrades event upgradeStructures(upgradeStructuresTr ) { 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 )) { 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 )) { 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))) { 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))) { if((numBuildSameBuilding(powModule, _powGen.x,_powGen.y) + numBuildSameBuilding(powGen, _powGen.x,_powGen.y)) < _maxBuilders) { orderDroidStatsLoc(_truck, DORDER_BUILD,resModule, _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)) { 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)) { 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); skDefenseLocation(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: set droid retreat level and start building next droid event droidBuilt(droidBuiltTr) { local STRUCTURE _repairFacility; if(!isVtol(droid)) { _repairFacility = getStructure(repairFacility,me); if(_repairFacility == NULLOBJECT) { setDroidSecondary(droid,DSO_REPAIR_LEVEL, DSS_REPLEV_NEVER); } else { setDroidSecondary(droid,DSO_REPAIR_LEVEL, DSS_REPLEV_LOW); } } /* Start building next droid */ if(structure != NULLOBJECT) { 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 )) { orderDroidStatsLoc(droid, DORDER_BUILD,facModule, structure.x,structure.y); // upgrade it. } } /* 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) { /* get next oil resource nearby */ _oilResource = closestOil(structure.x, structure.y, TRUE); if(_oilResource != NULLOBJECT) { if(distBetweenTwoPoints(_oilResource.x, _oilResource.y, structure.x, structure.y) < MORE_OIL_RANGE) //not too far away { dbg("structBuilt: more oil", me); orderDroidStatsLoc(droid, DORDER_BUILD, derrick, _oilResource.x, _oilResource.y); //build a derick } } } //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) { buildTruck(); } /* function void buildTruck() { local int _maxTrucks; local STRUCTURE _factory; local int _numBuilding,_haveTrucks,_maxTruckFactories,_totalTrucks; _maxTrucks = MAX_TRUCKS; if(powerSave){ _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(); // find factory. while((_factory != NULLOBJECT) and (_numBuilding < _maxTruckFactories) and (_totalTrucks < _maxTrucks)) { if(structureComplete(_factory)) { if(getDroidCount(me) < MAX_DROIDS) { buildDroid(constructor, _factory, me, 1); // build constructor _numBuilding++; _totalTrucks++; } } _factory = enumStruct(); } } */ function void buildTruck() { local int _maxTrucks; local STRUCTURE _factory; local int _numBuilding,_haveTrucks,_maxTruckFactories,_totalTrucks; local bool _bStartedBuilding; _maxTrucks = MAX_TRUCKS; if(powerSave){ _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 _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(); } } //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) and (getDroidCount(me) < MAX_DROIDS) ) { 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((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 < 4) 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(superCyb[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(cybTempl[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( baseobj2 != NULLOBJECT ) { if((baseobj2.type == OBJ_DROID) and !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 ) { 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; 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); } if( idleGroup(scoutGroup) >= (scoutGroup.members /2) ) { orderGroupLoc(scoutGroup, DORDER_MOVE,scoutX,scoutY); } } } } } ///////////////////////////////////////////////////////////////////// event doAllOutAttack(allOutAttackTr) { if( (allOutAttack != NULLOBJECT) and (not helpingAlly()) ) { if( !friendlyPlayer(allOutAttack.player) ) { if( getDroidCount(me) > 40) // plenty of units. { orderGroupObj(attackGroup, DORDER_ATTACK,allOutAttack); //orderGroupLoc(defendGroup, DORDER_SCOUT,allOutAttack.x,allOutAttack.y); 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(not isHumanPlayer(baseobj.player) ) // new in wdg1 dont allout attack a pc player //TODO:is this check needed? { 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) //orderGroupObj(defendGroup, DORDER_ATTACK, defendObj); } 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; _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(); } } // 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 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)) { orderGroupObj(attackGroup, DORDER_ATTACK,attackObj); } else { attackObj = NULLOBJECT; } } else { // 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); } } } ///////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////// // power management. // if running low on power put some power eating stuff on hold for a while. event managePower(managePowerTr) { if( playerPower(me) < LOW_POWER ) // turn off some events. { powerSave = TRUE; // setEventTrigger(fortify, inactive); // stop building defenses. setEventTrigger(upgradeStructures, inactive); // stop building oil defenses. // setEventTrigger(buildExpand, inactive); // stop building extra buildings. // setEventTrigger(conDroids, inactive); // stop building more construct droids. } else { if(powerSave == TRUE) // turn events back on. { powerSave = FALSE; // setEventTrigger(fortify, fortifyTr); // building defenses. setEventTrigger(upgradeStructures, upgradeStructuresTr);// building oil defenses. // setEventTrigger(buildExpand, buildExpandTr); // building extra buildings. // setEventTrigger(conDroids, conDroidsTr); // building more construct droids. } } } ///////////////////////////////////////////////////////////////////// event difficultyModifier(difficultyModifierTr) { skDifficultyModifier(me); } ///////////////////////////////////////////////////////////////////// // vtols. ///////////////////////////////////////////////////////////////////// // build vtol strucutures. event vtolStructs(inactive) { local int _maxTrucks,_numTrucks,_maxBuildTrucks,_minBuildTrucks; 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(); } // calculate how many trucks we want to use for construction _minBuildTrucks = 1; _maxBuildTrucks = 3; _maxTrucks = min(_maxBuildTrucks, max(_minBuildTrucks, idleGroup(buildGroup) / 2)); if(_numVtolFacs < maxVtolFacs[curTech]) // if not enough { // build factory buildX = baseX; // pick a location buildY = baseY; boolResult = pickStructLocation(vtolFactory, ref buildX, ref buildY,me); if(boolResult == TRUE) { initIterateGroup(buildGroup); // find idle droids in build group. droid = iterateGroup(buildGroup); _numTrucks = 0; // only send _maxTrucks to do the job while( (_numTrucks < _maxTrucks) and (droid != NULLOBJECT)) { if( (droid.order == DORDER_NONE) or (droid.order == DORDER_RTB)) { orderDroidStatsLoc(droid, DORDER_BUILD,vtolFactory, buildX,buildY); _numTrucks++; } droid = iterateGroup(buildGroup); } } } } //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() { local int _buildX,_buildY; local DROID _truck; local bool _buildOK; if(!isStructureAvailable(vtolPad,me)){ return; } // build vtol rearm pads. _buildX = baseX; // pick a location _buildY = baseY; _buildOK = pickStructLocation(vtolPad, ref _buildX, ref _buildY,me); if(_buildOK) { initIterateGroup(buildGroup); // find idle droids in build group. _truck = iterateGroup(buildGroup); _buildOK = FALSE; while(_truck != NULLOBJECT and _buildOK == FALSE) { if((_truck.order != DORDER_BUILD) and (_truck.order != DORDER_LINEBUILD)) { orderDroidStatsLoc(_truck, DORDER_BUILD,vtolPad, _buildX,_buildY); _buildOK = TRUE; } _truck = iterateGroup(buildGroup); } } } ///////////////////////////////////////////////////////////////////// // 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) { if(not isHumanPlayer(defendObj.player) ) // new in wdg1 //TODO:is this check needed? { 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; // boolResult2 = FALSE; // if attacked by a vtol. if(baseobj != NULLOBJECT) { if(baseobj.type == OBJ_DROID) { if(isVtol(objToDroid(baseobj))) { // activate other vtol functions.. setEventTrigger(vtolStructs,vtolStructsTr); setEventTrigger(buildVtols, buildVtolsTr); setEventTrigger(vtolAttack, vtolAttackTr); _numBuilders = 0; _maxBuilders = 2; // build defenses. initIterateGroup(buildGroup); // find idle droids in build group. droid = iterateGroup(buildGroup); // while( (boolResult2 != TRUE) and (droid != NULLOBJECT)) 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 = pickStructLocation(vtolDefStruct[count2], ref buildX, ref buildY,me); if((boolResult == TRUE) and (_numBuilders < _maxBuilders)) // build a vtol defense near the attacked struct... { orderDroidStatsLoc(droid, DORDER_BUILD,vtolDefStruct[count2],buildX,buildY); _numBuilders++; // boolResult2 = TRUE; } } } 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(givehelp, inactive); 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(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(managePower, inactive); setEventTrigger(difficultyModifier, 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); } event reassignPlayers(reassignTr) { reassignAI(); } 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(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(managePower,managePowerTr); setEventTrigger(difficultyModifier,difficultyModifierTr); 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); } /* 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 < 8, "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, BASE_DEFEND_RADIUS, (_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(); } //else //{ // /* See if all units we sent were killed */ // if(not haveHelpers()) // { // if(random(4) == 0) // { // messagePlayer(lastHelpPlayer, M_HELPERS_KILLED); // } // if(not attemptToHelp(lastHelpPlayer, helpX, helpY)) // { // dbg("NO UNITS, STOPPED HELPING", me); // stopHelpingAlly(); //don't make sense to try again // } // else // { // dbg("SENDING REINFORCEMENTS", me); // } // } //} } } 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, int _defendRadius, bool _bMove) { dbg("starting defending for " & _tDefendTimeout - (gameTime / 10) & " secs, with defend radius " & _defendRadius, me); ASSERT(_defendRadius >= TILE, "defendLocation: defendRadius too low:" & _defendRadius, me); defendX = _defendX; defendY = _defendY; defendRadius = _defendRadius; 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; defendRadius = -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 DROID _droid; dbg("manageDefendLocationEv", me); ASSERT(defendRadius >= TILE, "manageDefendLocationEv: defendRadius too low:" & defendRadius, 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); if(!(defendX > 0 && defendY > 0)){ dbg("not defending???????", me); exit; //not defending? } /* 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; } function FEATURE closestOil(int _x, int _y, bool _bAvoidThreat) { local FEATURE _oil,_closestOil; local int _bestDist,_newDist; _bestDist = 99999; _closestOil = NULLOBJECT; initGetFeature(oilRes,me,me); _oil = getFeatureB(me); while(_oil != NULLOBJECT) { _newDist = distBetweenTwoPoints(_x, _y, _oil.x, _oil.y); if(_newDist < _bestDist) //this one is closer { if( !(_bAvoidThreat && threatInRange(me, _oil.x, _oil.y, OIL_THREAT_RANGE, FALSE)) ) { _bestDist = _newDist; _closestOil = _oil; } } _oil = getFeatureB(me); } return _closestOil; } event keyPressed(CALL_KEY_PRESSED, ref count, ref count2) { if(count == KEY_P and (count2 == KEY_RCTRL or count2 == KEY_LCTRL)) { if(_DEBUG) { addPower(1000, me); console("add power"); } } } 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]; _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(pickStructLocationB(_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(); } } } } //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); } }