Return
1998/1999
Back to beginners guide to A.I.
to DancingMoogles short guide to A.i editor
As we progress with the tutorial for the A.I. this will become
the benchmark that all other A.I. will go by - as it was the first to work
correctly ( some would argue that point) but anyways, on with the battle - first
being to translate this mass of code into one that everyone can read and
understand. Never have I undertaken such a task but as with all things - there
is a first time for everything... you will notice that I am in process of
highlighting in
RED his comments - looks to be a pretty straight forward task - but you
all know what that means - (see murphy's law - ie: code ):>
CAUTION: EXTREMELY LONG DOCUMENTATION AHEAD!
Coffee is mandatory!
///////////////////////////////////////////////////////////////////////
general ai for skirmish game
/////////////////////////////////////////////////////////////////////
Warzone2100, Pumpkin Studios,
alex lee.98/99.
/////////////////////////////////////////////////////////////////////
public INT player; //
player for this instance.
public INT tileExpand; //
rate of exploration
public INT numScouts; //
aim for...
public INT numDefenders;
public INT numAttackers;
// structures
private
INT baseX,baseY,minx,miny,maxx,maxy;
public INT numStructs,numIncendrys,numDefStructs,numExtraStructs,numWallWeaps;
public STRUCTURESTAT incendrys[8],structs[13],defStructs[26],extraStructs[6],structChoice[5],wallWeaps[11];
public STRUCTURESTAT sensorTower,wallStruct,resLab,powGen,playerHQ,lassat,factory,derrick,cybFactory,vtolDefStruct[5],vtolPad,vtolFactory,repairFacility;
public STRUCTURESTAT powModule,facModule,resModule,vtolModule;
public INT extraStruct;
// unit templates
public INT numTemplates;
public TEMPLATE tmpl[80];
private TEMPLATE tmplChoice[5];
public TEMPLATE cybTempl[4],superCyb[4];
public TEMPLATE vtols[18];
public INT numVtolTemplates;
public TEMPLATE sense[11];
public INT numSenseTemplates;
public TEMPLATE constructor,repairUnit;
public INT numCyborgs,numRepairUnits;
private
INT currentCyborgs,currentCyborgTemplate;
//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;
// vtols
private
GROUP vtolGroup;
// generic
private
STRUCTURE structure,structure2;
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;
private INT allianceTime[8];
/////////////////////////////////////////////////////////////////////
// triggers.
trigger
buildExpandTr (every,
900);
trigger
fortifyTr (every, 1250);
trigger
upgradeStructuresTr (every,
590 );
trigger
conDroidsTr (every,
1800); //
was 3600
trigger
repairDroidsTr (every,
2600);
trigger managePowerTr (every,
2000);
trigger
basedetailsTr (every,
700 );
trigger
buildDerrickTr (every,
110 );
trigger
buildOilDefenseOrRetreatTr (every,
170 );
trigger
incendryTr (every,
310 );
trigger
buildPowerGeneratorsTr (every,
90 );
trigger
buildBaseTr (every,
210 );
trigger
finishStructsTr (every,
610 );
trigger
droidBuiltTr (CALL_NEWDROID,player,
ref droid,ref structure);
trigger
droidDestroyedTr (CALL_DROID_DESTROYED,
player, ref droid);
trigger
consolidateEventTr (every, 3100);
trigger
factoryEventTr (every,
200 );
trigger
cyborgFactoryEventTr (every,
200 );
trigger
chooseScoutAreaTr (every, 200 );
trigger
expandScoutAreaTr (every, 600 );
trigger
scoutMainTr (every, 150 );
trigger
newObjectReportTr (CALL_OBJ_SEEN,
player, ref baseobj, ref baseobj2);
trigger
attackStuffTr (every,
300 );
trigger
allOutAttackTr (every,
2380);
trigger
defendWatchTr (CALL_STRUCT_ATTACKED,
player, ref structure, ref baseobj);
trigger
defendReturnTr (every, 600 );
trigger
doResearchTr (every,
500 );
trigger
vtolDefendTr (CALL_STRUCT_ATTACKED,
player, ref structure, ref baseobj);
trigger
vtolStructsTr (every,
360);
trigger
buildVtolsTr (every,
360);
trigger
vtolAttackTr (every,
460);
trigger
vtolEnablerTr (every,
2100);
trigger
takeoverTr (CALL_UNITTAKEOVER,
ref droid);
trigger
useLassatTr (every,
3000);
trigger
reassignTr (CALL_PLAYERLEFT,count);
trigger
formAllianceEventTr (every,170);
trigger
breakAllianceEventTr (every,700);
trigger
difficultyModifierTr (every,600);
trigger
humanAllianceTr (CALL_ALLIANCEOFFER,ref
count, ref count2);
/////////////////////////////////////////////////////////////////////
// HouseKeeping
event initialisedEvent(CALL_GAMEINIT)
{
//
initialise
extraStruct = 0;
numRepairUnits = 0;
allOutAttack = NULLOBJECT;
currentCyborgTemplate = 0;
powerSave = FALSE;
//
setup build group
//all
initial droids are in buildgroup!
groupAddArea(buildGroup,
player, 0, 0, (mapWidth*128), (mapHeight*128));
initGetFeature(oilRes,player,player); //
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;
}
else
{
baseX
= (128*mapWidth)/2;
baseY
= (128*mapHeight)/2;
}
//
defence.
defendbusy = FALSE;
//
setup scouts
structure =
getStructure(factory, player);
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;
}
/////////////////////////////////////////////////////////////////////
// initial force setup thing. plonk down a force.
event givehelp(every, 100)
{
if( (player == selectedPlayer)
or (not myResponsibility(player)) )
{
setEventTrigger(givehelp, inactive);
}
else
{
if(multiPlayerBaseType
== CAMP_WALLS)
{
//
free power
addPower(1500,
player);
//
free droids.
structure
= getStructure(factory, player);
if(structure
!= NULLOBJECT)
{
count
= 0;
while(count<10)
{
tempx
= baseX;
tempy
= baseY;
boolResult
= pickStructLocation(defStructs[0], ref tempx, ref tempy,player);
if(boolResult
== TRUE)
{
addDroid(tmpl[
random(6) ] , tempx, tempy, player);
}
count
= count + 1;
}
}
}
setEventTrigger(givehelp, inactive);
}
}
/////////////////////////////////////////////////////////////////////
// keep details about the size and postion of the ai players base
event basedetails(basedetailsTr)
{
if( (player == selectedPlayer)
or (not myResponsibility(player)) )
{
setEventTrigger(basedetails, inactive);
}
else
{
//
clear old extremities.
maxy
= 0;
maxx
= 0;
miny
= (mapHeight*128);
minx
= (mapWidth*128);
//
now find the extremities of our vital structures.
count
= 0;
while(count
< numStructs)
{
initEnumStruct(FALSE,structs[count],player,player);
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;
}
structure=
enumStruct();
}
count
= count + 1;
}
}
}
/////////////////////////////////////////////////////////////////////
// structure building rules
// build derricks on oil.
event buildDerrick(buildDerrickTr)
{
if( (player == selectedPlayer)
or (not myResponsibility(player)) )
{
setEventTrigger(buildDerrick, inactive);
}
else
{
feature
=
getFeature(player); //
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,player,player); //
start again next time.
}
}
}
/////////////////////////////////////////////////////////////////////
// if idle and derrick in range and no defense then build defense, else ret to
base .
event buildOilDefenseOrRetreat(buildOilDefenseOrRetreatTr)
{
if( (player == selectedPlayer)
or (not myResponsibility(player)) )
{
setEventTrigger(buildOilDefenseOrRetreat, inactive);
}
else
{
//
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), player);
//
if inside base limits then presume ok..
if(
structure != NULLOBJECT)
{
if((structure.x
> minx) and (structure.y > miny) and (structure.x < maxx) and
(structure.y <maxy))
{
structure
= NULLOBJECT;
}
}
if(structure
!= NULLOBJECT)
{
buildX
= structure.x;
buildY
= structure.y;
count
=
0; //
if derrick has no defense near it.
result
= 0;
while(count
< numDefStructs)
{
structure
= structureBuiltInRange(defStructs[count], buildX, buildX,(3*128), player);
if(structure
!= NULLOBJECT)
{
result
= result +
1; //
found a defense.
}
count
= count + 1;
}
//
not many defenses nearby
if(result
< 2)
{
count
= numDefStructs -
1; //pick
a struct to build..
count2
= 0;
while(
(count2 < 5) and (count >= 0) )
{
if(
isStructureAvailable(defStructs[count],player))
{
//
don't build multiple sensors together.
if(count
== 5)
{
structure
= structureBuiltInRange(defStructs[count], buildX, buildY,(6*128), player);
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,player);
if(boolResult
== TRUE)
{
//
build it.
orderDroidStatsLoc(droid,
DORDER_BUILD,structChoice[count], buildX,buildY);
}
}
}
else
{
structure
= structureBuiltInRange(playerHQ, droid.x, droid.y, (5*128),
player);
if(structure
== NULLOBJECT)
{
orderDroid(droid,DORDER_RTB); //
return to base;
}
}
}
else
{
structure
= structureBuiltInRange(playerHQ, droid.x, droid.y, (5*128),
player);
if(structure
== NULLOBJECT)
{
orderDroid(droid,DORDER_RTB); //
return to base;
}
}
}
droid
= iterateGroup(buildGroup);
}
}
}
/////////////////////////////////////////////////////////////////////
//mortar etc.. rules. build sensor towers and emplacements.
event incendry(incendryTr)
{
if( (player == selectedPlayer)
or (not myResponsibility(player)) )
{
setEventTrigger(incendry, inactive);
}
else
{
initEnumStruct(FALSE,sensorTower,player,player);
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,player,player);
structure=
enumStruct();
while(structure
!= NULLOBJECT)
{
count
=
0;
result
= 0;
while(count
< numDefStructs)
{
structure2
= structureBuiltInRange(defStructs[count], structure.x, structure.y,(4*128),
player);
if(structure2
!= NULLOBJECT)
{
result
= result +
1;
}
count
= count + 1;
}
//
check for sensor nearby,
structure2
= structureBuiltInRange(sensorTower, structure.x, structure.y,(5*128),
player);
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,player); //
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,player,player);
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),
player);
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],player))
{
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,player); //
pick spot.
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,incendrys[result], buildX,buildY);
}
droid
= iterateGroup(buildGroup);
}
}
}
}
}
}
}
/////////////////////////////////////////////////////////////////////
// build a power gen for every 4 derricks. VITAL!
event buildPowerGenerators(buildPowerGeneratorsTr)
{
if( (player == selectedPlayer)
or (not myResponsibility(player)) )
{
setEventTrigger(buildPowerGenerators, inactive);
}
else
{
initEnumStruct(FALSE,derrick,player,player); //
count = numderricks
structure=
enumStruct();
count
= 0;
while(structure
!= NULLOBJECT)
{
count
= count + 1;
structure=
enumStruct();
}
initEnumStruct(FALSE,powGen,player,player); //
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,player);
if(boolResult
== TRUE)
{
initIterateGroup(buildGroup);
droid
= iterateGroup(buildGroup);
&nb