diff --git a/scripts/ai/API b/scripts/ai/API index 7f0dab2..c698b5b 100644 --- a/scripts/ai/API +++ b/scripts/ai/API @@ -64,7 +64,7 @@ face(number/Vec2 target, number invert) -- Turn to face the current target. -- target pilot ID or Vec2 to face. -- invert face away if 1 - -- return nil + -- return number offset from target in grad // ================ // MISC! diff --git a/scripts/ai/test.lua b/scripts/ai/test.lua index 09a1a41..6efafd7 100644 --- a/scripts/ai/test.lua +++ b/scripts/ai/test.lua @@ -1,6 +1,10 @@ function follow() - face(1,1) - accel(1) + target = 1 + dir = face(target) + dist = getdist(getpos(target)) + if dir < 10 and dist > 100 then + accel() + end end function goto() diff --git a/src/ai.c b/src/ai.c index a813470..3cb4fa6 100644 --- a/src/ai.c +++ b/src/ai.c @@ -62,6 +62,12 @@ static Pilot* cur_pilot = NULL; static double pilot_acc = 0.; static double pilot_turn = 0.; +// Destroy the AI part of the pilot. +void ai_destroy(Pilot* p) { + ai_freetask(p->task); +} + +// Init the AI stuff. Which is basically Lua. int ai_init(void) { L = luaL_newstate(); if(L == NULL) @@ -76,7 +82,7 @@ int ai_init(void) { lua_register(L, "taskname", ai_taskname); lua_register(L, "gettarget", ai_gettarget); lua_register(L, "gettargetid", ai_gettargetid); - lua_register(L, "getdistance", ai_getdistance); + lua_register(L, "getdist", ai_getdistance); lua_register(L, "getpos", ai_getpos); lua_register(L, "minbrakedist", ai_minbrakedist); lua_register(L, "accel", ai_accel); @@ -96,6 +102,7 @@ int ai_init(void) { return 0; } +// Clean up global AI void ai_exit(void) { lua_close(L); } @@ -148,6 +155,7 @@ static int ai_pushtask(lua_State* L) { Task* t = MALLOC_L(Task); t->name = (lua_isstring(L, 2)) ? strdup((char*) lua_tostring(L, 2)) : NULL; t->next = NULL; + t->target = NULL; if(lua_gettop(L) > 2) { if(lua_isnumber(L, 3)) @@ -241,8 +249,7 @@ static int ai_minbrakedist(lua_State* L) { // Accelerate the pilot based on a param. static int ai_accel(lua_State* L) { - MIN_ARGS(1); - pilot_acc = (lua_isnumber(L, 1)) ? ABS((double)lua_tonumber(L, 1)) : 1.; + pilot_acc = (lua_gettop(L) > 1 && lua_isnumber(L, 1)) ? ABS((double)lua_tonumber(L, 1)) : 1.; return 0; } @@ -263,13 +270,17 @@ static int ai_face(lua_State* L) { double mod = 10; if(lua_gettop(L) > 1 && lua_isnumber(L,2)) switch((int)lua_tonumber(L,2)) { + case 0: break; case 1: mod *= -1; break; case 2: break; } + double diff = angle_diff(cur_pilot->solid->dir, vect_angle(&cur_pilot->solid->pos, v)); - pilot_turn = mod * angle_diff(cur_pilot->solid->dir, vect_angle(&cur_pilot->solid->pos, v)); + pilot_turn = mod*diff; - return 0; + lua_pushnumber(L, ABS(diff*180./M_PI)); + + return 1; } // Create a vector. diff --git a/src/main.c b/src/main.c index 6384edd..14c9bba 100644 --- a/src/main.c +++ b/src/main.c @@ -28,6 +28,8 @@ extern const char* keybindNames[]; // Keybindings. static int quit = 0; // Primary loop. static unsigned int time = 0; // Calculate FPS and movement. +static int show_fps = 1; // Default - True. + // Prototypes. static void print_usage(char** argv); @@ -82,6 +84,10 @@ int main(int argc, char** argv) { if((int)lua_tonumber(L, -1) == 1) gl_screen.fullscreen = 1; + lua_getglobal(L, "fps"); + if(lua_isnumber(L, -1)) + show_fps = (int)lua_tonumber(L, -1); + // Joystick. lua_getglobal(L, "joystick"); if(lua_isnumber(L, -1)) @@ -137,19 +143,23 @@ int main(int argc, char** argv) { // Parse arguments. static struct option long_options[] = { { "fullscreen", no_argument, 0, 'f' }, + { "fps", optional_argument, 0, 'F' }, { "joystick", required_argument, 0, 'j' }, { "joystick", required_argument, 0, 'J' }, { "help", no_argument, 0, 'h' }, { "version", no_argument, 0, 'v' }, - { 0, 0, 0, 0 } + { NULL, 0, 0, 0 } }; int option_index = 0; int c = 0; - while((c = getopt_long(argc, argv, "fJ:j:hv", long_options, &option_index)) != -1) { + while((c = getopt_long(argc, argv, "fFJ:j:hv", long_options, &option_index)) != -1) { switch(c) { case 'f': gl_screen.fullscreen = 1; break; + case 'F': + if(optarg != NULL) show_fps = atoi(optarg); + break; case 'j': indjoystick = atoi(optarg); break; @@ -256,7 +266,7 @@ static void update_all(void) { if(dt > MINIMUM_FPS) { Vec2 pos; - vect_cset(&pos, 10., (double)(gl_screen.h-40)); + vect_csetmin(&pos, 10., (double)(gl_screen.h-40)); gl_print(NULL, &pos, "FPS is really low! Skipping frames."); SDL_GL_SwapBuffers(); return; @@ -264,10 +274,15 @@ static void update_all(void) { glClear(GL_COLOR_BUFFER_BIT); + // BG. space_render(dt); planets_render(); + // N pilots_update(dt); + + // FG. + player_renderGUI(); display_fps(dt); @@ -287,7 +302,8 @@ static void display_fps(const double dt) { fps_dt = fps_cur = 0.; } Vec2 pos; - vect_cset(&pos, 10., (double)(gl_screen.h-20)); - gl_print(NULL, &pos, "%3.2f", fps); + vect_csetmin(&pos, 10., (double)(gl_screen.h-20)); + if(show_fps) + gl_print(NULL, &pos, "%3.2f", fps); } diff --git a/src/opengl.c b/src/opengl.c index aa0b43d..132d11a 100644 --- a/src/opengl.c +++ b/src/opengl.c @@ -420,6 +420,8 @@ static void gl_fontMakeDList(FT_Face face, char ch, GLuint list_base, GLuint* te // End of the display list. glEndList(); + + FT_Done_Glyph(glyph); } void gl_fontInit(gl_font* font, const char* fname, unsigned int h) { diff --git a/src/physics.c b/src/physics.c index 12d587e..8e3c103 100644 --- a/src/physics.c +++ b/src/physics.c @@ -25,6 +25,12 @@ void vect_cset(Vec2* v, const double x, const double y) { v->angle = ANGLE(x, y); } +// Create a minimal vector, only valid for blitting. +void vect_csetmin(Vec2* v, const double x, const double y) { + v->x = x; + v->y = y; +} + // Set the vector value using polar coords. void vect_pset(Vec2* v, const double mod, const double angle) { v->mod = mod; diff --git a/src/physics.h b/src/physics.h index 77f6e28..1940ecd 100644 --- a/src/physics.h +++ b/src/physics.h @@ -20,6 +20,8 @@ typedef struct { // Vector manupulation. void vect_cset(Vec2* v, const double x, const double y); +// Doesn't set mod nor angle. +void vect_csetmin(Vec2* v, const double x, const double y); void vect_pset(Vec2* v, const double mod, const double angle); void vectcpy(Vec2* dest, const Vec2* src); void vectnull(Vec2* v); diff --git a/src/pilot.c b/src/pilot.c index 180f76d..e124e44 100644 --- a/src/pilot.c +++ b/src/pilot.c @@ -14,8 +14,11 @@ static unsigned int pilot_id = 0; static Pilot** pilot_stack; static int pilots = 0; +// External. +extern void ai_destroy(Pilot* p); // Ai. extern void player_think(Pilot* pilot, const double dt); // Player.c extern void ai_think(Pilot* pilot); // Ai.c +// Internal. static void pilot_update(Pilot* pilot, const double dt); static void pilot_render(Pilot* pilot); @@ -110,6 +113,24 @@ unsigned int pilot_create(Ship* ship, char* name, const Vec2* vel, const Vec2* p return dyn->id; } +// Frees and cleans up a pilot. +void pilot_destroy(Pilot* p) { + int i; + + solid_free(p->solid); + free(p->name); + ai_destroy(p); + + for(i = 0; i < pilots; i++) + if(pilot_stack[i] == p) + break; + while(i < pilots) { + pilot_stack[i] = pilot_stack[i+1]; + i++; + } + free(p); +} + // Free the prisoned pilot! void pilots_free(void) { int i; diff --git a/src/pilot.h b/src/pilot.h index 65e0d07..26fa190 100644 --- a/src/pilot.h +++ b/src/pilot.h @@ -39,6 +39,7 @@ unsigned int pilot_create(Ship* ship, char* name, const Vec2* vel, const Vec2* pos, const int flags); // Cleanup. +void pilot_destroy(Pilot* p); void pilots_free(void); // Update. diff --git a/src/player.c b/src/player.c index 2736bc6..deaaf60 100644 --- a/src/player.c +++ b/src/player.c @@ -32,6 +32,17 @@ void player_think(Pilot* player, const double dt) { vect_pset(&player->solid->force, player->ship->thrust * player_acc, player->solid->dir); } +// ================ +// GUI! +// ================ +void player_renderGUI(void) { + +} + + +// ================ +// INPUT! +// ================ // Initialization/exit functions (does not assign keys). void input_init(void) { Keybind* tmp; @@ -178,6 +189,7 @@ void input_handle(SDL_Event* event) { break; case SDL_JOYBUTTONUP: input_joyup(event->jbutton.button); + break; case SDL_KEYDOWN: input_keydown(event->key.keysym.sym); break; diff --git a/src/player.h b/src/player.h index 6083a2f..dc248d5 100644 --- a/src/player.h +++ b/src/player.h @@ -3,6 +3,9 @@ typedef enum { KEYBIND_NULL, KEYBIND_KEYBOARD, KEYBIND_JAXIS, KEYBIND_JBUTTON } KeybindType; +// GUI. +void player_renderGUI(void); + int player_isFlag(unsigned int flag); void player_setFlag(unsigned int flag); void player_rmFlag(unsigned int flag); diff --git a/src/space.c b/src/space.c index c7b7006..93d2790 100644 --- a/src/space.c +++ b/src/space.c @@ -26,6 +26,13 @@ #define PLANET_GFX "../gfx/planet/" +// Overcome warning due to zero value. + +#define FLAG_XSET (1<<0) +#define FLAG_YSET (1<<1) +#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_A, // Geothermal. @@ -55,14 +62,14 @@ typedef enum { typedef struct { char* name; - double x, y; // Position in star system. + Vec2 pos; // Position in star system. PlanetClass class; gl_texture* gfx_space; // Graphics in space. } Planet; typedef struct { char* name; - double x, y; // Position. + Vec2 pos; // Position. int stars, asteroids; // Un numero! double interference; // Un uh.. Percentage. @@ -112,6 +119,9 @@ static Planet* planet_get(const char* name) { Planet* tmp = NULL; char str[MAX_PATH_NAME] = "\0"; + char* tstr; + + uint32_t flags = 0; uint32_t bufsize; char* buf = pack_readfile(DATA, PLANET_DATA, &bufsize); @@ -133,9 +143,10 @@ static Planet* planet_get(const char* name) { do { if(node->type == XML_NODE_START && strcmp((char*)node->name, XML_PLANET_TAG)==0) { - if(strcmp((char*)xmlGetProp(node, (xmlChar*)"name"), name)==0) { // Found. + tstr = (char*)xmlGetProp(node, (xmlChar*)"name"); + if(strcmp(tstr, name)==0) { // Found. tmp = CALLOC_L(Planet); - tmp->name = strdup(name); + tmp->name = tstr; node = node->xmlChildrenNode; @@ -151,10 +162,14 @@ static Planet* planet_get(const char* name) { else if(strcmp((char*)node->name, "pos")==0) { cur = node->children; while((cur = cur->next)) { - if(strcmp((char*)cur->name, "x")==0) - tmp->x = atof((char*)cur->children->content); - else if(strcmp((char*)cur->name, "y")==0) - tmp->y = atof((char*)cur->children->content); + if(strcmp((char*)cur->name, "x")==0) { + flags |= FLAG_XSET; + tmp->pos.x = atof((char*)cur->children->content); + } + else if(strcmp((char*)cur->name, "y")==0) { + flags |= FLAG_YSET; + tmp->pos.y = atof((char*)cur->children->content); + } } } else if(strcmp((char*)node->name, "general")==0) { @@ -166,7 +181,8 @@ static Planet* planet_get(const char* name) { } } break; - } + } else + free(tstr); // xmlGetProp mallocs the string. } } while((node = node->next)); @@ -176,9 +192,9 @@ static Planet* planet_get(const char* name) { // Check elements. if(tmp) { -#define MELEMENT(o,s) if(o == 0) WARN("Planet '%s' missing '"s"' element", tmp->name) - MELEMENT(tmp->x, "x"); - MELEMENT(tmp->x, "y"); +#define MELEMENT(o,s) if((o) == 0) WARN("Planet '%s' missing '"s"' element", tmp->name) + MELEMENT(flags&FLAG_XSET, "x"); + MELEMENT(flags&FLAG_YSET, "y"); MELEMENT(tmp->class, "class"); #undef MELEMENT } else @@ -194,8 +210,10 @@ static StarSystem* system_parse(const xmlNodePtr parent) { StarSystem* tmp = CALLOC_L(StarSystem); xmlNodePtr cur, node; - tmp->name = strdup((char*) xmlGetProp(parent, (xmlChar*)"name")); - + uint32_t flags; + + tmp->name = (char*)xmlGetProp(parent, (xmlChar*)"name"); // Already mallocs. + node = parent->xmlChildrenNode; while((node = node->next)) { @@ -203,21 +221,29 @@ static StarSystem* system_parse(const xmlNodePtr parent) { if(strcmp((char*)node->name, "pos")==0) { cur = node->children; while((cur = cur->next)) { - if(strcmp((char*)cur->name, "x")==0) - tmp->x = atof((char*)cur->children->content); - if(strcmp((char*)cur->name, "y")==0) - tmp->y = atof((char*)cur->children->content); + if(strcmp((char*)cur->name, "x")==0) { + flags |= FLAG_XSET; + tmp->pos.x = atof((char*)cur->children->content); + } + if(strcmp((char*)cur->name, "y")==0) { + flags |= FLAG_YSET; + tmp->pos.y = atof((char*)cur->children->content); + } } } else if(strcmp((char*)node->name, "general")==0) { cur = node->children; while((cur = cur->next)) { - if(strcmp((char*)cur->name, "stars")==0) + if(strcmp((char*)cur->name, "stars")==0) // Non-zero. tmp->stars = atoi((char*)cur->children->content); - else if(strcmp((char*)cur->name, "asteroids")==0) + else if(strcmp((char*)cur->name, "asteroids")==0) { + flags |= FLAG_ASTEROIDSSET; tmp->asteroids = atoi((char*)cur->children->content); - else if(strcmp((char*)cur->name, "interference")==0) + } + else if(strcmp((char*)cur->name, "interference")==0) { + flags |= FLAG_INTEFERENCESET; tmp->interference = atof((char*)cur->children->content); + } } } else if(strcmp((char*)node->name, "planets")==0) { @@ -233,12 +259,12 @@ static StarSystem* system_parse(const xmlNodePtr parent) { } } // Check elements. -#define MELEMENT(o,s) if(o == 0) WARN("Star System '%s' missing '"s"' element", tmp->name) - MELEMENT(tmp->x, "x"); - MELEMENT(tmp->x, "y"); +#define MELEMENT(o,s) if((o) == 0) WARN("Star System '%s' missing '"s"' element", tmp->name) + MELEMENT(flags&FLAG_XSET, "x"); + MELEMENT(flags&FLAG_YSET, "y"); MELEMENT(tmp->stars, "stars"); - /*MELEMENT(tmp->asteroids, "asteroids"); // Can be 0. - MELEMENT(tmp->interference, "interference");*/ + MELEMENT(flags&FLAG_ASTEROIDSSET, "asteroids"); // Can be 0. + MELEMENT(flags&FLAG_INTEFERENCESET, "inteference"); #undef MELEMENT DEBUG("Loaded Star System '%s' with %d Planets%s", tmp->name, tmp->nplanets, (tmp->nplanets > 1) ? "s" : ""); @@ -314,11 +340,8 @@ void space_render(double dt) { void planets_render(void) { int i; Vec2 v; - for(i = 0; i < cur_system->nplanets; i++) { - v.x = cur_system->planets[i].x; - v.y = cur_system->planets[i].y; - gl_blitSprite(cur_system->planets[i].gfx_space, &v, 0, 0); - } + for(i = 0; i < cur_system->nplanets; i++) + gl_blitSprite(cur_system->planets[i].gfx_space, &cur_system->planets[i].pos, 0, 0); } // Clean up the system.