[Add] We can now have multiple enemies.
[Add] You are able to get other ship's health from AI now.
This commit is contained in:
parent
f107574b38
commit
a89395a54f
@ -16,9 +16,12 @@
|
||||
</Alliances>
|
||||
<Enemies>
|
||||
<enemies>
|
||||
<enemy type = "faction">Player</enemy>
|
||||
<enemy type = "alliance">Neutral</enemy>
|
||||
<enemy type = "faction">Pirate</enemy>
|
||||
</enemies>
|
||||
<enemies>
|
||||
<enemy type="faction">Pirate</enemy>
|
||||
<enemy type="faction">Player</enemy>
|
||||
</enemies>
|
||||
</Enemies>
|
||||
</Factions>
|
||||
|
@ -5,7 +5,7 @@
|
||||
<class>1</class>
|
||||
<movement>
|
||||
<thrust>400</thrust>
|
||||
<turn>360</turn>
|
||||
<turn>180</turn>
|
||||
<speed>360</speed>
|
||||
</movement>
|
||||
<health>
|
||||
@ -23,7 +23,7 @@
|
||||
<cap_cargo>20</cap_cargo>
|
||||
</characteristics>
|
||||
<outfits>
|
||||
<outfit quantity='3'>laser</outfit>
|
||||
<outfit quantity='2'>laser</outfit>
|
||||
</outfits>
|
||||
</ship>
|
||||
<ship name="Enemy Test">
|
||||
@ -31,7 +31,7 @@
|
||||
<class>1</class>
|
||||
<movement>
|
||||
<thrust>180</thrust>
|
||||
<turn>360</turn>
|
||||
<turn>130</turn>
|
||||
<speed>260</speed>
|
||||
</movement>
|
||||
<health>
|
||||
|
@ -51,7 +51,7 @@ function stop()
|
||||
brake()
|
||||
if isstopped() then
|
||||
poptask()
|
||||
settimer(0, rng(3000, 5000))
|
||||
settimer(0, rng(8000, 15000))
|
||||
pushtask(0, "land")
|
||||
end
|
||||
end
|
||||
|
@ -3,9 +3,23 @@ control_rate = 2
|
||||
|
||||
-- Required "control" function.
|
||||
function control()
|
||||
if taskname() ~= "attack" then
|
||||
task = taskname()
|
||||
if task ~= "attack" and task ~= "runaway" then
|
||||
-- If getenemy() is 0, there is no enemy around.
|
||||
enemy = getenemy()
|
||||
if enemy ~= -1 then
|
||||
if enemy ~= 0 then
|
||||
-- Taunts.
|
||||
num = rng(0,4)
|
||||
if num == 0 then msg "Prepare to be boarded!"
|
||||
elseif num == 1 then msg = "Whoa! Lookie we I found here!"
|
||||
elseif num == 2 then msg = "What's a ship like you doing in a place like this?"
|
||||
end
|
||||
comm(enemy,msg)
|
||||
|
||||
-- Make hostile to the enemy (mainly, player! YOU!).
|
||||
hostile(enemy)
|
||||
|
||||
-- Go ahead and attack.
|
||||
pushtask(0, "attack", enemy)
|
||||
else
|
||||
pushtask(0, "fly")
|
||||
@ -36,22 +50,24 @@ function taunt()
|
||||
if msg then comm(attacker, msg) end
|
||||
end
|
||||
|
||||
-- Run away.
|
||||
-- Run away from the target.
|
||||
function runaway()
|
||||
target = gettargerid()
|
||||
dir = face(target, 1)
|
||||
accel()
|
||||
end
|
||||
|
||||
-- Attack.
|
||||
-- Attack the target.
|
||||
function attack()
|
||||
target = gettargetid()
|
||||
dir = face(target)
|
||||
dist = getdist(getpos(target))
|
||||
|
||||
-- We need to know when to run away.
|
||||
if parmor() < 70 then
|
||||
poptask()
|
||||
pushtask(0, "runaway", target)
|
||||
-- Try to obliterate the target.
|
||||
elseif dir < 10 and dist > 300 then
|
||||
accel()
|
||||
elseif dir < 10 and dist < 300 then
|
||||
@ -59,9 +75,9 @@ function attack()
|
||||
end
|
||||
end
|
||||
|
||||
-- Fly to the player.
|
||||
-- Fly to the player. Pointless until hyperspace is implemented.
|
||||
function fly()
|
||||
target = 0
|
||||
target = player
|
||||
dir = face(target)
|
||||
dist = getdist(getpos(target))
|
||||
if dir < 10 and dist > 300 then
|
||||
|
@ -50,7 +50,7 @@ end
|
||||
|
||||
-- Fly to the player.
|
||||
function fly()
|
||||
target = 0
|
||||
target = player
|
||||
dir = face(target)
|
||||
dist = getdist(getpos(target))
|
||||
if dir < 10 and dist > 300 then
|
||||
|
69
src/ai.c
69
src/ai.c
@ -56,9 +56,9 @@
|
||||
// Don't run the function if (n) params aren't passed.
|
||||
#define MIN_ARGS(n) if(lua_gettop(L) < n) return 0
|
||||
|
||||
#define MIN_DIR_ERR 5.0*M_PI/180.
|
||||
#define MAX_DIR_ERR 2.5*M_PI/180.
|
||||
#define MIN_VEL_ERR 2.5
|
||||
#define MIN_DIR_ERR 1.0*M_PI/180.
|
||||
#define MAX_DIR_ERR 0.1*M_PI/180.
|
||||
#define MIN_VEL_ERR 0.5
|
||||
|
||||
// file info.
|
||||
#define AI_PREFIX "../scripts/ai/"
|
||||
@ -112,6 +112,7 @@ static int ai_getrndplanet(lua_State* L); // pointer getrndplanet()
|
||||
// Combat.
|
||||
static int ai_shoot(lua_State* L); // shoot(number) number = 1,2,3.
|
||||
static int ai_getenemy(lua_State* L); // number getenemy().
|
||||
static int ai_hostile(lua_State* L); // hostile(number).
|
||||
// Timers.
|
||||
static int ai_settimer(lua_State* L); // settimer(number, number)
|
||||
static int ai_timeup(lua_State* L); // bool timeup(number)
|
||||
@ -213,6 +214,7 @@ static int ai_loadProfile(char* filename) {
|
||||
// Combat.
|
||||
lua_register(L, "shoot", ai_shoot);
|
||||
lua_register(L, "getenemy", ai_getenemy);
|
||||
lua_register(L, "hostile", ai_hostile);
|
||||
// Timers.
|
||||
lua_register(L, "settimer", ai_settimer);
|
||||
lua_register(L, "timeup", ai_timeup);
|
||||
@ -395,25 +397,54 @@ static int ai_gettargetid(lua_State* L) {
|
||||
|
||||
// Get the pilots armor.
|
||||
static int ai_armor(lua_State* L) {
|
||||
lua_pushnumber(L, cur_pilot->armor);
|
||||
double d;
|
||||
|
||||
if(lua_isnumber(L,1)) d = pilot_get((unsigned int)lua_tonumber(L,1))->armor;
|
||||
else d = cur_pilot->armor;
|
||||
|
||||
lua_pushnumber(L, d);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Get pilots shield.
|
||||
static int ai_shield(lua_State* L) {
|
||||
lua_pushnumber(L, cur_pilot->shield);
|
||||
double d;
|
||||
|
||||
if(lua_isnumber(L,1)) d = pilot_get((unsigned int)lua_tonumber(L,1))->shield;
|
||||
else d = cur_pilot->shield;
|
||||
|
||||
lua_pushnumber(L, d);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Get the pilot's armor in percentage.
|
||||
static int ai_parmor(lua_State* L) {
|
||||
lua_pushnumber(L, cur_pilot->armor / cur_pilot->armor_max * 100.);
|
||||
double d;
|
||||
Pilot* p;
|
||||
|
||||
if(lua_isnumber(L,1)) {
|
||||
p = pilot_get((unsigned int)lua_tonumber(L,1));
|
||||
d = p->armor / p->armor_max * 100.;
|
||||
}
|
||||
else d = cur_pilot->armor / cur_pilot->armor_max * 100.;
|
||||
|
||||
lua_pushnumber(L, d);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Get the pilot's shield in percentage.
|
||||
static int ai_pshield(lua_State* L) {
|
||||
lua_pushnumber(L, cur_pilot->shield / cur_pilot->shield_max * 100.);
|
||||
double d;
|
||||
Pilot* p;
|
||||
|
||||
if(lua_isnumber(L,1)) {
|
||||
p = pilot_get((unsigned int)lua_tonumber(L,1));
|
||||
d = p->shield / p->shield_max * 100.;
|
||||
}
|
||||
else d = cur_pilot->shield / cur_pilot->shield_max * 100.;
|
||||
|
||||
lua_pushnumber(L, d);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -449,7 +480,7 @@ static int ai_minbrakedist(lua_State* L) {
|
||||
double time = VMOD(cur_pilot->solid->vel) /
|
||||
(cur_pilot->ship->thrust / cur_pilot->solid->mass);
|
||||
|
||||
double dist = VMOD(cur_pilot->solid->vel) * (time + cur_pilot->ship->turn/360.) -
|
||||
double dist = VMOD(cur_pilot->solid->vel) * (time + cur_pilot->ship->turn/180.) -
|
||||
0.5 * (cur_pilot->ship->thrust / cur_pilot->solid->mass)*time*time;
|
||||
|
||||
lua_pushnumber(L, dist); // return
|
||||
@ -520,9 +551,15 @@ static int ai_face(lua_State* L) {
|
||||
// This is generally good for coming to a halt.
|
||||
static int ai_brake(lua_State* L) {
|
||||
(void)L; // Just a hack to avoid -W -Wall warnings.
|
||||
double diff = angle_diff(cur_pilot->solid->dir, VANGLE(cur_pilot->solid->vel));
|
||||
pilot_turn = 10*diff;
|
||||
if(diff < MAX_DIR_ERR && VMOD(cur_pilot->solid->vel) > MIN_VEL_ERR)
|
||||
double diff, d;
|
||||
|
||||
d = cur_pilot->solid->dir+M_PI;
|
||||
if(d >= 2*M_PI) d = fmodf(d, 2*M_PI);
|
||||
|
||||
diff = angle_diff(d, VANGLE(cur_pilot->solid->vel));
|
||||
pilot_turn = -10*diff;
|
||||
|
||||
if(ABS(diff) < MAX_DIR_ERR && VMOD(cur_pilot->solid->vel) > MIN_VEL_ERR)
|
||||
pilot_acc = 1.;
|
||||
return 0;
|
||||
}
|
||||
@ -595,6 +632,16 @@ static int ai_getenemy(lua_State* L) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Set the enemy hostile. (Simply notifies of an impending attack).
|
||||
static int ai_hostile(lua_State* L) {
|
||||
MIN_ARGS(1);
|
||||
|
||||
if(lua_isnumber(L,1) && ((unsigned int)lua_tonumber(L,1) == PLAYER_ID))
|
||||
pilot_setFlag(cur_pilot, PILOT_HOSTILE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Set the timer.
|
||||
static int ai_settimer(lua_State* L) {
|
||||
MIN_ARGS(2);
|
||||
|
@ -162,14 +162,14 @@ static void enemies_parse(xmlNodePtr parent) {
|
||||
int i, *j, n, m, x, y, z, e;
|
||||
char* type;
|
||||
|
||||
i = 0;
|
||||
f = NULL;
|
||||
j = NULL;
|
||||
|
||||
node = parent->xmlChildrenNode;
|
||||
|
||||
do {
|
||||
if((node->type == XML_NODE_START) && (strcmp((char*)node->name, XML_ENEMIES_TAG)==0)) {
|
||||
i = 0;
|
||||
f = NULL;
|
||||
j = NULL;
|
||||
|
||||
cur = node->xmlChildrenNode;
|
||||
do {
|
||||
if(strcmp((char*)cur->name,"enemy")==0) {
|
||||
|
@ -132,8 +132,8 @@ static void simple_update(Solid* obj, const double dt) {
|
||||
#define RK4_MIN_H 0.01 // Minimal pass we want.
|
||||
static void rk4_update(Solid* obj, const double dt) {
|
||||
// Make sure angle doesn't flip.
|
||||
obj->dir += M_PI/360.*obj->dir_vel*dt;
|
||||
if(obj->dir > 2*M_PI) obj->dir -= 2*M_PI;
|
||||
obj->dir += M_PI/180.*obj->dir_vel*dt;
|
||||
if(obj->dir >= 2*M_PI) obj->dir -= 2*M_PI;
|
||||
if(obj->dir < 0.) obj->dir += 2*M_PI;
|
||||
|
||||
int N = (dt > RK4_MIN_H) ? (int)(dt/RK4_MIN_H) : 1;
|
||||
|
34
src/pilot.c
34
src/pilot.c
@ -20,7 +20,7 @@
|
||||
#define FLEET_DATA "../dat/fleet.xml"
|
||||
|
||||
// Stack of pilot id's to assure uniqueness.
|
||||
static unsigned int pilot_id = 0;
|
||||
static unsigned int pilot_id = PLAYER_ID;
|
||||
|
||||
// Stack of pilots - yes, they come in stacks now.
|
||||
Pilot** pilot_stack = NULL; // Not static, it is used in player.c and weapon.c and ai.c
|
||||
@ -41,7 +41,7 @@ void pilot_render(Pilot* pilot);
|
||||
static void pilot_free(Pilot* p);
|
||||
static Fleet* fleet_parse(const xmlNodePtr parent);
|
||||
|
||||
// Get the next pilot based on player_id.
|
||||
// Get the next pilot based on id.
|
||||
unsigned int pilot_getNext(const unsigned int id) {
|
||||
// Regular search.
|
||||
int i;
|
||||
@ -49,20 +49,37 @@ unsigned int pilot_getNext(const unsigned int id) {
|
||||
if(pilot_stack[i]->id == id)
|
||||
break;
|
||||
|
||||
if(i == pilots-1) return 0;
|
||||
if(i == pilots-1) return PLAYER_ID;
|
||||
|
||||
return pilot_stack[i+1]->id;
|
||||
}
|
||||
|
||||
// Get the nearest enemy to the pilot -- Tamir's (insightful) request.
|
||||
unsigned int pilot_getNearest(Pilot* p) {
|
||||
int i, tp;
|
||||
unsigned int pilot_getNearest(const Pilot* p) {
|
||||
unsigned int tp;
|
||||
int i;
|
||||
double d, td;
|
||||
|
||||
for(tp = -1, i = 0; i < pilots; i++)
|
||||
for(tp = 0, d = 0., i = 0; i < pilots; i++)
|
||||
if(areEnemies(p->faction, pilot_stack[i]->faction)) {
|
||||
td = vect_dist(&pilot_stack[i]->solid->pos, &p->solid->pos);
|
||||
if((tp == -1) || (td < d)) {
|
||||
if((!tp) || (td < d)) {
|
||||
d = td;
|
||||
tp = pilot_stack[i]->id;
|
||||
}
|
||||
}
|
||||
return tp;
|
||||
}
|
||||
|
||||
// Get the nearest hostile enemy to the player.
|
||||
unsigned pilot_getHostile(void) {
|
||||
unsigned int tp;
|
||||
int i;
|
||||
double d, td;
|
||||
for(tp = PLAYER_ID, d = 0., i = 0; i < pilots; i++)
|
||||
if(pilot_isFlag(pilot_stack[i], PILOT_HOSTILE)) {
|
||||
td = vect_dist(&pilot_stack[i]->solid->pos, &player->solid->pos);
|
||||
if((tp == PLAYER_ID) || (td < d)) {
|
||||
d = td;
|
||||
tp = pilot_stack[i]->id;
|
||||
}
|
||||
@ -80,7 +97,6 @@ Pilot* pilot_get(const unsigned int id) {
|
||||
return NULL;
|
||||
|
||||
if(id == 0) return player;
|
||||
DEBUG("id = %d", id);
|
||||
#if 0
|
||||
// Dichotomical search.
|
||||
int i, n;
|
||||
@ -177,7 +193,7 @@ void pilot_init(Pilot* pilot, Ship* ship, char* name, Faction* faction, AI_Profi
|
||||
const double dir, const Vec2* pos, const Vec2* vel, const int flags) {
|
||||
|
||||
if(flags & PILOT_PLAYER) // Player is ID 0
|
||||
pilot->id = 0;
|
||||
pilot->id = PLAYER_ID;
|
||||
else
|
||||
pilot->id = ++pilot_id; // New unique pilot id based on pilot_id, Can't be 0.
|
||||
|
||||
|
10
src/pilot.h
10
src/pilot.h
@ -6,7 +6,7 @@
|
||||
#include "faction.h"
|
||||
#include "ship.h"
|
||||
|
||||
#define PLAYER_ID 0
|
||||
#define PLAYER_ID 1
|
||||
|
||||
// Aproximation for pilot size.
|
||||
#define PILOT_SIZE_APROX 0.8
|
||||
@ -21,6 +21,9 @@
|
||||
// Dynamic.
|
||||
#define PILOT_HOSTILE (1<<1) // Pilot is hostile to the player.
|
||||
|
||||
// Just makes life simpler.
|
||||
#define pilot_isPlayer(p) ((p)->flags & PILOT_PLAYER)
|
||||
|
||||
typedef struct {
|
||||
Outfit* outfit; // Associated outfit.
|
||||
unsigned int quantity; // Number of outfits of this type that the pilot has.
|
||||
@ -79,8 +82,9 @@ typedef struct {
|
||||
// Grabing pilot crap.
|
||||
extern Pilot* player; // The player.
|
||||
Pilot* pilot_get(unsigned int id);
|
||||
unsigned int pilot_getNext(unsigned int id);
|
||||
unsigned int pilot_getNearest(Pilot* p);
|
||||
unsigned int pilot_getNext(const unsigned int id);
|
||||
unsigned int pilot_getNearest(const Pilot* p);
|
||||
unsigned int pilot_getHostile(void); // Only for the player.
|
||||
Fleet* fleet_get(const char* name);
|
||||
|
||||
// MISC.
|
||||
|
@ -31,7 +31,7 @@ Pilot* player = NULL; // extern in pilot.h
|
||||
static double player_turn = 0.; // Turn velocity from input.
|
||||
static double player_acc = 0.; // Accel velocity from input.
|
||||
static int player_primary = 0; // Player is shooting primary weapon.
|
||||
static unsigned int player_target = 0; // Targetted pilot.
|
||||
static unsigned int player_target = PLAYER_ID; // Targetted pilot.
|
||||
|
||||
// Pilot stuff for GUI.
|
||||
extern Pilot** pilot_stack;
|
||||
@ -141,7 +141,7 @@ void player_render(void) {
|
||||
Vec2 v;
|
||||
|
||||
// Render the player target graphics.
|
||||
if(player_target) {
|
||||
if(player_target != PLAYER_ID) {
|
||||
p = pilot_get(player_target);
|
||||
|
||||
vect_csetmin(&v, VX(p->solid->pos) - p->ship->gfx_space->sw * PILOT_SIZE_APROX/2.,
|
||||
@ -219,7 +219,7 @@ void player_render(void) {
|
||||
gui_renderBar(&cEnergy, &gui.pos_energy, &gui.energy, player->energy / player->energy_max);
|
||||
|
||||
// Target.
|
||||
if(player_target) {
|
||||
if(player_target != PLAYER_ID) {
|
||||
p = pilot_get(player_target);
|
||||
|
||||
gl_blitStatic(p->ship->gfx_target, &gui.pos_target);
|
||||
@ -452,7 +452,7 @@ static void input_key(int keynum, double value, int abs) {
|
||||
if(value == KEY_PRESS) player_target = pilot_getNext(player_target);
|
||||
}
|
||||
else if(strcmp(player_input[keynum]->name, "target_nearest")==0) {
|
||||
if(value == KEY_PRESS) player_target = pilot_getNearest(player);
|
||||
if(value == KEY_PRESS) player_target = pilot_getHostile();
|
||||
}
|
||||
// Zoom in.
|
||||
else if(strcmp(player_input[keynum]->name, "mapzoomin")==0) {
|
||||
|
@ -128,7 +128,7 @@ static void weapon_update(Weapon* w, const double dt, WeaponLayer layer) {
|
||||
CollideSprite(w->outfit->gfx_space, wsx, wsy, &w->solid->pos,
|
||||
pilot_stack[i]->ship->gfx_space, psx, psy, &pilot_stack[i]->solid->pos)) {
|
||||
|
||||
if(i != PLAYER_ID)
|
||||
if(!pilot_isPlayer(pilot_stack[i]))
|
||||
// Inform the ai it has been attacked. Useless if we are player.
|
||||
ai_attacked(pilot_stack[i], w->parent);
|
||||
if(w->parent == PLAYER_ID) // Make hostile to player.
|
||||
|
Loading…
Reference in New Issue
Block a user