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);
}