starfighter/code/ai.cpp

201 lines
5.0 KiB
C++

/*
Copyright (C) 2003 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "ai.h"
/*
Some very simple artificial intelligence routines for the aliens.
Shouldn't really be called AI since they just do things at random.
Aliens are assigned various AI types and this routine makes use of them.
Levels of aggression, defence and evasion are all here.
*/
void setEnemyAI(object *theEnemy)
{
// Make friendly craft generally concentrate on smaller fighters
if ((theEnemy->flags & FL_FRIEND) && (theEnemy->target == &enemy[WC_BOSS]))
{
if ((rand() % 5) == 0)
{
theEnemy->target = theEnemy;
theEnemy->thinktime = 0;
return;
}
}
int i = rand() % 10;
float tx = theEnemy->target->x;
float ty = theEnemy->target->y;
int chase = 0; // Chance in 10 of chasing player
int area = 0; // Chance in 10 of moving to an area around the player
int stop = 0; // Chance in 10 of hanging back
int point = 0; // Size of area alien will move into
switch (theEnemy->AIType)
{
case AI_NORMAL:
chase = 3;
point = 6;
stop = 9;
area = 250;
break;
case AI_OFFENSIVE:
chase = 7;
point = 8;
stop = 9;
area = 50;
break;
case AI_DEFENSIVE:
chase = 2;
point = 6;
stop = 8;
area = 300;
break;
case AI_EVASIVE:
chase = 1;
point = 8;
stop = 9;
area = 600;
break;
case AI_WANDER:
chase = -1;
point = 0;
stop = 10;
area = 1200;
break;
}
if (i <= chase)
{
// Chase the target
theEnemy->dx = ((theEnemy->x - tx) / ((300 / theEnemy->speed) + rand() % 100));
theEnemy->dy = ((theEnemy->y - ty) / ((300 / theEnemy->speed) + rand() % 100));
return;
}
else if ((i >= point) && (i <= stop))
{
// Fly to a random point around the target
tx += (rand() % area - (rand() % area * 2));
ty += (rand() % area - (rand() % area * 2));
theEnemy->dx = ((theEnemy->x - tx) / ((300 / theEnemy->speed) + rand() % 100));
theEnemy->dy = ((theEnemy->y - ty) / ((300 / theEnemy->speed) + rand() % 100));
return;
}
else
{
// Hang back
theEnemy->dx = 0;
theEnemy->dy = 0;
return;
}
}
void setKlineAttackMethod(object *theEnemy)
{
theEnemy->maxShield -= 500;
if (theEnemy->maxShield == 0)
theEnemy->flags -= FL_CANNOTDIE;
if (theEnemy->maxShield == 1000)
{
setRadioMessage(FACE_KLINE, "Very good, Bainfield. Now let's get a little more serious...", 1);
theEnemy->weaponType[0] = W_SPREADSHOT;
theEnemy->chance[1] = 40;
}
else if (theEnemy->maxShield == 500)
{
setRadioMessage(FACE_KLINE, "Your ability to stay alive irritates me!! Try dodging some of these!!", 1);
theEnemy->weaponType[0] = W_DIRSHOCKMISSILE;
theEnemy->weaponType[1] = W_DIRSHOCKMISSILE;
theEnemy->chance[0] = 2;
theEnemy->chance[1] = 2;
theEnemy->flags += FL_AIMS;
}
else if (theEnemy->maxShield == 0)
{
setRadioMessage(FACE_KLINE, "ENOUGH!! THIS ENDS NOW!!!", 1);
theEnemy->weaponType[0] = W_AIMED_SHOT;
theEnemy->weaponType[1] = W_MICRO_HOMING_MISSILES;
theEnemy->flags += FL_CANCLOAK;
theEnemy->chance[0] = 100;
theEnemy->chance[1] = 2;
}
theEnemy->shield = 500;
}
/*
This AI is exclusively for Kline.
*/
void setKlineAI(object *theEnemy)
{
// Weapon type change
if ((rand() % 3) == 0)
{
if (currentGame.area != 26)
{
if (theEnemy->flags & FL_AIMS)
theEnemy->flags -= FL_AIMS;
switch(rand() % 2)
{
case 0:
theEnemy->weaponType[0] = W_TRIPLE_SHOT;
break;
case 1:
theEnemy->weaponType[0] = W_AIMED_SHOT;
theEnemy->flags += FL_AIMS;
break;
}
}
}
if (theEnemy->flags & FL_CIRCLES)
theEnemy->flags -= FL_CIRCLES;
if (theEnemy->flags & FL_CONTINUOUS_FIRE)
theEnemy->flags -= FL_CONTINUOUS_FIRE;
if (theEnemy->flags & FL_DROPMINES)
theEnemy->flags -= FL_DROPMINES;
switch(rand() % 10)
{
case 0:
if ((theEnemy->weaponType[0] != W_DIRSHOCKMISSILE) && (theEnemy->weaponType[1] != W_MICRO_HOMING_MISSILES))
theEnemy->flags += FL_CONTINUOUS_FIRE;
theEnemy->dx = ((theEnemy->x - theEnemy->target->x) / ((300 / theEnemy->speed) + rand() % 100));
theEnemy->dy = ((theEnemy->y - theEnemy->target->y) / ((300 / theEnemy->speed) + rand() % 100));
break;
case 1:
case 2:
// Kline only attacks then he is ready!
if ((!(theEnemy->flags & FL_NOFIRE)) && (currentGame.area == 11))
theEnemy->flags += FL_DROPMINES;
break;
case 3:
case 4:
theEnemy->flags += FL_CIRCLES;
break;
default:
setEnemyAI(theEnemy);
break;
}
}