diff --git a/bin/Makefile b/bin/Makefile index a284a43..5869fef 100644 --- a/bin/Makefile +++ b/bin/Makefile @@ -14,9 +14,9 @@ CSDL = $(shell sdl-config --cflags) CXML = $(shell xml2-config --cflags) CTTF = $(shell freetype-config --cflags) CGL = -CFLAGS = -Wall $(CLUA) $(CSDL) $(CXML) $(CTTF) $(CGL) $(VERSION) +CFLAGS = $(CLUA) $(CSDL) $(CXML) $(CTTF) $(CGL) $(VERSION) ifdef DEBUG -CFLAGS += -g3 -DDEBUG -DLUA_USE_APICHECK +CFLAGS += -W -Wall -g3 -DDEBUG -DLUA_USE_APICHECK else CFLAGS += -O2 endif diff --git a/dat/outfit.xml b/dat/outfit.xml index e597fa0..76b3a2c 100644 --- a/dat/outfit.xml +++ b/dat/outfit.xml @@ -2,21 +2,19 @@ - 0 - 1 - 0 + 5 + 2 + 1 - laser - - laser_green - - - 7 - 7 - 600 - 400 - 18 - 500 - + + laser.wav + lasergreen.png + 450 + 30 + + 20 + 10 + + diff --git a/gfx/outfit/lasergreen.png b/gfx/outfit/lasergreen.png new file mode 100644 index 0000000..83580cd Binary files /dev/null and b/gfx/outfit/lasergreen.png differ diff --git a/scripts/ai/test.lua b/scripts/ai/test.lua index df11988..011b5b1 100644 --- a/scripts/ai/test.lua +++ b/scripts/ai/test.lua @@ -3,14 +3,14 @@ control_rate = 2 -- Required "control" function. function control() - pusttask(0, "follow"); + pushtask(0, "follow"); end function follow() target =1 dir = face(target) - dist = getdist(getpos(targer)) - if dir < 10 and dist > 100 then + dist = getdist(getpos(target)) + if -dir < 10 and dist > 100 then accel(dist/100-1) end end diff --git a/src/ai.c b/src/ai.c index 982a841..935c3f4 100644 --- a/src/ai.c +++ b/src/ai.c @@ -217,6 +217,7 @@ static int ai_pushtask(lua_State* L) { // Pop the current task. static int ai_poptask(lua_State* L) { + (void)L; // Just a hack to avoid -W -Wall warnings. Task* t = cur_pilot->task; cur_pilot->task = t->next; t->next = NULL; @@ -231,7 +232,7 @@ static int ai_taskname(lua_State* L) { return 1; } -// Grab the targer pointer. +// Grab the target pointer. static int ai_gettarget(lua_State* L) { lua_pushlightuserdata(L, cur_pilot->task->target); return 1; @@ -315,7 +316,7 @@ static int ai_face(lua_State* L) { if(lua_isnumber(L,1)) v = &get_pilot((unsigned int)lua_tonumber(L,1))->solid->pos; else if(lua_islightuserdata(L,1)) v = (Vec2*)lua_topointer(L,1); - double mod = 10; + double mod = -10; if(lua_gettop(L) > 1 && lua_isnumber(L,2)) switch((int)lua_tonumber(L,2)) { case 0: break; @@ -333,6 +334,7 @@ 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) diff --git a/src/ai.h b/src/ai.h index 4bcb1c1..ccffc6b 100644 --- a/src/ai.h +++ b/src/ai.h @@ -1,6 +1,6 @@ #pragma once -struct Task { +typedef struct Task { struct Task* next; char* name; @@ -8,8 +8,7 @@ struct Task { void* target; // Vec2 etc. unsigned int ID; // Pilot ID etc. }; -}; -typedef struct Task Task; +} Task; int ai_init(void); void ai_exit(void); diff --git a/src/main.c b/src/main.c index 5f12994..c8df506 100644 --- a/src/main.c +++ b/src/main.c @@ -17,6 +17,7 @@ #include "space.h" #include "rng.h" #include "ai.h" +#include "outfit.h" #include "pilot.h" #define WINDOW_CAPTION "Lephisto" @@ -219,6 +220,7 @@ int main(int argc, char** argv) { gl_fontInit(NULL, NULL, 16); // Data loading. + outfit_load(); ships_load(); space_load(); @@ -249,6 +251,7 @@ int main(int argc, char** argv) { space_exit(); // Clean up the universe!!! pilots_free(); // Free the pilots, they where locked up D: ships_free(); + outfit_free(); gl_freeFont(NULL); diff --git a/src/main.h b/src/main.h index 9f16338..baef2c0 100644 --- a/src/main.h +++ b/src/main.h @@ -8,3 +8,8 @@ extern char* data; // Modifiable datafile. #define DATA data // Data file. +// Max filename path. +#ifndef PATH_MAX +# define PATH_MAX 100 +#endif + diff --git a/src/opengl.c b/src/opengl.c index e80616e..bcb5a92 100644 --- a/src/opengl.c +++ b/src/opengl.c @@ -551,7 +551,7 @@ int gl_init(void) { // Some openGL options. glClearColor(0., 0., 0., 1.); glDisable(GL_DEPTH_TEST); // Set for doing 2D shidazles. - //glEnable(GL_TEXTURE_2D); + //glEnable(GL_TEXTURE_2D); // Don't enable globally, it will break non-texture blits. glDisable(GL_LIGHTING); // No lighting, it is done when rendered. glMatrixMode(GL_PROJECTION); glMatrixMode(GL_PROJECTION); diff --git a/src/outfit.c b/src/outfit.c new file mode 100644 index 0000000..5187d6d --- /dev/null +++ b/src/outfit.c @@ -0,0 +1,190 @@ +#include +#include +#include + +#include "main.h" +#include "log.h" +#include "outfit.h" + +#define XML_NODE_START 1 +#define XML_NODE_TEXT 3 + +#define XML_OUTFIT_ID "Outfits" +#define XML_OUTFIT_TAG "outfit" + +#define OUTFIT_DATA "../dat/outfit.xml" +#define OUTFIT_GFX "../gfx/outfit/" + +static Outfit* outfit_stack = NULL; +static int outfits = 0; + +static Outfit* outfit_parse(const xmlNodePtr parent); +static void outfit_parseSWeapon(Outfit* tmp, const xmlNodePtr parent); + +// Return an outfit. +Outfit* outfit_get(const char* name) { + int i; + for(i = 0; i < outfits; i++) + if(strcmp(name, outfit_stack[i].name)==0) + return &outfit_stack[i]; + return NULL; +} + +// Return 1 if outfit is a weapon. +int outfit_isweapon(const Outfit* o) { + return (o->type > OUTFIT_TYPE_NULL && o->type <= OUTFIT_TYPE_MISSILE_SWARM_SMART); +} + +const char* outfit_typename[] = { + "NULL", + "Bolt Cannon", + "Beam Cannon", + "Dumb Missile", + "Seeker Missile", + "Smart Missile", + "Swam Missile", + "Smart Swarm Missile" +}; + +const char* outfit_getType(const Outfit* o) { + return outfit_typename[o->type]; +} + +// Parses the specific area for a weapon and loads it into outfit. +static void outfit_parseSWeapon(Outfit* tmp, const xmlNodePtr parent) { + xmlNodePtr cur, node; + node = parent->xmlChildrenNode; + + char str[PATH_MAX] = "\0"; + + while((node = node->next)) { + // Load all the things. + if(strcmp((char*)node->name, "speed")==0) + tmp->speed = (double)atoi((char*)node->children->content); + else if(strcmp((char*)node->name, "accuracy")==0) + tmp->accuracy = atof((char*)node->children->content)*M_PI/180.; // to rad. + else if(strcmp((char*)node->name, "gfx")==0) { + snprintf(str, strlen((char*)node->children->content)+sizeof(OUTFIT_GFX), + OUTFIT_GFX"%s", (char*)node->children->content); + tmp->gfx_space = gl_newSprite(str, 6, 6); + } + if(strcmp((char*)node->name, "damage")==0) { + cur = node->children; + while((cur = cur->next)) { + if(strcmp((char*)cur->name, "armor")==0) + tmp->damage_armor = atof((char*)cur->children->content); + else if(strcmp((char*)cur->name, "shield")==0) + tmp->damage_shield = atof((char*)cur->children->content); + } + } + } +#define MELEMENT(o,s) if((o) == 0) WARN("Outfit '%s' missing '"s"' element", tmp->name) + MELEMENT(tmp->speed, "speed"); + MELEMENT(tmp->accuracy, "tech"); + MELEMENT(tmp->damage_armor, "armor' from element 'damage"); + MELEMENT(tmp->damage_shield, "shield' from element 'damage"); +#undef MELEMENT +} + +// Parse and return Outfits from parent node. +static Outfit* outfit_parse(const xmlNodePtr parent) { + Outfit* tmp = CALLOC_L(Outfit); + xmlNodePtr cur, node; + xmlChar* prop; + + tmp->name = (char*)xmlGetProp(parent, (xmlChar*)"name"); // Already mallocs. + + node = parent->xmlChildrenNode; + + while((node = node->next)) { + // Load all the things. + if(strcmp((char*)node->name, "general")==0) { + cur = node->children; + while((cur = cur->next)) { + if(strcmp((char*)cur->name, "max")==0) + tmp->max = atoi((char*)cur->children->content); + else if(strcmp((char*)cur->name, "tech")==0) + tmp->tech = atoi((char*)cur->children->content); + else if(strcmp((char*)cur->name, "mass")== 0) + tmp->mass = atoi((char*)cur->children->content); + } + } + else if(strcmp((char*)node->name, "specific")==0) { + // Has to be processed seperately. + prop = xmlGetProp(node,(xmlChar*)"type"); + if(prop == NULL) + ERR("Outfit '%s' element 'specific' missing property 'type'", tmp->name); + tmp->type = atoi((char*)prop); + free(prop); + switch(tmp->type) { + case OUTFIT_TYPE_NULL: + WARN("Outfit '%s' is of type NONE", tmp->name); + break; + case OUTFIT_TYPE_BOLT: + outfit_parseSWeapon(tmp, node); + break; + default: + break; + } + } + } +#define MELEMENT(o,s) if((o) == 0) WARN("Outfit '%s' missing '"s"' element", tmp->name) + MELEMENT(tmp->max, "max"); + MELEMENT(tmp->tech, "tech"); + MELEMENT(tmp->mass, "mass"); + MELEMENT(tmp->type, "type"); +#undef MELEMENT + + DEBUG("Loaded outfit '%s' of type '%s'", tmp->name, outfit_getType(tmp)); + + return tmp; +} + +// Load all the outfits into the outfit stack. +int outfit_load(void) { + uint32_t bufsize; + char* buf = pack_readfile(DATA, OUTFIT_DATA, &bufsize); + + Outfit* tmp; + + xmlNodePtr node; + xmlDocPtr doc = xmlParseMemory(buf, bufsize); + + node = doc->xmlChildrenNode; + if(strcmp((char*)node->name, XML_OUTFIT_ID)) { + ERR("Malformed "OUTFIT_DATA" file: missing root element '"XML_OUTFIT_ID"'"); + return -1; + } + + node = node->xmlChildrenNode; // First system node. + if(node == NULL) { + ERR("Malformed "OUTFIT_DATA" file: does not contain elements"); + return -1; + } + + do { + if(node->type == XML_NODE_START && strcmp((char*)node->name, XML_OUTFIT_TAG)==0) { + tmp = outfit_parse(node); + outfit_stack = realloc(outfit_stack, sizeof(Outfit)*(++outfits)); + memcpy(outfit_stack+outfits-1, tmp, sizeof(Outfit)); + free(tmp); + } + } while((node = node->next)); + + xmlFreeDoc(doc); + free(buf); + xmlCleanupParser(); + return 0; +} + +// Frees the outfit stack. +void outfit_free(void) { + int i; + for(i = 0; i < outfits; i++) { + if(outfit_isweapon(&outfit_stack[i]) && outfit_stack[i].gfx_space) + gl_freeTexture(outfit_stack[i].gfx_space); + free(outfit_stack[i].name); + } + free(outfit_stack); +} + diff --git a/src/outfit.h b/src/outfit.h new file mode 100644 index 0000000..350d0cb --- /dev/null +++ b/src/outfit.h @@ -0,0 +1,45 @@ +#pragma once +#include "opengl.h" + +// Outfit types. +typedef enum { + OUTFIT_TYPE_NULL, + OUTFIT_TYPE_BOLT, + OUTFIT_TYPE_BEAM, + OUTFIT_TYPE_MISSILE_DUMB, + OUTFIT_TYPE_MISSILE_SEEK, + OUTFIT_TYPE_MISSILE_SEEK_SMART, + OUTFIT_TYPE_MISSILE_SWARM, + OUTFIT_TYPE_MISSILE_SWARM_SMART +} OutfitType; + +// An outfit depends a lot on the type. +typedef struct { + char* name; + + int max; + int tech; + int mass; + + gl_texture gfx_store; + + OutfitType type; + union { + struct { + double speed; + double accuracy; + double damage_armor, damage_shield; + + gl_texture* gfx_space; + }; + }; +} Outfit; + +Outfit* outfit_get(const char* name); +int outfit_isweapon(const Outfit* o); +const char* outfit_getType(const Outfit* o); + +// Load/free outfit stack. +int outfit_load(void); +void outfit_free(void); + diff --git a/src/pack.c b/src/pack.c index 0b66e61..4053fc7 100644 --- a/src/pack.c +++ b/src/pack.c @@ -80,7 +80,8 @@ int pack_check(const char* filename) { int pack_files(const char* outfile, const char** infiles, const uint32_t nfiles) { void* buf; struct stat file; - int i, namesize; + uint32_t i; + int namesize; int outfd, infd; uint32_t indexsize, pointer; int bytes; @@ -163,8 +164,8 @@ int pack_files(const char* outfile, const char** infiles, const uint32_t nfiles) ERR("Too few bytes read. Expected more."); \ free(buf); return -1; } int pack_open(Packfile* file, const char* packfile, const char* filename) { - int i, j; - uint32_t nfiles; + int j; + uint32_t nfiles, i; char* buf = malloc(MAX_FILENAME); file->start = file->end = 0; @@ -201,7 +202,7 @@ int pack_open(Packfile* file, const char* packfile, const char* filename) { if(file->start) { // Go to the beginning of the file. - if(lseek(file->fd, file->start, SEEK_SET) != file->start) { + if((uint32_t)lseek(file->fd, file->start, SEEK_SET) != file->start) { ERR("Failure to seek to file start: %s", strerror(errno)); return -1; } diff --git a/src/pilot.c b/src/pilot.c index e124e44..9c2f110 100644 --- a/src/pilot.c +++ b/src/pilot.c @@ -16,7 +16,7 @@ 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 player_think(Pilot* pilot); // Player.c extern void ai_think(Pilot* pilot); // Ai.c // Internal. static void pilot_update(Pilot* pilot, const double dt); @@ -89,7 +89,7 @@ void pilot_init(Pilot* pilot, Ship* ship, char* name, const Vec2* vel, const Vec pilot->task = NULL; if(flags & PILOT_PLAYER) { - pilot->think = (void*)player_think; // Players don't need to thing! :P + pilot->think = player_think; // Players don't need to thing! :P pilot->properties |= PILOT_PLAYER; player = pilot; } else diff --git a/src/pilot.h b/src/pilot.h index 26fa190..cc89013 100644 --- a/src/pilot.h +++ b/src/pilot.h @@ -7,7 +7,7 @@ #define PILOT_PLAYER 1 // Pilot is a player. // Primary pilot structure. -struct Pilot { +typedef struct Pilot { unsigned int id; // Pilots id. char* name; // Pilot's name (if unique). @@ -25,8 +25,7 @@ struct Pilot { // AI. void (*think)(struct Pilot*); // Ai thinking for the pilot. Task* task; // Current action. -}; -typedef struct Pilot Pilot; +} Pilot; extern Pilot* player; // The player. Pilot* get_pilot(unsigned int id); diff --git a/src/player.c b/src/player.c index 20a8f28..5f797d7 100644 --- a/src/player.c +++ b/src/player.c @@ -11,7 +11,7 @@ typedef struct { char* name; // Keybinding name, taken from keybindNames[] KeybindType type; // type, defined in player.h. - int key; // Key/axis/button event number. + unsigned int key; // Key/axis/button event number. double reverse; // 1. if normal, -1 if reversed, only useful for joystick axis. } Keybind; static Keybind** player_input; // Contains the players keybindings. @@ -24,7 +24,7 @@ static double player_acc = 0.; // Accel velocity from input. // Used in pilot.c // Basically uses keyboard input instead of AI input. -void player_think(Pilot* player, const double dt) { +void player_think(Pilot* player) { player->solid->dir_vel = 0.; if(player_turn) player->solid->dir_vel -= player->ship->turn * player_turn; @@ -109,16 +109,16 @@ static void input_key(int keynum, double value, int abs) { // --Events-- -static void input_joyaxis(int axis, int value); -static void input_joydown(int button); -static void input_joyup(int button); +static void input_joyaxis(const unsigned int axis, const int value); +static void input_joydown(const unsigned int button); +static void input_joyup(const unsigned int button); static void input_keydown(SDLKey key); static void input_keyup(SDLKey key); // Joystick. // Axis. -static void input_joyaxis(int axis, int value) { +static void input_joyaxis(const unsigned int axis, const int value) { int i; for(i = 0; keybindNames[i]; i++) if(player_input[i]->type == KEYBIND_JAXIS && player_input[i]->key == axis) { @@ -128,7 +128,7 @@ static void input_joyaxis(int axis, int value) { } // Joystick button down. -static void input_joydown(int button) { +static void input_joydown(const unsigned int button) { int i; for(i = 0; keybindNames[i]; i++) if(player_input[i]->type == KEYBIND_JBUTTON && player_input[i]->key == button) { @@ -138,7 +138,7 @@ static void input_joydown(int button) { } // Joystick button up. -static void input_joyup(int button) { +static void input_joyup(const unsigned int button) { int i; for(i = 0; keybindNames[i]; i++) if(player_input[i]->type == KEYBIND_JBUTTON && player_input[i]->key == button) { diff --git a/src/space.c b/src/space.c index 93d2790..5c79e0f 100644 --- a/src/space.c +++ b/src/space.c @@ -10,8 +10,6 @@ #include "pack.h" #include "space.h" -#define MAX_PATH_NAME 30 // Max size of the path. - #define XML_NODE_START 1 #define XML_NODE_TEST 3 @@ -22,7 +20,7 @@ #define XML_SYSTEM_TAG "ssys" #define PLANET_DATA "../dat/planet.xml" -#define SPACE_DATA "../dat/ssys.xml" +#define SYSTEM_DATA "../dat/ssys.xml" #define PLANET_GFX "../gfx/planet/" @@ -103,7 +101,7 @@ void space_init(const char* sysname) { if(strcmp(sysname, systems[i].name)==0) break; if(i == nsystems) ERR("System %s not found in stack", sysname); - cur_system = systems++; + cur_system = systems+i; nstars = (cur_system->stars*gl_screen.w*gl_screen.h+STAR_BUF*STAR_BUF)/(800*640); stars = malloc(sizeof(Star)*nstars); @@ -118,7 +116,7 @@ void space_init(const char* sysname) { static Planet* planet_get(const char* name) { Planet* tmp = NULL; - char str[MAX_PATH_NAME] = "\0"; + char str[PATH_MAX] = "\0"; char* tstr; uint32_t flags = 0; @@ -274,7 +272,7 @@ static StarSystem* system_parse(const xmlNodePtr parent) { // Load the ENTIRE universe into RAM. -- WOAH! -- Wasn't that bad. :P int space_load(void) { uint32_t bufsize; - char* buf = pack_readfile(DATA, SPACE_DATA, &bufsize); + char* buf = pack_readfile(DATA, SYSTEM_DATA, &bufsize); StarSystem* tmp; @@ -283,25 +281,20 @@ int space_load(void) { node = doc->xmlChildrenNode; if(strcmp((char*)node->name, XML_SYSTEM_ID)) { - ERR("Malformed "SPACE_DATA" file: missing root element '"XML_SYSTEM_ID"'"); + ERR("Malformed "SYSTEM_DATA" file: missing root element '"XML_SYSTEM_ID"'"); return -1; } node = node->xmlChildrenNode; // First system node. if(node == NULL) { - ERR("Malformed "SPACE_DATA" file: does not contain elements"); + ERR("Malformed "SYSTEM_DATA" file: does not contain elements"); return -1; } do { if(node->type == XML_NODE_START && strcmp((char*)node->name, XML_SYSTEM_TAG)==0) { - if(systems == NULL) { - systems = tmp = system_parse(node); - nsystems = 1; - } else { - tmp = system_parse(node); - systems = realloc(systems, sizeof(StarSystem)*(++nsystems)); - memcpy(systems+nsystems-1, tmp, sizeof(StarSystem)); - free(tmp); - } + tmp = system_parse(node); + systems = realloc(systems, sizeof(StarSystem)*(++nsystems)); + memcpy(systems+nsystems-1, tmp, sizeof(StarSystem)); + free(tmp); } } while((node = node->next)); @@ -339,7 +332,6 @@ void space_render(double dt) { // Render the planets. void planets_render(void) { int i; - Vec2 v; for(i = 0; i < cur_system->nplanets; i++) gl_blitSprite(cur_system->planets[i].gfx_space, &cur_system->planets[i].pos, 0, 0); }