[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:
Allanis 2013-02-10 05:21:09 +00:00
parent f107574b38
commit a89395a54f
12 changed files with 133 additions and 47 deletions

View File

@ -16,9 +16,12 @@
</Alliances> </Alliances>
<Enemies> <Enemies>
<enemies> <enemies>
<enemy type = "faction">Player</enemy>
<enemy type = "alliance">Neutral</enemy> <enemy type = "alliance">Neutral</enemy>
<enemy type = "faction">Pirate</enemy> <enemy type = "faction">Pirate</enemy>
</enemies> </enemies>
<enemies>
<enemy type="faction">Pirate</enemy>
<enemy type="faction">Player</enemy>
</enemies>
</Enemies> </Enemies>
</Factions> </Factions>

View File

@ -5,7 +5,7 @@
<class>1</class> <class>1</class>
<movement> <movement>
<thrust>400</thrust> <thrust>400</thrust>
<turn>360</turn> <turn>180</turn>
<speed>360</speed> <speed>360</speed>
</movement> </movement>
<health> <health>
@ -23,7 +23,7 @@
<cap_cargo>20</cap_cargo> <cap_cargo>20</cap_cargo>
</characteristics> </characteristics>
<outfits> <outfits>
<outfit quantity='3'>laser</outfit> <outfit quantity='2'>laser</outfit>
</outfits> </outfits>
</ship> </ship>
<ship name="Enemy Test"> <ship name="Enemy Test">
@ -31,7 +31,7 @@
<class>1</class> <class>1</class>
<movement> <movement>
<thrust>180</thrust> <thrust>180</thrust>
<turn>360</turn> <turn>130</turn>
<speed>260</speed> <speed>260</speed>
</movement> </movement>
<health> <health>

View File

@ -51,7 +51,7 @@ function stop()
brake() brake()
if isstopped() then if isstopped() then
poptask() poptask()
settimer(0, rng(3000, 5000)) settimer(0, rng(8000, 15000))
pushtask(0, "land") pushtask(0, "land")
end end
end end

View File

@ -3,9 +3,23 @@ control_rate = 2
-- Required "control" function. -- Required "control" function.
function control() 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() 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) pushtask(0, "attack", enemy)
else else
pushtask(0, "fly") pushtask(0, "fly")
@ -36,22 +50,24 @@ function taunt()
if msg then comm(attacker, msg) end if msg then comm(attacker, msg) end
end end
-- Run away. -- Run away from the target.
function runaway() function runaway()
target = gettargerid() target = gettargerid()
dir = face(target, 1) dir = face(target, 1)
accel() accel()
end end
-- Attack. -- Attack the target.
function attack() function attack()
target = gettargetid() target = gettargetid()
dir = face(target) dir = face(target)
dist = getdist(getpos(target)) dist = getdist(getpos(target))
-- We need to know when to run away.
if parmor() < 70 then if parmor() < 70 then
poptask() poptask()
pushtask(0, "runaway", target) pushtask(0, "runaway", target)
-- Try to obliterate the target.
elseif dir < 10 and dist > 300 then elseif dir < 10 and dist > 300 then
accel() accel()
elseif dir < 10 and dist < 300 then elseif dir < 10 and dist < 300 then
@ -59,9 +75,9 @@ function attack()
end end
end end
-- Fly to the player. -- Fly to the player. Pointless until hyperspace is implemented.
function fly() function fly()
target = 0 target = player
dir = face(target) dir = face(target)
dist = getdist(getpos(target)) dist = getdist(getpos(target))
if dir < 10 and dist > 300 then if dir < 10 and dist > 300 then

View File

@ -50,7 +50,7 @@ end
-- Fly to the player. -- Fly to the player.
function fly() function fly()
target = 0 target = player
dir = face(target) dir = face(target)
dist = getdist(getpos(target)) dist = getdist(getpos(target))
if dir < 10 and dist > 300 then if dir < 10 and dist > 300 then

View File

