From 58e7c9b3d7af7e358901dbb4ceb4a8839dc8af4b Mon Sep 17 00:00:00 2001 From: Allanis Date: Sat, 9 Feb 2013 00:53:37 +0000 Subject: [PATCH] [Add] Ai profile support. --- dat/fleet.xml | 3 + scripts/ai/merchant.lua | 41 +++++++ scripts/ai/test.lua | 13 ++- src/ai.c | 247 +++++++++++++++++++++++++++++----------- src/ai.h | 10 ++ src/faction.c | 2 +- src/main.c | 2 +- src/pack.c | 22 ++-- src/pack.h | 2 +- src/physics.c | 4 +- src/physics.h | 2 +- src/pilot.c | 20 ++-- src/pilot.h | 11 +- src/player.h | 2 + src/space.c | 63 +--------- src/space.h | 61 ++++++++++ src/weapon.c | 5 +- 17 files changed, 353 insertions(+), 157 deletions(-) create mode 100644 scripts/ai/merchant.lua diff --git a/dat/fleet.xml b/dat/fleet.xml index a31e32e..f54c612 100644 --- a/dat/fleet.xml +++ b/dat/fleet.xml @@ -1,18 +1,21 @@ + test Independent Test + merchant Merchant Ship + merchant Merchant Ship diff --git a/scripts/ai/merchant.lua b/scripts/ai/merchant.lua new file mode 100644 index 0000000..e087480 --- /dev/null +++ b/scripts/ai/merchant.lua @@ -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 + diff --git a/scripts/ai/test.lua b/scripts/ai/test.lua index a878efe..7b15387 100644 --- a/scripts/ai/test.lua +++ b/scripts/ai/test.lua @@ -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 diff --git a/src/ai.c b/src/ai.c index 26338d6..f50f905 100644 --- a/src/ai.c +++ b/src/ai.c @@ -1,7 +1,6 @@ // Woot, LUA!!!!!! -#include -#include -#include +#include "lauxlib.h" +#include "lualib.h" #include @@ -12,6 +11,8 @@ #include "physics.h" #include "pack.h" #include "rng.h" +#include "space.h" +#include "faction.h" #include "ai.h" // == AI ====================================================== @@ -46,7 +47,8 @@ // ============================================================ // Call the AI function with name f. -#define AI_LCALL(f) (lua_getglobal(L, f), lua_pcall(L, 0, 0, 0)) +#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,48 +56,58 @@ #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 // Ai routines for Lua. // Tasks. -static int ai_pushtask(lua_State* L); // pushtask(string, number/pointer, number) -static int ai_poptask(lua_State* L); // poptask() -static int ai_taskname(lua_State* L); // Number taskname. +static int ai_pushtask(lua_State* L); // pushtask(string, number/pointer, number) +static int ai_poptask(lua_State* L); // poptask() +static int ai_taskname(lua_State* L); // Number taskname. // Consult values. -static int ai_gettarget(lua_State* L); // Pointer gettarget() -static int ai_gettargetid(lua_State* L); // Number gettargetis() -static int ai_armor(lua_State* L); // armor() -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_minbrakedist(lua_State* L); // Number minbrakedist() +static int ai_gettarget(lua_State* L); // Pointer gettarget() +static int ai_gettargetid(lua_State* L); // Number gettargetis() +static int ai_armor(lua_State* L); // armor() +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) +static int ai_minbrakedist(lua_State* L); // Number minbrakedist() // Boolean expressions. -static int ai_ismaxvel(lua_State* L); // Boolean ismaxvel() -static int ai_isstopped(lua_State* L); // Boolean isstopped() -static int ai_isenemy(lua_State* L); // bool isenemy(number). -static int ai_isally(lua_State* L); // bool isally(number). +static int ai_ismaxvel(lua_State* L); // Boolean ismaxvel() +static int ai_isstopped(lua_State* L); // Boolean isstopped() +static int ai_isenemy(lua_State* L); // bool isenemy(number). +static int ai_isally(lua_State* L); // bool isally(number). // Movement. -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_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_shoot(lua_State* L); // shoot(number) number = 1,2,3. +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; +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) // Current pilot "thinking" and assorted variables. static Pilot* cur_pilot = NULL; @@ -111,52 +123,93 @@ 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. - lua_register(L, "pushtask", ai_pushtask); - lua_register(L, "poptask", ai_poptask); - lua_register(L, "taskname", ai_taskname); + lua_register(L, "pushtask", ai_pushtask); + lua_register(L, "poptask", ai_poptask); + lua_register(L, "taskname", ai_taskname); // Consult. - lua_register(L, "gettarget", ai_gettarget); - lua_register(L, "gettargetid", ai_gettargetid); - lua_register(L, "armor", ai_armor); - lua_register(L, "shield", ai_shield); - lua_register(L, "parmor", ai_parmor); - lua_register(L, "pshield", ai_pshield); - lua_register(L, "getdist", ai_getdistance); - lua_register(L, "getpos", ai_getpos); - lua_register(L, "minbrakedist", ai_minbrakedist); + lua_register(L, "gettarget", ai_gettarget); + lua_register(L, "gettargetid", ai_gettargetid); + lua_register(L, "armor", ai_armor); + lua_register(L, "shield", ai_shield); + lua_register(L, "parmor", ai_parmor); + lua_register(L, "pshield", ai_pshield); + lua_register(L, "getdist", ai_getdistance); + lua_register(L, "getpos", ai_getpos); + lua_register(L, "minbrakedist", ai_minbrakedist); // Boolean. - lua_register(L, "ismaxvel", ai_ismaxvel); - lua_register(L, "isstopped", ai_isstopped); - lua_register(L, "isenemy", ai_isenemy); - lua_register(L, "isally", ai_isally); + lua_register(L, "ismaxvel", ai_ismaxvel); + lua_register(L, "isstopped", ai_isstopped); + lua_register(L, "isenemy", ai_isenemy); + lua_register(L, "isally", ai_isally); // Movement. - lua_register(L, "accel", ai_accel); - lua_register(L, "turn", ai_turn); - lua_register(L, "face", ai_face); - lua_register(L, "brake", ai_brake); + lua_register(L, "accel", ai_accel); + 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); + lua_register(L, "shoot", ai_shoot); + lua_register(L, "getenemy", ai_getenemy); // Misc. - lua_register(L, "createvect", ai_createvect); - lua_register(L, "say", ai_say); - lua_register(L, "rng", ai_rng); + lua_register(L, "createvect", ai_createvect); + 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; diff --git a/src/ai.h b/src/ai.h index c350946..2796363 100644 --- a/src/ai.h +++ b/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); diff --git a/src/faction.c b/src/faction.c index 28725bb..b775d52 100644 --- a/src/faction.c +++ b/src/faction.c @@ -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; } diff --git a/src/main.c b/src/main.c index 5d66954..d0a5bf2 100644 --- a/src/main.c +++ b/src/main.c @@ -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"); diff --git a/src/pack.c b/src/pack.c index f9be300..5c51e11 100644 --- a/src/pack.c +++ b/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 diff --git a/src/pack.h b/src/pack.h index 8c57f85..72ddb0b 100644 --- a/src/pack.h +++ b/src/pack.h @@ -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); diff --git a/src/physics.c b/src/physics.c index 6b7ba13..b98dfe4 100644 --- a/src/physics.c +++ b/src/physics.c @@ -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); } diff --git a/src/physics.h b/src/physics.h index 9a2b109..0fa1a8b 100644 --- a/src/physics.h +++ b/src/physics.h @@ -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); diff --git a/src/pilot.c b/src/pilot.c index 4a3e1f0..a294d3e 100644 --- a/src/pilot.c +++ b/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,9 +345,10 @@ static Fleet* fleet_parse(const xmlNodePtr parent) { } } #define MELEMENT(o,s) if((o) == NULL) WARN("Fleet '%s' missing '"s"' element", tmp->name) - MELEMENT(tmp->faction, "faction"); - MELEMENT(tmp->pilots, "pilots"); -#undef MELEMENT + MELEMENT(tmp->ai, "ai"); + MELEMENT(tmp->faction, "faction"); + MELEMENT(tmp->pilots, "pilots"); + #undef MELEMENT return tmp; } diff --git a/src/pilot.h b/src/pilot.h index d85260e..be2a1e6 100644 --- a/src/pilot.h +++ b/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; @@ -64,6 +65,8 @@ typedef struct { 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. @@ -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); diff --git a/src/player.h b/src/player.h index 46a517f..d0e812c 100644 --- a/src/player.h +++ b/src/player.h @@ -2,6 +2,8 @@ #include #include "pilot.h" +#define PLAYER_ID 0 + extern Pilot* pilot; typedef enum { KEYBIND_NULL, KEYBIND_KEYBOARD, KEYBIND_JAXIS, KEYBIND_JBUTTON } KeybindType; diff --git a/src/space.c b/src/space.c index ae47341..594d406 100644 --- a/src/space.c +++ b/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, diff --git a/src/space.h b/src/space.h index 6d18bd3..f5c4014 100644 --- a/src/space.h +++ b/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); diff --git a/src/weapon.c b/src/weapon.c index ef0cc78..c22d289 100644 --- a/src/weapon.c +++ b/src/weapon.c @@ -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; }