AI Coding Examples

From OPU Wiki

There's nothing that "magical" or "special" about AI, it's just triggers that control what computer opponents do. To make a simple AI is one thing, to make an AI that can adapt and react to players is totally another, for the most part it's just logic and thinking how to break situations down. Go to AI Coding for a detailed explaination of the functions you need to use.

Disasters & timed events

Triggers for disasters can be put in InitProc:

// This procedure below goes OUSIDE any other procedure, 
// so just put just above your InitProc:
SCRIPT_API void Quake()
{
  TethysGame::SetEarthquake(TethysGame::GetRand(128)+32,TethysGame::GetRand(128)-1,1);
}

SCRIPT_API int InitProc()
{
// This is where all your other init stuff goes
// just insert this line into your InitProc:

  CreateTimeTrigger(1,0,3000,7000,"Quake");

  return 1;
} 

The above will create quakes every 30~70 time-marks.


Simple group creation & attack

The same can be done for other AI functions:

// These 2 procedures and the Group definition below 
// go OUSIDE any other procedure, so just put just above your InitProc:
FightGroup grp1;

SCRIPT_API void CreateTanks()
{
  Unit u;

  grp1=CreateFightGroup(Player[1]);
  grp1.SetRect(MAP_RECT(130,8,134,12));
  TethysGame::CreateUnit(u,mapLynx,LOCATION(158,2),1,mapLaser,SouthWest);
  grp1.TakeUnit(u);
  TethysGame::CreateUnit(u,mapLynx,LOCATION(158,4),1,mapLaser,SouthWest);
  grp1.TakeUnit(u);
}
 
SCRIPT_API void Attack()
{
  grp1.DoAttackEnemy();
}

SCRIPT_API int InitProc()
{
// This is where all your other init stuff goes
// just insert these 2 lines into your InitProc:

  CreateTimeTrigger(1,1,2000,"CreateTanks");
  CreateTimeTrigger(1,1,4000,"Attack");

  return 1;
} 

That code will create 2 lynx at time-mark 20 and send them on the MAP_RECT(130,8,134,12). Then at time-mark 40, they will start attacking enemies.

Recurring attack group

Now, to make this group replenish itself, you have 2 options:

  • Use a TimeTrigger; edit your code to look like this. Note that the Attack procedure has been removed, and the CreateFightGroup is moved into the InitProc:
FightGroup grp1;

SCRIPT_API void CreateTanks()
{
  Unit u;

  TethysGame::CreateUnit(u,mapLynx,LOCATION(158,2),1,mapLaser,SouthWest);
  grp1.TakeUnit(u);
  TethysGame::CreateUnit(u,mapLynx,LOCATION(158,4),1,mapLaser,SouthWest);
  grp1.TakeUnit(u);
}
 
SCRIPT_API int InitProc()
{
// This is where all your other init stuff goes
// just insert these lines into your InitProc:

  grp1=CreateFightGroup(Player[1]);
  grp1.SetRect(MAP_RECT(130,8,134,12));
  grp1.DoAttackEnemy();

  CreateTimeTrigger(1,0,2000,"CreateTanks");

  return 1;
} 
How does this work?

Actually, the only important change is the second param in the CreateTimeTrigger call: it changed from a 1 to a 0; 1 meaning one-time only execution, and 0 meaning indefinate execution: it was call "CreateTanks" every 20 timemarks. It is important to remove the group creation code from the trigger call-back function: the group needs only be created once. Every time "CreateTanks" is called, it'll just add 2 more tanks to the FightGroup, no matter how many units the group already has, even when the group was already reduced to zero members.


  • Use a more intelligent trigger: DamagedTrigger.
FightGroup grp1;

SCRIPT_API void CreateTanks()
{
  Unit u;

  TethysGame::CreateUnit(u,mapLynx,LOCATION(158,2),1,mapLaser,SouthWest);
  grp1.TakeUnit(u);
  TethysGame::CreateUnit(u,mapLynx,LOCATION(158,4),1,mapLaser,SouthWest);
  grp1.TakeUnit(u);

  CreateDamagedTrigger(1,1,grp1,Damage100,"CreateTanks");
}
 
SCRIPT_API int InitProc()
{
// This is where all your other init stuff goes
// just insert these lines into your InitProc:

  grp1=CreateFightGroup(Player[1]);
  grp1.SetRect(MAP_RECT(130,8,134,12));
  grp1.DoAttackEnemy();

  CreateTimeTrigger(1,1,2000,"CreateTanks");

  return 1;
} 
How does this work?

This will start the next wave of attack when the first group is 100% destroyed (i.e. both of the linx). This version of code has 1 disadvantage: it will eventually crash OP2, because of a trigger-limit: you can only create 127 triggers and/or groups. So in this example it will take about 2500 time-marks for it to crash. Preventing this problem is somewhat tricky, but can be done.

Note: the second param of the TimeTrigger is 1: "CreateTanks" needs to be called only once. After that the Damagedtrigger will keep calling "CreateTanks"

Personal tools