[Add] Ai profile support.
This commit is contained in:
parent
dbfef7b7f0
commit
58e7c9b3d7
@ -1,18 +1,21 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Fleets>
|
||||
<fleet name="Test">
|
||||
<ai>test</ai>
|
||||
<faction>Independent</faction>
|
||||
<pilots>
|
||||
<pilot chance='100'>Test</pilot>
|
||||
</pilots>
|
||||
</fleet>
|
||||
<fleet name="Merchant Ship">
|
||||
<ai>merchant</ai>
|
||||
<faction>Merchant</faction>
|
||||
<pilots>
|
||||
<pilot chance='100'>Ship</pilot>
|
||||
</pilots>
|
||||
</fleet>
|
||||
<fleet name="Sml Merchant Convoy">
|
||||
<ai>merchant</ai>
|
||||
<faction>Merchant</faction>
|
||||
<pilots>
|
||||
<pilot chance='80'>Ship</pilot>
|
||||
|
41
scripts/ai/merchant.lua
Normal file
41
scripts/ai/merchant.lua
Normal file
@ -0,0 +1,41 @@
|
||||
-- Required control rate.
|
||||
control_rate = 2
|
||||
|
||||
-- Required "control" function.
|
||||
function control()
|
||||
pushtask(0, "fly")
|
||||
end
|
||||
|
||||
-- Required "attacked" function.
|
||||
function attacked(attacker)
|
||||
task = taskname()
|
||||
if task ~= "runaway" then
|
||||
-- Let's have some messages.
|
||||
if attacker == player then
|
||||
msg = rng(0,4)
|
||||
if msg == 0 then say("ARGH! Please don't hurt me.")
|
||||
elseif msg == 1 then say("HEY! We are simply a merchant vessle.")
|
||||
elseif msg == 2 then say("LEAVE! ME! ALONE!")
|
||||
end
|
||||
end
|
||||
pushtask(0, "runaway", attacker)
|
||||
end
|
||||
end
|
||||
|
||||
-- Runs away.
|
||||
function runaway()
|
||||
target = gettargetid()
|
||||
dir = face(target, 1)
|
||||
accel()
|
||||
end
|
||||
|
||||
-- Fly to the player.
|
||||
function fly()
|
||||
target = 0
|
||||
dir = face(target)
|
||||
dist = getdist(getpos(target))
|
||||
if dir < 10 and dist > 300 then
|
||||
accel()
|
||||
end
|
||||
end
|
||||
|
@ -10,6 +10,15 @@ end
|
||||
function attacked(attacker)
|
||||
task = taskname()
|
||||
if task ~= "attack" and task ~= "runaway" then
|
||||
-- Let's have some taunts.
|
||||
if attacker == player then
|
||||
msg = rng(0,4)
|
||||
if msg == 0 then say("You will never kill me!")
|
||||
elseif msg == 1 then say("DIE!")
|
||||
elseif msg == 2 then say("You won't survive!")
|
||||
elseif msg == 3 then say("I hate you!")
|
||||
end
|
||||
end
|
||||
pushtask(0, "attack", attacker)
|
||||
end
|
||||
end
|
||||
@ -20,10 +29,6 @@ function runaway()
|
||||
dir = face(target, 1)
|
||||
accel()
|
||||
dist = getdist(getpos(target))
|
||||
|
||||
if dist > 800 then
|
||||
say("So long Biatch!!")
|
||||
end
|
||||
end
|
||||
|
||||
-- Attack
|
||||
|
149
src/ai.c
149
src/ai.c
@ -1,7 +1,6 @@
|
||||
// Woot, LUA!!!!!!
|
||||
#include <lua.h>
|
||||
#include <lauxlib.h>
|
||||
#include <lualib.h>
|
||||
#include "lauxlib.h"
|
||||
#include "lualib.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
@ -12,6 +11,8 @@
|
||||
#include "physics.h"
|
||||
#include "pack.h"
|
||||
#include "rng.h"
|
||||
#include "space.h"
|
||||
#include "faction.h"
|
||||
#include "ai.h"
|
||||
|
||||
// == AI ======================================================
|
||||
@ -47,6 +48,7 @@
|
||||
|
||||
// Call the AI function with name f.
|
||||
#define AI_LCALL(f) (lua_getglobal(L, f), lua_pcall(L, 0, 0, 0))
|
||||
#define lua_regnumber(s,n) (lua_pushnumber(L,n), lua_setglobal(L,s))
|
||||
|
||||
// Don't run the function if (n) params aren't passed.
|
||||
#define MIN_ARGS(n) if(lua_gettop(L) < n) return 0
|
||||
@ -54,10 +56,21 @@
|
||||
#define MAX_DIR_ERR 5.0*M_PI/180.
|
||||
#define MIN_VEL_ERR 2.5
|
||||
|
||||
// file info.
|
||||
#define AI_PREFIX "../scripts/ai/"
|
||||
#define AI_SUFFIX ".lua"
|
||||
|
||||
// AI profiles.
|
||||
static AI_Profile* profiles = NULL;
|
||||
static int nprofiles = 0;
|
||||
// Current AI Lua interpreter.
|
||||
static lua_State* L = NULL;
|
||||
|
||||
static int ai_minbrakedist(lua_State* L); // Minimal breaking distance.
|
||||
static int ai_accel(lua_State* L); // Accelerate.
|
||||
|
||||
// Internal C routines.
|
||||
static int ai_loadProfile(char* filename);
|
||||
static void ai_freetask(Task* t);
|
||||
// External C routines.
|
||||
void ai_attacked(Pilot* attacked, const unsigned int attacker); // weapon.c
|
||||
@ -74,7 +87,7 @@ static int ai_shield(lua_State* L); // shield()
|
||||
static int ai_parmor(lua_State* L); // parmor()
|
||||
static int ai_pshield(lua_State* L); // pshield()
|
||||
static int ai_getdistance(lua_State* L); // Number getdist(Vec2)
|
||||
static int ai_getpos(lua_State* L); // getpos(number/pilot)
|
||||
static int ai_getpos(lua_State* L); // getpos(number)
|
||||
static int ai_minbrakedist(lua_State* L); // Number minbrakedist()
|
||||
// Boolean expressions.
|
||||
static int ai_ismaxvel(lua_State* L); // Boolean ismaxvel()
|
||||
@ -86,17 +99,16 @@ static int ai_accel(lua_State* L); // accel(number); nuimber <= 1.
|
||||
static int ai_turn(lua_State* L); // turn(number); abs(number) <= 1.
|
||||
static int ai_face(lua_State* L); // face(number/pointer)
|
||||
static int ai_brake(lua_State* L); // Brake()
|
||||
static int ai_getnearestplanet(lua_State* L); // pointer getnearestplanet()
|
||||
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); // pointer getenemy().
|
||||
static int ai_getenemy(lua_State* L); // number getenemy().
|
||||
// Misc.
|
||||
static int ai_createvect(lua_State* L); // createvect(number, number)
|
||||
static int ai_say(lua_State* L); // say(string)
|
||||
static int ai_rng(lua_State* L); // rng(number, number)
|
||||
|
||||
// Global Lua interpreter.
|
||||
static lua_State* L = NULL;
|
||||
|
||||
// Current pilot "thinking" and assorted variables.
|
||||
static Pilot* cur_pilot = NULL;
|
||||
static double pilot_acc = 0.;
|
||||
@ -111,14 +123,52 @@ void ai_destroy(Pilot* p) {
|
||||
|
||||
// Init the AI stuff. Which is basically Lua.
|
||||
int ai_init(void) {
|
||||
L = luaL_newstate();
|
||||
if(L == NULL) {
|
||||
char** files;
|
||||
uint32_t nfiles, i;
|
||||
|
||||
// Get the file list.
|
||||
files = pack_listfiles(data, &nfiles);
|
||||
|
||||
// Load the profiles.
|
||||
for(i = 0; i < nfiles; i++)
|
||||
if((strncmp(files[i], AI_PREFIX, strlen(AI_PREFIX))==0 &&
|
||||
strncmp(files[i] + strlen(files[i]) - strlen(AI_SUFFIX),
|
||||
AI_SUFFIX, strlen(AI_SUFFIX))==0))
|
||||
if(ai_loadProfile(files[i]))
|
||||
WARN("Error loading AI profile '%s'", files[i]);
|
||||
|
||||
// Free the char allocated by pack.
|
||||
for(i = 0; i < nfiles; i++)
|
||||
free(files[i]);
|
||||
free(files);
|
||||
|
||||
DEBUG("Loaded %d AI profile%c", nprofiles, (nprofiles==1)?' ':'s');
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Init an IA_Profile and add it to the stack.
|
||||
static int ai_loadProfile(char* filename) {
|
||||
char* buf;
|
||||
|
||||
profiles = realloc(profiles, sizeof(AI_Profile)*(++nprofiles));
|
||||
profiles[nprofiles-1].name = strndup(filename+strlen(AI_PREFIX),
|
||||
strlen(filename)-strlen(AI_PREFIX)-strlen(AI_SUFFIX));
|
||||
|
||||
profiles[nprofiles-1].L = luaL_newstate();
|
||||
|
||||
if(profiles[nprofiles-1].L == NULL) {
|
||||
ERR("Unable to create a new Lua state");
|
||||
return -1;
|
||||
}
|
||||
|
||||
L = profiles[nprofiles-1].L;
|
||||
|
||||
// Open the standard Lua libraries.
|
||||
luaL_openlibs(L);
|
||||
//luaL_openlibs(L);
|
||||
|
||||
// Constants.
|
||||
lua_regnumber("player", PLAYER_ID); // Player id.
|
||||
|
||||
// Register C funstions in Lua.
|
||||
// Tasks.
|
||||
@ -145,6 +195,8 @@ int ai_init(void) {
|
||||
lua_register(L, "turn", ai_turn);
|
||||
lua_register(L, "face", ai_face);
|
||||
lua_register(L, "brake", ai_brake);
|
||||
lua_register(L, "getnearestplanet", ai_getnearestplanet);
|
||||
lua_register(L, "getrndplanet", ai_getrndplanet);
|
||||
// Combat.
|
||||
lua_register(L, "shoot", ai_shoot);
|
||||
lua_register(L, "getenemy", ai_getenemy);
|
||||
@ -153,10 +205,11 @@ int ai_init(void) {
|
||||
lua_register(L, "say", ai_say);
|
||||
lua_register(L, "rng", ai_rng);
|
||||
|
||||
char* buf = pack_readfile(DATA, "../scripts/ai/test.lua", NULL);
|
||||
buf = pack_readfile(DATA, filename, NULL);
|
||||
|
||||
if(luaL_dostring(L, buf) != 0) {
|
||||
ERR("loading AI file: %s", "../scripts/ai/test.lua");
|
||||
ERR("%s", lua_tostring(L, -1));
|
||||
WARN("Most likely Lua file has improper syntax, please check it.");
|
||||
return -1;
|
||||
}
|
||||
@ -166,6 +219,19 @@ int ai_init(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Get the AI_Profile with name.
|
||||
AI_Profile* ai_getProfile(char* name) {
|
||||
if(profiles == NULL) return NULL;
|
||||
|
||||
int i;
|
||||
for(i = 0; i < nprofiles; i++)
|
||||
if(strcmp(name, profiles[i].name)==0)
|
||||
return &profiles[i];
|
||||
|
||||
WARN("AI Profile '%s' not found in AI stack", name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Clean up global AI
|
||||
void ai_exit(void) {
|
||||
lua_close(L);
|
||||
@ -174,6 +240,7 @@ void ai_exit(void) {
|
||||
// Heart of hearts of the ai!! Brains of the pilot.
|
||||
void ai_think(Pilot* pilot) {
|
||||
cur_pilot = pilot; // Set current pilot being processed.
|
||||
L = cur_pilot->ai->L; // Set the AI profile to the current pilot's.
|
||||
|
||||
// Clean up some variables.
|
||||
pilot_acc = pilot_turn = 0.;
|
||||
@ -202,6 +269,7 @@ void ai_think(Pilot* pilot) {
|
||||
// Pilot is attacked.
|
||||
void ai_attacked(Pilot* attacked, const unsigned int attacker) {
|
||||
cur_pilot = attacked;
|
||||
L = cur_pilot->ai->L;
|
||||
lua_getglobal(L, "attacked");
|
||||
lua_pushnumber(L, attacker);
|
||||
lua_pcall(L, 1, 0, 0);
|
||||
@ -241,8 +309,10 @@ static int ai_pushtask(lua_State* L) {
|
||||
t->ID = (unsigned int) lua_tonumber(L, 3);
|
||||
}
|
||||
else if(lua_islightuserdata(L, 3)) {
|
||||
// Only pointer valid is Vec2* in Lua.
|
||||
t->dtype = TYPE_PTR;
|
||||
t->target = (void*)lua_topointer(L, 3);
|
||||
t->target = MALLOC_L(Vec2);
|
||||
vectcpy(t->target, (Vec2*)lua_topointer(L,3));
|
||||
} else
|
||||
t->dtype = TYPE_NULL;
|
||||
}
|
||||
@ -325,7 +395,7 @@ static int ai_pshield(lua_State* L) {
|
||||
static int ai_getdistance(lua_State* L) {
|
||||
MIN_ARGS(1);
|
||||
Vec2* vect = (Vec2*)lua_topointer(L,1);
|
||||
lua_pushnumber(L, DIST(*vect, cur_pilot->solid->pos));
|
||||
lua_pushnumber(L, vect_dist(vect, &cur_pilot->solid->pos));
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -333,7 +403,6 @@ static int ai_getdistance(lua_State* L) {
|
||||
static int ai_getpos(lua_State* L) {
|
||||
Pilot* p;
|
||||
if(lua_isnumber(L, 1)) p = pilot_get((int)lua_tonumber(L,1)); // Pilot ID.
|
||||
else if(lua_islightuserdata(L, 1)) p = (Pilot*)lua_topointer(L, 1); // Pilot pointer.
|
||||
else p = cur_pilot; // Default to ones self.
|
||||
|
||||
lua_pushlightuserdata(L, &p->solid->pos);
|
||||
@ -432,6 +501,56 @@ static int ai_brake(lua_State* L) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Return the nearest friendly planet's position to the pilot.
|
||||
static int ai_getnearestplanet(lua_State* L) {
|
||||
if(cur_system->nplanets == 0) return 0; // No planets.
|
||||
|
||||
double dist, d;
|
||||
int i, j;
|
||||
|
||||
// Cycle through planets.
|
||||
for(dist = 0., j = -1, i = 0; i < cur_system->nplanets; i++) {
|
||||
d = vect_dist(&cur_system->planets[i].pos, &cur_pilot->solid->pos);
|
||||
if((!areEnemies(cur_pilot->faction, cur_system->planets[i].faction)) &&
|
||||
(d < dist)) {
|
||||
// Closer friendly planet.
|
||||
j = i;
|
||||
dist = d;
|
||||
}
|
||||
}
|
||||
|
||||
// No friendly planet found.
|
||||
if(j == -1) return 0;
|
||||
|
||||
lua_pushlightuserdata(L, &cur_system->planets[j].pos);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Return a random friendly planet's position to the pilot.
|
||||
static int ai_getrndplanet(lua_State* L) {
|
||||
if(cur_system->nplanets == 0) return 0; // No planets.
|
||||
|
||||
Planet** planets;
|
||||
int nplanets, i;
|
||||
planets = malloc(sizeof(Planet*) * cur_system->nplanets);
|
||||
|
||||
for(nplanets = 0, i = 0; i < cur_system->nplanets; i++)
|
||||
if(!areEnemies(cur_pilot->faction, cur_system->planets[i].faction))
|
||||
planets[nplanets++] = &cur_system->planets[i];
|
||||
|
||||
// No planet to land on found.
|
||||
if(nplanets == 0) {
|
||||
free(planets);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// We can actually get a random planet now.
|
||||
i = RNG(0,nplanets-1);
|
||||
lua_pushlightuserdata(L, &planets[i]->pos);
|
||||
free(planets);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Pew pew.. Says the pilot.
|
||||
static int ai_shoot(lua_State* L) {
|
||||
int n = 1;
|
||||
|
10
src/ai.h
10
src/ai.h
@ -1,4 +1,5 @@
|
||||
#pragma once
|
||||
#include "lua.h"
|
||||
|
||||
typedef enum { TYPE_NULL, TYPE_INT, TYPE_PTR } TaskData;
|
||||
|
||||
@ -14,6 +15,15 @@ typedef struct Task {
|
||||
};
|
||||
} Task;
|
||||
|
||||
// Ai profile.
|
||||
typedef struct {
|
||||
char* name;
|
||||
lua_State* L;
|
||||
} AI_Profile;
|
||||
|
||||
// Misc.
|
||||
AI_Profile* ai_getProfile(char* name);
|
||||
|
||||
int ai_init(void);
|
||||
void ai_exit(void);
|
||||
|
||||
|
@ -178,7 +178,7 @@ int factions_load(void) {
|
||||
free(buf);
|
||||
xmlCleanupParser();
|
||||
|
||||
DEBUG("Loaded %d factions", nfactions);
|
||||
DEBUG("Loaded %d factions%c", nfactions, (nfactions==1)?' ':'s');
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -253,7 +253,7 @@ int main(int argc, char** argv) {
|
||||
space_load();
|
||||
|
||||
// Testing.
|
||||
pilot_create(ship_get("Ship"), "Player", faction_get("Player"), 0., NULL, NULL, PILOT_PLAYER);
|
||||
pilot_create(ship_get("Ship"), "Player", faction_get("Player"), NULL, 0., NULL, NULL, PILOT_PLAYER);
|
||||
gl_bindCamera(&player->solid->pos);
|
||||
space_init("SaraSys");
|
||||
|
||||
|
22
src/pack.c
22
src/pack.c
@ -294,30 +294,28 @@ void* pack_readfile(const char* packfile, const char* filename, uint32_t* filesi
|
||||
// Load the filenames int the packfile to filenames.
|
||||
// filenames should be freed after use
|
||||
// On error if filenames is (char**)-1.
|
||||
#define READ(f,b,n) if(read(f,b,n)!=n) { ERR("Too few bytes read. Expected more."); return; }
|
||||
void pack_listfiles(const char* packfile, char** filenames, uint32_t* nfiles) {
|
||||
#define READ(f,b,n) if(read(f,b,n)!=n) { ERR("Too few bytes read. Expected more."); return NULL; }
|
||||
char** pack_listfiles(const char* packfile, uint32_t* nfiles) {
|
||||
int fd, j;
|
||||
uint32_t i;
|
||||
char** filenames;
|
||||
char* buf = malloc(sizeof(magic));
|
||||
|
||||
*nfiles = 0;
|
||||
filenames = malloc(sizeof(char*));
|
||||
filenames = (char**)-1;
|
||||
|
||||
fd = open(packfile, O_RDONLY);
|
||||
if(fd == -1) {
|
||||
ERR("opening %s: %s", packfile, strerror(errno));
|
||||
return;
|
||||
return NULL;
|
||||
}
|
||||
READ(fd, buf, sizeof(magic)); // Make sure it is a packfile.
|
||||
if(memcpy(buf, &magic, sizeof(magic))) {
|
||||
if(memcmp(buf, &magic, sizeof(magic))) {
|
||||
ERR("File %s is not a valid packfile", packfile);
|
||||
return;
|
||||
return NULL;
|
||||
}
|
||||
free(buf);
|
||||
|
||||
READ(fd, &nfiles, 4);
|
||||
filenames = realloc(filenames,(*nfiles+1)*sizeof(char*));
|
||||
READ(fd, nfiles, 4);
|
||||
filenames = malloc(((*nfiles)+1)*sizeof(char*));
|
||||
for(i = 0; i < *nfiles; i++) {
|
||||
// Start searching files.
|
||||
j = 0;
|
||||
@ -325,9 +323,11 @@ void pack_listfiles(const char* packfile, char** filenames, uint32_t* nfiles) {
|
||||
READ(fd, &filenames[i][j], 1); // Get the name.
|
||||
while(filenames[i][j++] != '\0')
|
||||
READ(fd, &filenames[i][j], 1);
|
||||
READ(fd, buf, 4); // skip the location.
|
||||
}
|
||||
filenames[i] = NULL;
|
||||
free(buf);
|
||||
close(fd);
|
||||
return filenames;
|
||||
}
|
||||
#undef READ
|
||||
|
||||
|
@ -19,5 +19,5 @@ int pack_close(Packfile* file);
|
||||
|
||||
// Fancy stuff.
|
||||
void* pack_readfile(const char* packfile, const char* filename, uint32_t* filesize);
|
||||
void pack_listfiles(const char* packfile, char** filenames, uint32_t* nfiles);
|
||||
char** pack_listfiles(const char* packfile, uint32_t* nfiles);
|
||||
|
||||
|
@ -58,8 +58,8 @@ double vect_angle(const Vec2* ref, const Vec2* v) {
|
||||
}
|
||||
|
||||
void vect_cadd(Vec2* v, const double x, const double y) {
|
||||
v->x -= x;
|
||||
v->y -= y;
|
||||
v->x += x;
|
||||
v->y += y;
|
||||
v->mod = MOD(v->x, v->y);
|
||||
v->angle = ANGLE(v->x, v->y);
|
||||
}
|
||||
|
@ -9,7 +9,7 @@
|
||||
#define MOD(x,y) (sqrt((x)*(x) + (y)*(y)))
|
||||
#define ANGLE(x,y)(((x)==0.) ? 0. : (((x)<0.)?atan((y)/(x))+M_PI:atan((y)/(x))))
|
||||
|
||||
#define DIST(v,u) MOD((v).x-(u).x, (v).y-(u).y)
|
||||
#define vect_dist(v,u) MOD((v)->x-(u)->x, (v)->y-(u)->y)
|
||||
|
||||
// Misc
|
||||
double angle_diff(const double ref, double a);
|
||||
|
14
src/pilot.c
14
src/pilot.c
@ -161,8 +161,8 @@ static void pilot_update(Pilot* pilot, const double dt) {
|
||||
// pos : Initial position.
|
||||
// flags : Tweaking the pilot.
|
||||
// ========================================================
|
||||
void pilot_init(Pilot* pilot, Ship* ship, char* name, Faction* faction, const double dir, const Vec2* pos,
|
||||
const Vec2* vel, const int flags) {
|
||||
void pilot_init(Pilot* pilot, Ship* ship, char* name, Faction* faction, AI_Profile* ai,
|
||||
const double dir, const Vec2* pos, const Vec2* vel, const int flags) {
|
||||
|
||||
if(flags & PILOT_PLAYER) // Player is ID 0
|
||||
pilot->id = 0;
|
||||
@ -175,6 +175,9 @@ void pilot_init(Pilot* pilot, Ship* ship, char* name, Faction* faction, const do
|
||||
// Faction.
|
||||
pilot->faction = faction;
|
||||
|
||||
// AI.
|
||||
pilot->ai = ai;
|
||||
|
||||
// Solid.
|
||||
pilot->solid = solid_create(ship->mass, dir, pos, vel);
|
||||
|
||||
@ -218,14 +221,14 @@ void pilot_init(Pilot* pilot, Ship* ship, char* name, Faction* faction, const do
|
||||
}
|
||||
|
||||
// Create a new pilot - Params are same as pilot_init. Return pilot's id.
|
||||
unsigned int pilot_create(Ship* ship, char* name, Faction* faction, const double dir,
|
||||
unsigned int pilot_create(Ship* ship, char* name, Faction* faction, AI_Profile* ai, const double dir,
|
||||
const Vec2* pos, const Vec2* vel, const int flags) {
|
||||
Pilot* dyn = MALLOC_L(Pilot);
|
||||
if(dyn == NULL) {
|
||||
WARN("Unable to allocate memory.");
|
||||
return 0;
|
||||
}
|
||||
pilot_init(dyn, ship, name, faction, dir, pos, vel, flags);
|
||||
pilot_init(dyn, ship, name, faction, ai, dir, pos, vel, flags);
|
||||
|
||||
if(flags & PILOT_PLAYER) {
|
||||
// Player.
|
||||
@ -311,6 +314,8 @@ static Fleet* fleet_parse(const xmlNodePtr parent) {
|
||||
// Load all the data.
|
||||
if(strcmp((char*)node->name, "faction")==0)
|
||||
tmp->faction = faction_get((char*)node->children->content);
|
||||
else if(strcmp((char*)node->name, "ai")==0)
|
||||
tmp->ai = ai_getProfile((char*)node->children->content);
|
||||
else if(strcmp((char*)node->name, "pilots")==0) {
|
||||
cur = node->children;
|
||||
while((cur = cur->next)) {
|
||||
@ -340,6 +345,7 @@ static Fleet* fleet_parse(const xmlNodePtr parent) {
|
||||
}
|
||||
}
|
||||
#define MELEMENT(o,s) if((o) == NULL) WARN("Fleet '%s' missing '"s"' element", tmp->name)
|
||||
MELEMENT(tmp->ai, "ai");
|
||||
MELEMENT(tmp->faction, "faction");
|
||||
MELEMENT(tmp->pilots, "pilots");
|
||||
#undef MELEMENT
|
||||
|
11
src/pilot.h
11
src/pilot.h
@ -51,6 +51,7 @@ typedef struct Pilot {
|
||||
unsigned int flags; // Used for AI etc.
|
||||
|
||||
// AI.
|
||||
AI_Profile* ai; // Ai personality profile.
|
||||
Task* task; // Current action.
|
||||
} Pilot;
|
||||
|
||||
@ -65,6 +66,8 @@ typedef struct {
|
||||
char* name; // Fleet name, used as an identifier.
|
||||
Faction* faction; // Faction of the fleet.
|
||||
|
||||
AI_Profile* ai; // A useable profile.
|
||||
|
||||
FleetPilot* pilots; // The pilots in the fleet.
|
||||
int npilots; // Total number of pilots.
|
||||
} Fleet;
|
||||
@ -80,11 +83,11 @@ void pilot_shoot(Pilot* p, const int secondary);
|
||||
void pilot_hit(Pilot* p, const double damage_shield, const double damage_armor);
|
||||
|
||||
// Creation.
|
||||
void pilot_init(Pilot* dest, Ship* ship, char* name, Faction* faction, const double dir,
|
||||
const Vec2* pos, const Vec2* vel, const int flags);
|
||||
void pilot_init(Pilot* dest, Ship* ship, char* name, Faction* faction, AI_Profile* ai,
|
||||
const double dir, const Vec2* pos, const Vec2* vel, const int flags);
|
||||
|
||||
unsigned int pilot_create(Ship* ship, char* name, Faction* faction, const double dir,
|
||||
const Vec2* pos, const Vec2* vel, const int flags);
|
||||
unsigned int pilot_create(Ship* ship, char* name, Faction* faction, AI_Profile* ai,
|
||||
const double dir, const Vec2* pos, const Vec2* vel, const int flags);
|
||||
|
||||
// Init/Cleanup.
|
||||
void pilot_destroy(Pilot* p);
|
||||
|
@ -2,6 +2,8 @@
|
||||
#include <SDL.h>
|
||||
#include "pilot.h"
|
||||
|
||||
#define PLAYER_ID 0
|
||||
|
||||
extern Pilot* pilot;
|
||||
|
||||
typedef enum { KEYBIND_NULL, KEYBIND_KEYBOARD, KEYBIND_JAXIS, KEYBIND_JBUTTON } KeybindType;
|
||||
|
63
src/space.c
63
src/space.c
@ -4,12 +4,10 @@
|
||||
|
||||
#include "log.h"
|
||||
#include "physics.h"
|
||||
#include "opengl.h"
|
||||
#include "rng.h"
|
||||
#include "pilot.h"
|
||||
#include "pack.h"
|
||||
#include "faction.h"
|
||||
#include "space.h"
|
||||
#include "faction.h"
|
||||
|
||||
#define XML_NODE_START 1
|
||||
#define XML_NODE_TEST 3
|
||||
@ -32,65 +30,9 @@
|
||||
#define FLAG_ASTEROIDSSET (1<<2)
|
||||
#define FLAG_INTEFERENCESET (1<<3)
|
||||
|
||||
// Planet types. I didn't take them from Star Trek, I promise.
|
||||
typedef enum {
|
||||
PLANET_CLASS_NULL = 0,
|
||||
PLANET_CLASS_A, // Geothermal.
|
||||
PLANET_CLASS_B, // Geomorteus.
|
||||
PLANET_CLASS_C, // Geoinactive.
|
||||
PLANET_CLASS_D, // Asteroid/Moon.
|
||||
PLANET_CLASS_E, // Geoplastic.
|
||||
PLANET_CLASS_F, // Geometallic.
|
||||
PLANET_CLASS_G, // GroCrystaline.
|
||||
PLANET_CLASS_H, // Desert.
|
||||
PLANET_CLASS_I, // Gas Supergiant.
|
||||
PLANET_CLASS_J, // Gas Giant.
|
||||
PLANET_CLASS_K, // Adaptable.
|
||||
PLANET_CLASS_L, // Marginal.
|
||||
PLANET_CLASS_M, // Terrestrial.
|
||||
PLANET_CLASS_N, // Reducing.
|
||||
PLANET_CLASS_O, // Pelagic.
|
||||
PLANET_CLASS_P, // Glaciated.
|
||||
PLANET_CLASS_Q, // Variable.
|
||||
PLANET_CLASS_R, // Rogue.
|
||||
PLANET_CLASS_S, // Ultragiant.
|
||||
PLANET_CLASS_T, // Ultragiant.
|
||||
PLANET_CLASS_X, // Demon.
|
||||
PLANET_CLASS_Y, // Demon.
|
||||
PLANET_CLASS_Z // Demon.
|
||||
} PlanetClass;
|
||||
|
||||
typedef struct {
|
||||
char* name; // Planet name
|
||||
Vec2 pos; // Position in star system.
|
||||
|
||||
PlanetClass class; // Planet type.
|
||||
Faction* faction; // Planet faction.
|
||||
gl_texture* gfx_space; // Graphics in space.
|
||||
} Planet;
|
||||
|
||||
// Star systems.
|
||||
typedef struct {
|
||||
Fleet* fleet; // Fleet to appear.
|
||||
int chance; // Chance of fleet appearing in the system.
|
||||
} SystemFleet;
|
||||
|
||||
typedef struct {
|
||||
char* name; // Star system identifier.
|
||||
Vec2 pos; // Position.
|
||||
int stars, asteroids; // Un numero!
|
||||
double interference; // Un uh.. Percentage.
|
||||
|
||||
Planet* planets; // Planets.
|
||||
int nplanets; // Total number of planets.
|
||||
|
||||
SystemFleet* fleets; // Fleets that can appear in the current system.
|
||||
int nfleets; // Total number of fleets.
|
||||
} StarSystem;
|
||||
|
||||
static StarSystem* systems = NULL;
|
||||
static int nsystems = 0;
|
||||
static StarSystem* cur_system = NULL; // Current star system.
|
||||
StarSystem* cur_system = NULL; // Current star system.
|
||||
|
||||
#define STAR_BUF 100 // Area to leave around screen, more = less repitition.
|
||||
typedef struct {
|
||||
@ -223,6 +165,7 @@ void space_init(const char* sysname) {
|
||||
pilot_create(cur_system->fleets[i].fleet->pilots[j].ship,
|
||||
cur_system->fleets[i].fleet->pilots[j].name,
|
||||
cur_system->fleets[i].fleet->faction,
|
||||
cur_system->fleets[i].fleet->ai,
|
||||
vect_angle(&v,&vn),
|
||||
&v,
|
||||
NULL,
|
||||
|
61
src/space.h
61
src/space.h
@ -1,7 +1,68 @@
|
||||
#pragma once
|
||||
#include "faction.h"
|
||||
#include "opengl.h"
|
||||
#include "pilot.h"
|
||||
|
||||
#define MIN_HYPERSPACE_DIST 1500
|
||||
|
||||
// Planet types. I didn't take them from Star Trek, I promise.
|
||||
typedef enum {
|
||||
PLANET_CLASS_NULL = 0,
|
||||
PLANET_CLASS_A, // Geothermal.
|
||||
PLANET_CLASS_B, // Geomorteus.
|
||||
PLANET_CLASS_C, // Geoinactive.
|
||||
PLANET_CLASS_D, // Asteroid/Moon.
|
||||
PLANET_CLASS_E, // Geoplastic.
|
||||
PLANET_CLASS_F, // Geometallic.
|
||||
PLANET_CLASS_G, // GroCrystaline.
|
||||
PLANET_CLASS_H, // Desert.
|
||||
PLANET_CLASS_I, // Gas Supergiant.
|
||||
PLANET_CLASS_J, // Gas Giant.
|
||||
PLANET_CLASS_K, // Adaptable.
|
||||
PLANET_CLASS_L, // Marginal.
|
||||
PLANET_CLASS_M, // Terrestrial.
|
||||
PLANET_CLASS_N, // Reducing.
|
||||
PLANET_CLASS_O, // Pelagic.
|
||||
PLANET_CLASS_P, // Glaciated.
|
||||
PLANET_CLASS_Q, // Variable.
|
||||
PLANET_CLASS_R, // Rogue.
|
||||
PLANET_CLASS_S, // Ultragiant.
|
||||
PLANET_CLASS_T, // Ultragiant.
|
||||
PLANET_CLASS_X, // Demon.
|
||||
PLANET_CLASS_Y, // Demon.
|
||||
PLANET_CLASS_Z // Demon.
|
||||
} PlanetClass;
|
||||
|
||||
typedef struct {
|
||||
char* name; // Planet name
|
||||
Vec2 pos; // Position in star system.
|
||||
|
||||
PlanetClass class; // Planet type.
|
||||
Faction* faction; // Planet faction.
|
||||
gl_texture* gfx_space; // Graphics in space.
|
||||
} Planet;
|
||||
|
||||
// Star systems.
|
||||
typedef struct {
|
||||
Fleet* fleet; // Fleet to appear.
|
||||
int chance; // Chance of fleet appearing in the system.
|
||||
} SystemFleet;
|
||||
|
||||
typedef struct {
|
||||
char* name; // Star system identifier.
|
||||
Vec2 pos; // Position.
|
||||
int stars, asteroids; // Un numero!
|
||||
double interference; // Un uh.. Percentage.
|
||||
|
||||
Planet* planets; // Planets.
|
||||
int nplanets; // Total number of planets.
|
||||
|
||||
SystemFleet* fleets; // Fleets that can appear in the current system.
|
||||
int nfleets; // Total number of fleets.
|
||||
} StarSystem;
|
||||
|
||||
extern StarSystem* cur_system; // Current star system.
|
||||
|
||||
// Load/Exit.
|
||||
void space_init(const char* sysname);
|
||||
int space_load(void);
|
||||
|
@ -158,12 +158,15 @@ static Weapon* weapon_create(const Outfit* outfit, const double dir, const Vec2*
|
||||
|
||||
switch(outfit->type) {
|
||||
case OUTFIT_TYPE_BOLT:
|
||||
// Need accuracy and speed based on player. -- Another contribution from VLack.
|
||||
rdir += RNG(-outfit->accuracy/2., outfit->accuracy/2.)/180.*M_PI;
|
||||
if((rdir > 2.*M_PI) || (rdir < 0.)) rdir = fmod(rdir, 2.*M_PI);
|
||||
vect_cset(&v, VX(*vel)+outfit->speed*cos(rdir), VANGLE(*vel)+outfit->speed*sin(rdir));
|
||||
vectcpy(&v, vel);
|
||||
vect_cadd(&v, outfit->speed*cos(rdir), outfit->speed*sin(rdir));
|
||||
w->solid = solid_create(mass, rdir, pos, &v);
|
||||
break;
|
||||
default:
|
||||
// Just dump it where the player is.
|
||||
w->solid = solid_create(mass, dir, pos, vel);
|
||||
break;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user