@ -56,9 +56,9 @@
// Don't run the function if (n) params aren't passed. // Don't run the function if (n) params aren't passed.
#define MIN_ARGS(n) if(lua_gettop(L) < n) return 0 #define MIN_ARGS(n) if(lua_gettop(L) < n) return 0
#define MIN_DIR_ERR 5.0*M_PI/180. #define MIN_DIR_ERR 1.0*M_PI/180.
#define MAX_DIR_ERR 2.5*M_PI/180. #define MAX_DIR_ERR 0.1*M_PI/180.
#define MIN_VEL_ERR 2.5 #define MIN_VEL_ERR 0.5
// file info. // file info.
#define AI_PREFIX "../scripts/ai/" #define AI_PREFIX "../scripts/ai/"
@ -112,6 +112,7 @@ static int ai_getrndplanet(lua_State* L); // pointer getrndplanet()
// Combat. // Combat.
static int ai_shoot(lua_State* L); // shoot(number) number = 1,2,3. 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_getenemy(lua_State* L); // number getenemy().
static int ai_hostile(lua_State* L); // hostile(number).
// Timers. // Timers.
static int ai_settimer(lua_State* L); // settimer(number, number) static int ai_settimer(lua_State* L); // settimer(number, number)
static int ai_timeup(lua_State* L); // bool timeup(number) static int ai_timeup(lua_State* L); // bool timeup(number)
@ -213,6 +214,7 @@ static int ai_loadProfile(char* filename) {
// Combat. // Combat.
lua_register(L, "shoot", ai_shoot); lua_register(L, "shoot", ai_shoot);
lua_register(L, "getenemy", ai_getenemy); lua_register(L, "getenemy", ai_getenemy);
lua_register(L, "hostile", ai_hostile);
// Timers. // Timers.
lua_register(L, "settimer", ai_settimer); lua_register(L, "settimer", ai_settimer);
lua_register(L, "timeup", ai_timeup); lua_register(L, "timeup", ai_timeup);
@ -395,25 +397,54 @@ static int ai_gettargetid(lua_State* L) {
// Get the pilots armor. // Get the pilots armor.
static int ai_armor(lua_State* L) { 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; return 1;
} }
// Get pilots shield. // Get pilots shield.
static int ai_shield(lua_State* L) { 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; return 1;
} }
// Get the pilot's armor in percentage. // Get the pilot's armor in percentage.
static int ai_parmor(lua_State* L) { 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; return 1;
} }
// Get the pilot's shield in percentage. // Get the pilot's shield in percentage.
static int ai_pshield(lua_State* L) { 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; return 1;
} }
@ -449,7 +480,7 @@ static int ai_minbrakedist(lua_State* L) {
double time = VMOD(cur_pilot->solid->vel) / double time = VMOD(cur_pilot->solid->vel) /
(cur_pilot->ship->thrust / cur_pilot->solid->mass); (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; 0.5 * (cur_pilot->ship->thrust / cur_pilot->solid->mass)*time*time;
lua_pushnumber(L, dist); // return 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. // This is generally good for coming to a halt.
static int ai_brake(lua_State* L) { static int ai_brake(lua_State* L) {
(void)L; // Just a hack to avoid -W -Wall warnings. (void)L; // Just a hack to avoid -W -Wall warnings.
double diff = angle_diff(cur_pilot->solid->dir, VANGLE(cur_pilot->solid->vel)); double diff, d;
pilot_turn = 10*diff;
if(diff < MAX_DIR_ERR && VMOD(cur_pilot->solid->vel) > MIN_VEL_ERR) 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.; pilot_acc = 1.;
return 0; return 0;
} }
@ -595,6 +632,16 @@ static int ai_getenemy(lua_State* L) {
return 1; 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. // Set the timer.
static int ai_settimer(lua_State* L) { static int ai_settimer(lua_State* L) {
MIN_ARGS(2); MIN_ARGS(2);

View File

@ -161,15 +161,15 @@ static void enemies_parse(xmlNodePtr parent) {
Alliance* a; Alliance* a;
int i, *j, n, m, x, y, z, e; int i, *j, n, m, x, y, z, e;
char* type; char* type;
i = 0;
f = NULL;
j = NULL;
node = parent->xmlChildrenNode; node = parent->xmlChildrenNode;
do { do {
if((node->type == XML_NODE_START) && (strcmp((char*)node->name, XML_ENEMIES_TAG)==0)) { if((node->type == XML_NODE_START) && (strcmp((char*)node->name, XML_ENEMIES_TAG)==0)) {
i = 0;
f = NULL;
j = NULL;
cur = node->xmlChildrenNode; cur = node->xmlChildrenNode;
do { do {
if(strcmp((char*)cur->name,"enemy")==0) { if(strcmp((char*)cur->name,"enemy")==0) {

View File

@ -132,8 +132,8 @@ static void simple_update(Solid* obj, const double dt) {
#define RK4_MIN_H 0.01 // Minimal pass we want. #define RK4_MIN_H 0.01 // Minimal pass we want.
static void rk4_update(Solid* obj, const double dt) { static void rk4_update(Solid* obj, const double dt) {
// Make sure angle doesn't flip. // Make sure angle doesn't flip.
obj->dir += M_PI/360.*obj->dir_vel*dt; obj->dir += M_PI/180.*obj->dir_vel*dt;
if(obj->dir > 2*M_PI) obj->dir -= 2*M_PI; if(obj->dir >= 2*M_PI) obj->dir -= 2*M_PI;
if(obj->dir < 0.) 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; int N = (dt > RK4_MIN_H) ? (int)(dt/RK4_MIN_H) : 1;

View File

@ -20,7 +20,7 @@
#define FLEET_DATA "../dat/fleet.xml" #define FLEET_DATA "../dat/fleet.xml"
// Stack of pilot id's to assure uniqueness. // 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. // 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 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 void pilot_free(Pilot* p);
static Fleet* fleet_parse(const xmlNodePtr parent); 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) { unsigned int pilot_getNext(const unsigned int id) {
// Regular search. // Regular search.
int i; int i;
@ -49,20 +49,37 @@ unsigned int pilot_getNext(const unsigned int id) {
if(pilot_stack[i]->id == id) if(pilot_stack[i]->id == id)
break; break;
if(i == pilots-1) return 0; if(i == pilots-1) return PLAYER_ID;
return pilot_stack[i+1]->id; return pilot_stack[i+1]->id;
} }
// Get the nearest enemy to the pilot -- Tamir's (insightful) request. // Get the nearest enemy to the pilot -- Tamir's (insightful) request.
unsigned int pilot_getNearest(Pilot* p) { unsigned int pilot_getNearest(const Pilot* p) {
int i, tp; unsigned int tp;
int i;
double d, td; 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)) { if(areEnemies(p->faction, pilot_stack[i]->faction)) {
td = vect_dist(&pilot_stack[i]->solid->pos, &p->solid->pos); 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; d = td;
tp = pilot_stack[i]->id; tp = pilot_stack[i]->id;
} }
@ -80,7 +97,6 @@ Pilot* pilot_get(const unsigned int id) {
return NULL; return NULL;
if(id == 0) return player; if(id == 0) return player;
DEBUG("id = %d", id);
#if 0 #if 0
// Dichotomical search. // Dichotomical search.
int i, n; 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) { const double dir, const Vec2* pos, const Vec2* vel, const int flags) {
if(flags & PILOT_PLAYER) // Player is ID 0 if(flags & PILOT_PLAYER) // Player is ID 0
pilot->id = 0; pilot->id = PLAYER_ID;
else else
pilot->id = ++pilot_id; // New unique pilot id based on pilot_id, Can't be 0. pilot->id = ++pilot_id; // New unique pilot id based on pilot_id, Can't be 0.

View File

@ -6,7 +6,7 @@
#include "faction.h" #include "faction.h"
#include "ship.h" #include "ship.h"
#define PLAYER_ID 0 #define PLAYER_ID 1
// Aproximation for pilot size. // Aproximation for pilot size.
#define PILOT_SIZE_APROX 0.8 #define PILOT_SIZE_APROX 0.8
@ -21,6 +21,9 @@
// Dynamic. // Dynamic.
#define PILOT_HOSTILE (1<<1) // Pilot is hostile to the player. #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 { typedef struct {
Outfit* outfit; // Associated outfit. Outfit* outfit; // Associated outfit.
unsigned int quantity; // Number of outfits of this type that the pilot has. unsigned int quantity; // Number of outfits of this type that the pilot has.
@ -79,8 +82,9 @@ typedef struct {
// Grabing pilot crap. // Grabing pilot crap.
extern Pilot* player; // The player. extern Pilot* player; // The player.
Pilot* pilot_get(unsigned int id); Pilot* pilot_get(unsigned int id);
unsigned int pilot_getNext(unsigned int id); unsigned int pilot_getNext(const unsigned int id);
unsigned int pilot_getNearest(Pilot* p); unsigned int pilot_getNearest(const Pilot* p);
unsigned int pilot_getHostile(void); // Only for the player.
Fleet* fleet_get(const char* name); Fleet* fleet_get(const char* name);
// MISC. // MISC.

View File

@ -31,7 +31,7 @@ Pilot* player = NULL; // extern in pilot.h
static double player_turn = 0.; // Turn velocity from input. static double player_turn = 0.; // Turn velocity from input.
static double player_acc = 0.; // Accel velocity from input. static double player_acc = 0.; // Accel velocity from input.
static int player_primary = 0; // Player is shooting primary weapon. 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. // Pilot stuff for GUI.
extern Pilot** pilot_stack; extern Pilot** pilot_stack;
@ -141,7 +141,7 @@ void player_render(void) {
Vec2 v; Vec2 v;
// Render the player target graphics. // Render the player target graphics.
if(player_target) { if(player_target != PLAYER_ID) {
p = pilot_get(player_target); p = pilot_get(player_target);
vect_csetmin(&v, VX(p->solid->pos) - p->ship->gfx_space->sw * PILOT_SIZE_APROX/2., 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); gui_renderBar(&cEnergy, &gui.pos_energy, &gui.energy, player->energy / player->energy_max);
// Target. // Target.
if(player_target) { if(player_target != PLAYER_ID) {
p = pilot_get(player_target); p = pilot_get(player_target);
gl_blitStatic(p->ship->gfx_target, &gui.pos_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); if(value == KEY_PRESS) player_target = pilot_getNext(player_target);
} }
else if(strcmp(player_input[keynum]->name, "target_nearest")==0) { 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. // Zoom in.
else if(strcmp(player_input[keynum]->name, "mapzoomin")==0) { else if(strcmp(player_input[keynum]->name, "mapzoomin")==0) {

View File

@ -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, CollideSprite(w->outfit->gfx_space, wsx, wsy, &w->solid->pos,
pilot_stack[i]->ship->gfx_space, psx, psy, &pilot_stack[i]->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. // Inform the ai it has been attacked. Useless if we are player.
ai_attacked(pilot_stack[i], w->parent); ai_attacked(pilot_stack[i], w->parent);
if(w->parent == PLAYER_ID) // Make hostile to player. if(w->parent == PLAYER_ID) // Make hostile to player.