AI updates - allow enemies to flee.

This commit is contained in:
Steve 2015-11-15 13:26:34 +00:00
parent c8489e7dc6
commit 095e8b65a4
5 changed files with 121 additions and 98 deletions

View File

@ -20,15 +20,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "ai.h" #include "ai.h"
static int aggression[][5] =
{
{60, 65, 70, 75, 80},
{50, 55, 60, 65, 70},
{40, 45, 50, 55, 60},
{30, 35, 40, 45, 50},
{15, 20, 25, 30, 35}
};
static void faceTarget(Entity *f); static void faceTarget(Entity *f);
static int isInFOV(Entity *f, int fov); static int isInFOV(Entity *f, int fov);
static void preAttack(void); static void preAttack(void);
@ -44,21 +35,36 @@ static void slow(void);
static void moveToPlayer(void); static void moveToPlayer(void);
static int canAttack(Entity *f); static int canAttack(Entity *f);
static int selectWeapon(int type); static int selectWeapon(int type);
static void flee(void);
static int nearExtractionPoint(void); static int nearExtractionPoint(void);
static int nearEnemies(void); static int nearEnemies(void);
static void lookForPlayer(void); static void lookForPlayer(void);
static void fleeEnemies(void); static void fleeEnemies(void);
static void moveToExtractionPoint(void); static void moveToExtractionPoint(void);
static int getActionChance(int type);
static void flee(void);
static void doFighterAI(void);
static void doCivilianAI(void);
void doAI(void) void doAI(void)
{
if (self->flags & EF_CIVILIAN)
{
doCivilianAI();
}
else
{
doFighterAI();
}
}
static void doFighterAI(void)
{ {
int r; int r;
/* don't hold a grudge against current target */ /* don't hold a grudge against current target */
if ((self->target != NULL && self->target->health <= 0) || rand() % 2 == 0) if ((self->target != NULL && self->target->health <= 0) || rand() % 2 == 0)
{ {
self->action = self->defaultAction; self->action = doAI;
self->target = NULL; self->target = NULL;
} }
@ -83,27 +89,27 @@ void doAI(void)
r = rand() % 100; r = rand() % 100;
if (r <= aggression[self->aggression][0]) if (r <= getActionChance(AI_DODGE))
{ {
self->action = dodge; self->action = dodge;
self->aiActionTime = FPS; self->aiActionTime = FPS;
} }
else if (r <= aggression[self->aggression][1]) else if (r <= getActionChance(AI_BOOST))
{ {
self->action = boost; self->action = boost;
self->aiActionTime = FPS / 2; self->aiActionTime = FPS / 2;
} }
else if (r <= aggression[self->aggression][2]) else if (r <= getActionChance(AI_SLOW))
{ {
self->action = slow; self->action = slow;
self->aiActionTime = FPS / 2; self->aiActionTime = FPS / 2;
} }
else if (r <= aggression[self->aggression][3]) else if (r <= getActionChance(AI_STRAIGHT))
{ {
self->action = flyStraight; self->action = flyStraight;
self->aiActionTime = FPS; self->aiActionTime = FPS;
} }
else if (r <= aggression[self->aggression][4]) else if (r <= getActionChance(AI_HUNT))
{ {
self->action = huntTarget; self->action = huntTarget;
self->aiActionTime = FPS * 2; self->aiActionTime = FPS * 2;
@ -114,7 +120,7 @@ void doAI(void)
self->aiActionTime = FPS; self->aiActionTime = FPS;
} }
if (player != NULL && battle.numEnemies <= 2 && self->flags & EF_FLEES) if ((player != NULL && battle.numEnemies <= 2 && self->flags & EF_FLEES) || (self->flags & EF_ALWAYS_FLEES))
{ {
self->action = flee; self->action = flee;
self->aiActionTime = FPS * 3; self->aiActionTime = FPS * 3;
@ -126,6 +132,29 @@ void doAI(void)
} }
} }
static int getActionChance(int type)
{
switch (type)
{
case AI_DODGE:
return 40 - (self->aggression * 5);
case AI_BOOST:
return 50 - (self->aggression * 5);
case AI_SLOW:
return 60 - (self->aggression * 5);
case AI_STRAIGHT:
return 70 - (self->aggression * 5);
case AI_HUNT:
return 80 - (self->aggression * 5);
}
return 100;
}
static void huntTarget(void) static void huntTarget(void)
{ {
faceTarget(self->target); faceTarget(self->target);
@ -341,10 +370,61 @@ static void dodge(void)
nextAction(); nextAction();
} }
static void nextAction(void)
{
if (--self->aiActionTime <= 0)
{
self->action = doAI;
}
}
static void flee(void) static void flee(void)
{
if (!nearEnemies() && battle.extractionPoint)
{
self->target = battle.extractionPoint;
moveToExtractionPoint();
}
}
static int nearEnemies(void)
{
int i, numEnemies;
Entity *e, **candidates;
candidates = getAllEntsWithin(self->x - (self->w / 2) - 1000, self->y - (self->h / 2) - 1000, 2000, 2000, self);
self->target = NULL;
self->targetLocation.x = self->targetLocation.y = 0;
numEnemies = 0;
for (i = 0, e = candidates[i] ; e != NULL ; e = candidates[++i])
{
if (e->type == ET_FIGHTER && e->side != self->side)
{
self->targetLocation.x += e->x;
self->targetLocation.y += e->y;
numEnemies++;
}
}
if (numEnemies)
{
self->targetLocation.x /= numEnemies;
self->targetLocation.y /= numEnemies;
self->action = fleeEnemies;
self->aiActionTime = FPS / 2;
return 1;
}
return 0;
}
static void fleeEnemies(void)
{ {
int dir; int dir;
int wantedAngle = 180 + getAngle(self->x, self->y, player->x, player->y); int wantedAngle = 180 + getAngle(self->x, self->y, self->targetLocation.x, self->targetLocation.y);
wantedAngle %= 360; wantedAngle %= 360;
@ -359,17 +439,14 @@ static void flee(void)
applyFighterThrust(); applyFighterThrust();
nextAction();
}
static void nextAction(void)
{
if (--self->aiActionTime <= 0) if (--self->aiActionTime <= 0)
{ {
self->action = doAI; self->action = doAI;
} }
} }
/* ====== Ally AI ======= */
static void moveToPlayer(void) static void moveToPlayer(void)
{ {
int dist = getDistance(self->x, self->y, player->x, player->y); int dist = getDistance(self->x, self->y, player->x, player->y);
@ -430,64 +507,6 @@ static void moveToExtractionPoint(void)
applyFighterThrust(); applyFighterThrust();
} }
static int nearEnemies(void)
{
int i, numEnemies;
Entity *e, **candidates;
candidates = getAllEntsWithin(self->x - (self->w / 2) - 1000, self->y - (self->h / 2) - 1000, 2000, 2000, self);
self->target = NULL;
self->targetLocation.x = self->targetLocation.y = 0;
numEnemies = 0;
for (i = 0, e = candidates[i] ; e != NULL ; e = candidates[++i])
{
if (e->type == ET_FIGHTER && e->side != SIDE_ALLIES)
{
self->targetLocation.x += e->x;
self->targetLocation.y += e->y;
numEnemies++;
}
}
if (numEnemies)
{
self->targetLocation.x /= numEnemies;
self->targetLocation.y /= numEnemies;
self->action = fleeEnemies;
self->aiActionTime = FPS / 2;
return 1;
}
return 0;
}
static void fleeEnemies(void)
{
int dir;
int wantedAngle = 180 + getAngle(self->x, self->y, self->targetLocation.x, self->targetLocation.y);
wantedAngle %= 360;
if (fabs(wantedAngle - self->angle) > TURN_THRESHOLD)
{
dir = ((int)(wantedAngle - self->angle + 360)) % 360 > 180 ? -1 : 1;
self->angle += dir * TURN_SPEED;
self->angle = mod(self->angle, 360);
}
applyFighterThrust();
if (--self->aiActionTime <= 0)
{
self->action = doCivilianAI;
}
}
static void lookForPlayer(void) static void lookForPlayer(void)
{ {
if (player != NULL && getDistance(self->x, self->y, player->x, player->y) < 1000) if (player != NULL && getDistance(self->x, self->y, player->x, player->y) < 1000)

View File

@ -23,6 +23,12 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "../defs.h" #include "../defs.h"
#include "../structs.h" #include "../structs.h"
#define AI_DODGE 0
#define AI_BOOST 1
#define AI_SLOW 2
#define AI_STRAIGHT 3
#define AI_HUNT 4
#define TURN_SPEED 4 #define TURN_SPEED 4
#define TURN_THRESHOLD 2 #define TURN_THRESHOLD 2

View File

@ -75,15 +75,7 @@ Entity *spawnFighter(char *name, int x, int y, int side)
f->texture = getTexture("gfx/craft/civilian02.png"); f->texture = getTexture("gfx/craft/civilian02.png");
} }
if (f->flags & EF_CIVILIAN) f->action = doAI;
{
f->defaultAction = doCivilianAI;
}
else
{
f->defaultAction = doAI;
}
f->die = die; f->die = die;
return f; return f;
@ -193,11 +185,6 @@ void doFighter(void)
self->shieldRecharge = self->shieldRechargeRate; self->shieldRecharge = self->shieldRechargeRate;
} }
if (self->action == NULL && self->defaultAction != NULL)
{
self->action = self->defaultAction;
}
if (self->health <= 0) if (self->health <= 0)
{ {
self->health = 0; self->health = 0;
@ -395,7 +382,7 @@ void damageFighter(Entity *f, int amount, long flags)
if (f->systemPower == 0) if (f->systemPower == 0)
{ {
f->shield = f->maxShield = 0; f->shield = f->maxShield = 0;
f->action = f->defaultAction = NULL; f->action = NULL;
} }
} }
else else
@ -491,3 +478,16 @@ static void straightDie(void)
playBattleSound(SND_EXPLOSION_1 + rand() % 4, self->x, self->y); playBattleSound(SND_EXPLOSION_1 + rand() % 4, self->x, self->y);
} }
} }
void fleeAllEnemies(void)
{
Entity *e;
for (e = battle.entityHead.next ; e != NULL ; e = e->next)
{
if (e->type == ET_FIGHTER && e->side != SIDE_ALLIES)
{
e->flags |= EF_ALWAYS_FLEES;
}
}
}

View File

@ -56,7 +56,6 @@ void initPlayer(void)
STRNCPY(player->name, "Player", MAX_NAME_LENGTH); STRNCPY(player->name, "Player", MAX_NAME_LENGTH);
player->action = NULL; player->action = NULL;
player->defaultAction = NULL;
} }
void doPlayer(void) void doPlayer(void)

View File

@ -113,7 +113,6 @@ struct Entity {
Entity *target; Entity *target;
Entity *owner; Entity *owner;
void (*action)(void); void (*action)(void);
void (*defaultAction)(void);
void (*die)(void); void (*die)(void);
SDL_Texture *texture; SDL_Texture *texture;
Entity *next; Entity *next;