2011-08-24 14:14:44 +02:00
|
|
|
/*
|
|
|
|
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.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
2011-08-26 21:29:04 +02:00
|
|
|
#include "Starfighter.h"
|
2011-08-24 14:14:44 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|