[Add] Rudimentary shooting. This needs some work.

[Add] Layers should be working properly.
This commit is contained in:
Allanis 2013-02-05 16:50:56 +00:00
parent b13ecc66bb
commit 998a1bf68b
17 changed files with 496 additions and 103 deletions

1
.gitignore vendored
View File

@ -26,5 +26,6 @@
*bin/Lephisto *bin/Lephisto
*bin/data *bin/data
*pack *pack
*core

View File

@ -48,5 +48,5 @@ data: pack $(DATAFILES) ../src/pack.c
clean: clean:
@echo -e "\tRemoving data.." @echo -e "\tRemoving data.."
rm -rf $(OBJS) $(APPNAME) $(DATA) pack rm -rf $(OBJS) $(APPNAME) $(DATA) pack core

View File

@ -9,7 +9,9 @@
<specific type = "1"> <specific type = "1">
<sound>laser.wav</sound> <sound>laser.wav</sound>
<gfx>lasergreen.png</gfx> <gfx>lasergreen.png</gfx>
<speed>450</speed> <delay>500</delay>
<speed>550</speed>
<range>300</range>
<accuracy>30</accuracy> <accuracy>30</accuracy>
<damage> <damage>
<armor>20</armor> <armor>20</armor>

View File

@ -89,6 +89,7 @@ static double pilot_turn = 0.;
// Destroy the AI part of the pilot. // Destroy the AI part of the pilot.
void ai_destroy(Pilot* p) { void ai_destroy(Pilot* p) {
if(p->task)
ai_freetask(p->task); ai_freetask(p->task);
} }

View File

@ -18,9 +18,11 @@
#include "rng.h" #include "rng.h"
#include "ai.h" #include "ai.h"
#include "outfit.h" #include "outfit.h"
#include "pack.h"
#include "weapon.h"
#include "pilot.h" #include "pilot.h"
#define WINDOW_CAPTION "Lephisto" #define APPNAME "Lephisto"
#define CONF_FILE "conf" #define CONF_FILE "conf"
#define MINIMUM_FPS 0.5 #define MINIMUM_FPS 0.5
@ -31,14 +33,13 @@ static unsigned int time = 0; // Calculate FPS and movement.
#define DATA_DEF "data" #define DATA_DEF "data"
char* data = NULL; char* data = NULL;
static int show_fps = 1; // Default - True. static int show_fps = 1; // Default - True.
static int max_fps = 0;
// Prototypes. // Prototypes.
static void print_usage(char** argv); static void print_usage(char** argv);
static void display_fps(const double dt); static void display_fps(const double dt);
// Update. // Update.
static void update_all(void); static void update_all(void);
@ -47,7 +48,7 @@ static void print_usage(char** argv) {
LOG("USAGE: %s [OPTION]", argv[0]); LOG("USAGE: %s [OPTION]", argv[0]);
LOG("Options are:"); LOG("Options are:");
LOG("\t-f, --fullscreen - Fullscreen"); LOG("\t-f, --fullscreen - Fullscreen");
LOG("\t-F, --fps - Toggle frames per second"); LOG("\t-F, --fps - Limit frames per second");
LOG("\t-d s, --data s - Set the data file to be s"); LOG("\t-d s, --data s - Set the data file to be s");
LOG("\t-j n, --joystick n - Use joystick (n)"); LOG("\t-j n, --joystick n - Use joystick (n)");
LOG("\t-J s, --joystick s - Use joystick whose name contains (s)"); LOG("\t-J s, --joystick s - Use joystick whose name contains (s)");
@ -57,6 +58,10 @@ static void print_usage(char** argv) {
int main(int argc, char** argv) { int main(int argc, char** argv) {
int i; int i;
// Print the version.
LOG(""APPNAME" v%d.%d.%d", VMAJOR, VMINOR, VREV);
// Initialize SDL for possible warnings. // Initialize SDL for possible warnings.
SDL_Init(0); SDL_Init(0);
// Default values.. // Default values..
@ -74,6 +79,7 @@ int main(int argc, char** argv) {
input_setKeybind("accel", KEYBIND_KEYBOARD, SDLK_w, 0); input_setKeybind("accel", KEYBIND_KEYBOARD, SDLK_w, 0);
input_setKeybind("left", KEYBIND_KEYBOARD, SDLK_a, 0); input_setKeybind("left", KEYBIND_KEYBOARD, SDLK_a, 0);
input_setKeybind("right", KEYBIND_KEYBOARD, SDLK_d, 0); input_setKeybind("right", KEYBIND_KEYBOARD, SDLK_d, 0);
input_setKeybind("primary", KEYBIND_KEYBOARD, SDLK_SPACE, 0);
// Use Lua to parse configuration file. // Use Lua to parse configuration file.
lua_State* L = luaL_newstate(); lua_State* L = luaL_newstate();
@ -96,7 +102,7 @@ int main(int argc, char** argv) {
lua_getglobal(L, "fps"); lua_getglobal(L, "fps");
if(lua_isnumber(L, -1)) if(lua_isnumber(L, -1))
show_fps = (int)lua_tonumber(L, -1); max_fps = (int)lua_tonumber(L, -1);
// Joystick. // Joystick.
lua_getglobal(L, "joystick"); lua_getglobal(L, "joystick");
@ -153,7 +159,7 @@ int main(int argc, char** argv) {
// Parse arguments. // Parse arguments.
static struct option long_options[] = { static struct option long_options[] = {
{ "fullscreen", no_argument, 0, 'f' }, { "fullscreen", no_argument, 0, 'f' },
{ "fps", optional_argument, 0, 'F' }, { "fps", required_argument, 0, 'F' },
{ "data", required_argument, 0, 'd' }, { "data", required_argument, 0, 'd' },
{ "joystick", required_argument, 0, 'j' }, { "joystick", required_argument, 0, 'j' },
{ "joystick", required_argument, 0, 'J' }, { "joystick", required_argument, 0, 'J' },
@ -163,14 +169,14 @@ int main(int argc, char** argv) {
}; };
int option_index = 0; int option_index = 0;
int c = 0; int c = 0;
while((c = getopt_long(argc, argv, "fFd:J:j:hv", long_options, &option_index)) != -1) { while((c = getopt_long(argc, argv, "fF:d:J:j:hv", long_options, &option_index)) != -1) {
switch(c) { switch(c) {
case 'f': case 'f':
gl_screen.fullscreen = 1; gl_screen.fullscreen = 1;
break; break;
case 'F': case 'F':
if(optarg != NULL) show_fps = atoi(optarg); if(optarg != NULL) show_fps = atoi(optarg);
else show_fps = !show_fps; else max_fps = !show_fps;
break; break;
case 'd': case 'd':
data = strdup(optarg); data = strdup(optarg);
@ -195,11 +201,21 @@ int main(int argc, char** argv) {
if(gl_init()) { if(gl_init()) {
// Initializes video output. // Initializes video output.
WARN("Error initializing video output, exiting..."); WARN("Error initializing video output, exiting...");
SDL_Quit();
exit(EXIT_FAILURE);
}
// See if the data file is valid.
if(pack_check(data)) {
ERR("Data file '%s' not found", data);
WARN("You can specify what data file you want to use with '-d'");
WARN("See -h or -- help for more infoamtion.");
SDL_Quit();
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
// Window. // Window.
SDL_WM_SetCaption(WINDOW_CAPTION, NULL); SDL_WM_SetCaption(APPNAME, NULL);
// Input. // Input.
if(indjoystick >= 0 || namjoystick != NULL) { if(indjoystick >= 0 || namjoystick != NULL) {
@ -225,11 +241,11 @@ int main(int argc, char** argv) {
space_load(); space_load();
// Testing. // Testing.
pilot_create(get_ship("Ship"), "Player", NULL, NULL, PILOT_PLAYER); pilot_create(get_ship("Ship"), "Player", 0., NULL, NULL, PILOT_PLAYER);
gl_bindCamera(&player->solid->pos); gl_bindCamera(&player->solid->pos);
space_init("SaraSys"); space_init("SaraSys");
pilot_create(get_ship("Test"), NULL, NULL, NULL, 0); pilot_create(get_ship("Test"), NULL, 2., NULL, NULL, 0);
time = SDL_GetTicks(); time = SDL_GetTicks();
@ -268,19 +284,23 @@ int main(int argc, char** argv) {
// //
// BG | Stars and planets. // BG | Stars and planets.
// | Background particles. // | Background particles.
// | Back layer weapons.
// X // X
// N | NPC ships. // N | NPC ships.
// | Normal layer particles (above ships). // | Normal layer particles (above ships).
// | Front layer weapons.
// X // X
// FG | Player. // FG | Player.
// | Foreground particles. // | Foreground particles.
// | Text and GUI. // | Text and GUI.
// ======================================================== // ========================================================
static double fps_dt = 1.;
static void update_all(void) { static void update_all(void) {
// dt in us. // dt in us.
double dt = (double)(SDL_GetTicks() - time) / 1000.; double dt = (double)(SDL_GetTicks() - time) / 1000.;
time = SDL_GetTicks(); time = SDL_GetTicks();
// TODO: This could use some work.
if(dt > MINIMUM_FPS) { if(dt > MINIMUM_FPS) {
Vec2 pos; Vec2 pos;
vect_csetmin(&pos, 10., (double)(gl_screen.h-40)); vect_csetmin(&pos, 10., (double)(gl_screen.h-40));
@ -288,20 +308,27 @@ static void update_all(void) {
SDL_GL_SwapBuffers(); SDL_GL_SwapBuffers();
return; return;
} }
// If FPS is limited.
else if(max_fps != 0 && dt < 1./max_fps) {
double delay = 1./max_fps - dt;
SDL_Delay(delay);
fps_dt += delay; // Make sure it displays the propper FPS.
}
glClear(GL_COLOR_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT);
// --
// BG. // BG.
space_render(dt); space_render(dt);
planets_render(); planets_render();
weapons_update(dt, WEAPON_LAYER_BG);
// N // N.
pilots_update(dt); pilots_update(dt);
weapons_update(dt, WEAPON_LAYER_FG);
// FG. // FG.
player_renderGUI(); player_render();
display_fps(dt); display_fps(dt);
// --
SDL_GL_SwapBuffers(); SDL_GL_SwapBuffers();
} }
@ -310,7 +337,6 @@ static void update_all(void) {
// Spit this out on display. // Spit this out on display.
static double fps = 0.; static double fps = 0.;
static double fps_cur = 0.; static double fps_cur = 0.;
static double fps_dt = 1.;
static void display_fps(const double dt) { static void display_fps(const double dt) {
fps_dt += dt; fps_dt += dt;
fps_cur += 1.; fps_cur += 1.;

View File

@ -4,6 +4,7 @@
#include "main.h" #include "main.h"
#include "log.h" #include "log.h"
#include "pack.h"
#include "outfit.h" #include "outfit.h"
#define XML_NODE_START 1 #define XML_NODE_START 1
@ -31,8 +32,27 @@ Outfit* outfit_get(const char* name) {
} }
// Return 1 if outfit is a weapon. // Return 1 if outfit is a weapon.
int outfit_isweapon(const Outfit* o) { int outfit_isWeapon(const Outfit* o) {
return (o->type > OUTFIT_TYPE_NULL && o->type <= OUTFIT_TYPE_MISSILE_SWARM_SMART); return ((o->type == OUTFIT_TYPE_BOLT) || (o->type == OUTFIT_TYPE_BEAM));
}
// Return 1 if outfit is a launcher.
int outfit_isLauncher(const Outfit* o) {
return((o->type == OUTFIT_TYPE_MISSILE_DUMB) ||
(o->type == OUTFIT_TYPE_MISSILE_SEEK) ||
(o->type == OUTFIT_TYPE_MISSILE_SEEK_SMART) ||
(o->type == OUTFIT_TYPE_MISSILE_SWARM) ||
(o->type == OUTFIT_TYPE_MISSILE_SWARM_SMART));
}
// Return 1 if outfit is weapon ammunition.
int outfit_isAmmo(const Outfit* o) {
return((o->type == OUTFIT_TYPE_MISSILE_DUMB_AMMO) ||
(o->type == OUTFIT_TYPE_MISSILE_SEEK_AMMO) ||
(o->type == OUTFIT_TYPE_MISSILE_SEEK_SMART_AMMO) ||
(o->type == OUTFIT_TYPE_MISSILE_SWARM_AMMO) ||
(o->type == OUTFIT_TYPE_MISSILE_SWARM_SMART_AMMO));
} }
const char* outfit_typename[] = { const char* outfit_typename[] = {
@ -40,10 +60,15 @@ const char* outfit_typename[] = {
"Bolt Cannon", "Bolt Cannon",
"Beam Cannon", "Beam Cannon",
"Dumb Missile", "Dumb Missile",
"Dumb Missile Ammunition",
"Seeker Missile", "Seeker Missile",
"Smart Missile", "Seeker Missile Ammunition",
"Smart Seeker Missile",
"Smart Seeker Missile Ammunition",
"Swam Missile", "Swam Missile",
"Smart Swarm Missile" "Swarm Missile Ammunition Pack",
"Smart Swarm Missile",
"Smart Swarm Missile Ammunition Pack"
}; };
const char* outfit_getType(const Outfit* o) { const char* outfit_getType(const Outfit* o) {
@ -61,6 +86,8 @@ static void outfit_parseSWeapon(Outfit* tmp, const xmlNodePtr parent) {
// Load all the things. // Load all the things.
if(strcmp((char*)node->name, "speed")==0) if(strcmp((char*)node->name, "speed")==0)
tmp->speed = (double)atoi((char*)node->children->content); tmp->speed = (double)atoi((char*)node->children->content);
else if(strcmp((char*)node->name, "delay")==0)
tmp->delay = atoi((char*)node->children->content);
else if(strcmp((char*)node->name, "accuracy")==0) else if(strcmp((char*)node->name, "accuracy")==0)
tmp->accuracy = atof((char*)node->children->content)*M_PI/180.; // to rad. tmp->accuracy = atof((char*)node->children->content)*M_PI/180.; // to rad.
else if(strcmp((char*)node->name, "gfx")==0) { else if(strcmp((char*)node->name, "gfx")==0) {
@ -81,6 +108,7 @@ static void outfit_parseSWeapon(Outfit* tmp, const xmlNodePtr parent) {
#define MELEMENT(o,s) if((o) == 0) WARN("Outfit '%s' missing '"s"' element", tmp->name) #define MELEMENT(o,s) if((o) == 0) WARN("Outfit '%s' missing '"s"' element", tmp->name)
MELEMENT(tmp->speed, "speed"); MELEMENT(tmp->speed, "speed");
MELEMENT(tmp->accuracy, "tech"); MELEMENT(tmp->accuracy, "tech");
MELEMENT(tmp->delay, "delay");
MELEMENT(tmp->damage_armor, "armor' from element 'damage"); MELEMENT(tmp->damage_armor, "armor' from element 'damage");
MELEMENT(tmp->damage_shield, "shield' from element 'damage"); MELEMENT(tmp->damage_shield, "shield' from element 'damage");
#undef MELEMENT #undef MELEMENT
@ -181,7 +209,7 @@ int outfit_load(void) {
void outfit_free(void) { void outfit_free(void) {
int i; int i;
for(i = 0; i < outfits; i++) { for(i = 0; i < outfits; i++) {
if(outfit_isweapon(&outfit_stack[i]) && outfit_stack[i].gfx_space) if(outfit_isWeapon(&outfit_stack[i]) && outfit_stack[i].gfx_space)
gl_freeTexture(outfit_stack[i].gfx_space); gl_freeTexture(outfit_stack[i].gfx_space);
free(outfit_stack[i].name); free(outfit_stack[i].name);
} }

View File

@ -1,42 +1,70 @@
#pragma once #pragma once
#include "opengl.h" #include "opengl.h"
#define OUTFIT_PROP_WEAP_PRIMARY (1<<0)
#define OUTFIT_PROP_WEAP_SECONDARY (1<<1)
// Outfit types. // Outfit types.
typedef enum { typedef enum {
OUTFIT_TYPE_NULL, OUTFIT_TYPE_NULL = 0,
OUTFIT_TYPE_BOLT, OUTFIT_TYPE_BOLT,
OUTFIT_TYPE_BEAM, OUTFIT_TYPE_BEAM,
OUTFIT_TYPE_MISSILE_DUMB, OUTFIT_TYPE_MISSILE_DUMB,
OUTFIT_TYPE_MISSILE_DUMB_AMMO,
OUTFIT_TYPE_MISSILE_SEEK, OUTFIT_TYPE_MISSILE_SEEK,
OUTFIT_TYPE_MISSILE_SEEK_AMMO,
OUTFIT_TYPE_MISSILE_SEEK_SMART, OUTFIT_TYPE_MISSILE_SEEK_SMART,
OUTFIT_TYPE_MISSILE_SEEK_SMART_AMMO,
OUTFIT_TYPE_MISSILE_SWARM, OUTFIT_TYPE_MISSILE_SWARM,
OUTFIT_TYPE_MISSILE_SWARM_SMART OUTFIT_TYPE_MISSILE_SWARM_AMMO,
OUTFIT_TYPE_MISSILE_SWARM_SMART,
OUTFIT_TYPE_MISSILE_SWARM_SMART_AMMO
} OutfitType; } OutfitType;
// An outfit depends a lot on the type. // An outfit depends a lot on the type.
typedef struct { typedef struct {
char* name; char* name;
// General specs.
int max; int max;
int tech; int tech;
int mass; int mass;
gl_texture gfx_store; gl_texture gfx_store; // Store graphic.
int properties; // Properties stored bitwise.
// Type dependant.
OutfitType type; OutfitType type;
union { union {
struct { struct { // Beam/Bolt.
double speed; unsigned int delay; // Delay between shots.
double accuracy; double speed; // Speed of shot. (not applicable to beam.
double damage_armor, damage_shield; double range;
double accuracy; // Desviation accuracy.
double damage_armor, damage_shield; // Damage.
gl_texture* gfx_space; gl_texture* gfx_space;
}; };
struct { // Launcher.
//unsigned int delay; // Delay between shots.
};
struct { // Ammo.
//double speed; // Max speed.
//double turn; // Turn vel.
//double thrust; // Acceleration.
//double damage_armor, damage_shield;
//gl_texture* gfx_space;
};
}; };
} Outfit; } Outfit;
Outfit* outfit_get(const char* name); Outfit* outfit_get(const char* name);
int outfit_isweapon(const Outfit* o); // Outfit types.
int outfit_isWeapon(const Outfit* o);
int outfit_isLauncher(const Outfit* o);
int outfit_isAmmo(const Outfit* o);
const char* outfit_getType(const Outfit* o); const char* outfit_getType(const Outfit* o);
// Load/free outfit stack. // Load/free outfit stack.

View File

@ -175,11 +175,11 @@ static void rk4_update(Solid* obj, const double dt) {
} }
// Initialize a new solid. // Initialize a new solid.
void solid_init(Solid* dest, const double mass, const Vec2* vel, const Vec2* pos) { void solid_init(Solid* dest, const double mass, const double dir, const Vec2* pos, const Vec2* vel) {
dest->mass = mass; dest->mass = mass;
vect_cset(&dest->force, 0., 0.); vect_cset(&dest->force, 0., 0.);
dest->dir = 0.; dest->dir = dir;
if(vel == NULL) vectnull(&dest->vel); if(vel == NULL) vectnull(&dest->vel);
else vectcpy(&dest->vel, vel); else vectcpy(&dest->vel, vel);
@ -191,10 +191,10 @@ void solid_init(Solid* dest, const double mass, const Vec2* vel, const Vec2* pos
} }
// Create a new solid. // Create a new solid.
Solid* solid_create(const double mass, const Vec2* vel, const Vec2* pos) { Solid* solid_create(const double mass, const double dir, const Vec2* pos, const Vec2* vel) {
Solid* dyn = MALLOC_L(Solid); Solid* dyn = MALLOC_L(Solid);
assert(dyn != NULL); assert(dyn != NULL);
solid_init(dyn, mass, vel, pos); solid_init(dyn, mass, dir, pos, vel);
return dyn; return dyn;
} }

View File

@ -37,7 +37,9 @@ struct Solid {
typedef struct Solid Solid; typedef struct Solid Solid;
// Solid manipulation. // Solid manipulation.
void solid_init(Solid* dest, const double mass, const Vec2* vel, const Vec2* pos); void solid_init(Solid* dest, const double mass, const double dir,
Solid* solid_create(const double mass, const Vec2* vel, const Vec2* pos); const Vec2* pos, const Vec2* vel);
Solid* solid_create(const double mass, const double dir,
const Vec2* pos, const Vec2* vel);
void solid_free(Solid* src); void solid_free(Solid* src);

View File

@ -5,6 +5,7 @@
#include "main.h" #include "main.h"
#include "log.h" #include "log.h"
#include "weapon.h"
#include "pilot.h" #include "pilot.h"
// Stack of pilot id's to assure uniqueness. // Stack of pilot id's to assure uniqueness.
@ -13,6 +14,7 @@ static unsigned int pilot_id = 0;
// Stack of pilots - yes, they come in stacks now. // Stack of pilots - yes, they come in stacks now.
static Pilot** pilot_stack; static Pilot** pilot_stack;
static int pilots = 0; static int pilots = 0;
extern Pilot* player;
// External. // External.
extern void ai_destroy(Pilot* p); // Ai. extern void ai_destroy(Pilot* p); // Ai.
@ -20,7 +22,8 @@ extern void player_think(Pilot* pilot); // Player.c
extern void ai_think(Pilot* pilot); // Ai.c extern void ai_think(Pilot* pilot); // Ai.c
// Internal. // Internal.
static void pilot_update(Pilot* pilot, const double dt); static void pilot_update(Pilot* pilot, const double dt);
static void pilot_render(Pilot* pilot); void pilot_render(Pilot* pilot);
static void pilot_free(Pilot* p);
// Pull a pilot out of the pilot_stack based on id. // Pull a pilot out of the pilot_stack based on id.
Pilot* get_pilot(unsigned int id) { Pilot* get_pilot(unsigned int id) {
@ -31,6 +34,7 @@ Pilot* get_pilot(unsigned int id) {
return pilot_stack[i]; return pilot_stack[i];
return NULL; return NULL;
#endif #endif
if(id == 0) return player;
// Dichotomical search. // Dichotomical search.
int i, n; int i, n;
for(i = 0, n = pilots/2; n > 0; n /= 2) for(i = 0, n = pilots/2; n > 0; n /= 2)
@ -38,15 +42,40 @@ Pilot* get_pilot(unsigned int id) {
return (pilot_stack[i]->id == id) ? pilot_stack[i] : NULL; return (pilot_stack[i]->id == id) ? pilot_stack[i] : NULL;
} }
// Mkay, this is how we shoot. Listen up.
void pilot_shoot(Pilot* p, int secondary) {
int i;
if(!secondary) {
// Primary weapons.
if(!p->outfits) return; // No outfits.
for(i = 0; p->outfits[i].outfit; i++) // Cycle through outfits to find weapons.
if(outfit_isWeapon(p->outfits[i].outfit) || // Is a weapon or launch?
outfit_isLauncher(p->outfits[i].outfit))
// Ready to shoot again.
if((SDL_GetTicks()-p->outfits[i].timer) > p->outfits[i].outfit->delay)
// Different weapons have different behaviours.
switch(p->outfits[i].outfit->type) {
case OUTFIT_TYPE_BOLT:
weapon_add(p->outfits[i].outfit, p->solid->dir, &p->solid->pos,
&p->solid->vel, (p==player) ? WEAPON_LAYER_FG : WEAPON_LAYER_BG);
p->outfits[i].timer = SDL_GetTicks();
break;
default:
break;
}
}
}
// Render the pilot. // Render the pilot.
static void pilot_render(Pilot* pilot) { void pilot_render(Pilot* p) {
int sprite; int sprite;
gl_texture* texture = pilot->ship->gfx_ship; gl_texture* t = p->ship->gfx_ship;
// Get the sprite corresponding to the direction facing. // Get the sprite corresponding to the direction facing.
sprite = (int)(pilot->solid->dir / (2.0*M_PI / (texture->sy * texture->sx))); sprite = (int)(p->solid->dir / (2.0*M_PI / (t->sy * t->sx)));
gl_blitSprite(texture, &pilot->solid->pos, sprite % (int)texture->sx, sprite / (int)texture->sy); gl_blitSprite(t, &p->solid->pos, sprite % (int)t->sx, sprite / (int)t->sy);
} }
// Update the pilot. // Update the pilot.
@ -68,17 +97,23 @@ static void pilot_update(Pilot* pilot, const double dt) {
// ==Init pilot.=========================================== // ==Init pilot.===========================================
// ship : Ship pilot is flying. // ship : Ship pilot is flying.
// name : Pilot's name, if NULL, ships name will be used. // name : Pilot's name, if NULL, ships name will be used.
// dir : Initial facing direction. (radians)
// vel : Initial velocity. // vel : Initial velocity.
// pos : Initial position. // pos : Initial position.
// flags : Tweaking the pilot. // flags : Tweaking the pilot.
// ======================================================== // ========================================================
void pilot_init(Pilot* pilot, Ship* ship, char* name, const Vec2* vel, const Vec2* pos, const int flags) { void pilot_init(Pilot* pilot, Ship* ship, char* name, const double dir, const Vec2* pos,
const Vec2* vel, const int flags) {
if(flags & PILOT_PLAYER) // Player is ID 0
pilot->id = 0;
else
pilot->id = ++pilot_id; // New unique pilot id based on pilot_id, Can't be 0. pilot->id = ++pilot_id; // New unique pilot id based on pilot_id, Can't be 0.
pilot->ship = ship; pilot->ship = ship;
pilot->name = strdup((name == NULL) ? ship->name : name); pilot->name = strdup((name == NULL) ? ship->name : name);
pilot->solid = solid_create(ship->mass, vel, pos); pilot->solid = solid_create(ship->mass, dir, pos, vel);
// Max shields armor. // Max shields armor.
pilot->armor = ship->armor; pilot->armor = ship->armor;
@ -88,39 +123,73 @@ void pilot_init(Pilot* pilot, Ship* ship, char* name, const Vec2* vel, const Vec
// Initially idle. // Initially idle.
pilot->task = NULL; pilot->task = NULL;
// Outfits.
pilot->outfits = NULL;
ShipOutfit* so;
if(ship->outfit) {
int noutfits = 0;
for(so = ship->outfit; so; so = so->next) {
pilot->outfits = realloc(pilot->outfits, (noutfits+1)*sizeof(PilotOutfit));
pilot->outfits[noutfits].outfit = so->data;
pilot->outfits[noutfits].quantity = so->quantity;
pilot->outfits[noutfits].timer = 0;
noutfits++;
}
// Sentinal.
pilot->outfits = realloc(pilot->outfits, (noutfits+1)*sizeof(PilotOutfit));
pilot->outfits[noutfits].outfit = NULL;
pilot->outfits[noutfits].quantity = 0;
pilot->outfits[noutfits].timer = 0;
}
if(flags & PILOT_PLAYER) { if(flags & PILOT_PLAYER) {
pilot->think = player_think; // Players don't need to thing! :P pilot->think = player_think; // Players don't need to thing! :P
pilot->render = NULL;
pilot->properties |= PILOT_PLAYER; pilot->properties |= PILOT_PLAYER;
player = pilot; player = pilot;
} else } else {
pilot->think = ai_think; pilot->think = ai_think;
pilot->update = pilot_update; pilot->update = pilot_update;
}
} }
// Create a new pilot - Params are same as pilot_init. Return pilot's id. // Create a new pilot - Params are same as pilot_init. Return pilot's id.
unsigned int pilot_create(Ship* ship, char* name, const Vec2* vel, const Vec2* pos, const int flags) { unsigned int pilot_create(Ship* ship, char* name, const double dir,
const Vec2* pos, const Vec2* vel, const int flags) {
Pilot* dyn = MALLOC_L(Pilot); Pilot* dyn = MALLOC_L(Pilot);
if(dyn == NULL) { if(dyn == NULL) {
WARN("Unable to allocate memory."); WARN("Unable to allocate memory.");
return 0; return 0;
} }
pilot_init(dyn, ship, name, vel, pos, flags); pilot_init(dyn, ship, name, dir, pos, vel, flags);
if(flags & PILOT_PLAYER) {
// Player.
if(!pilot_stack) {
pilot_stack = MALLOC_L(Pilot*);
pilots = 1;
}
pilot_stack[0] = dyn;
} else {
// Add to the stack. // Add to the stack.
pilot_stack = realloc(pilot_stack, ++pilots*sizeof(Pilot*)); pilot_stack = realloc(pilot_stack, ++pilots*sizeof(Pilot*));
pilot_stack[pilots-1] = dyn; pilot_stack[pilots-1] = dyn;
}
return dyn->id; return dyn->id;
} }
// Frees and cleans up a pilot. // Frees and cleans up a pilot.
void pilot_destroy(Pilot* p) { static void pilot_free(Pilot* p) {
int i;
solid_free(p->solid); solid_free(p->solid);
free(p->outfits);
free(p->name); free(p->name);
ai_destroy(p); ai_destroy(p);
free(p);
}
// Destroy pilot from stack.
void pilot_destroy(Pilot* p) {
int i;
for(i = 0; i < pilots; i++) for(i = 0; i < pilots; i++)
if(pilot_stack[i] == p) if(pilot_stack[i] == p)
break; break;
@ -128,27 +197,27 @@ void pilot_destroy(Pilot* p) {
pilot_stack[i] = pilot_stack[i+1]; pilot_stack[i] = pilot_stack[i+1];
i++; i++;
} }
free(p); pilot_free(p);
} }
// Free the prisoned pilot! // Free the prisoned pilot!
void pilots_free(void) { void pilots_free(void) {
int i; int i;
for(i = 0; i < pilots; i++) { for(i = 0; i < pilots; i++)
solid_free(pilot_stack[i]->solid); pilot_free(pilot_stack[i]);
free(pilot_stack[i]->name);
free(pilot_stack[i]);
}
free(pilot_stack); free(pilot_stack);
} }
// Update all pilots. // Update all pilots.
void pilots_update(double dt) { void pilots_update(double dt) {
int i; int i;
for(i = pilots-1; i >= 0; i--) { for(i = 0; i < pilots; i++) {
if(pilot_stack[i]->think != NULL) if(pilot_stack[i]->think)
pilot_stack[i]->think(pilot_stack[i]); pilot_stack[i]->think(pilot_stack[i]);
if(pilot_stack[i]->update)
pilot_stack[i]->update(pilot_stack[i], dt); pilot_stack[i]->update(pilot_stack[i], dt);
if(pilot_stack[i]->render)
pilot_stack[i]->render(pilot_stack[i]);
} }
} }

View File

@ -2,10 +2,17 @@
#include "main.h" #include "main.h"
#include "physics.h" #include "physics.h"
#include "ai.h" #include "ai.h"
#include "outfit.h"
#include "ship.h" #include "ship.h"
#define PILOT_PLAYER 1 // Pilot is a player. #define PILOT_PLAYER 1 // Pilot is a player.
typedef struct {
Outfit* outfit; // Associated outfit.
unsigned int quantity; // Number of outfits of this type that the pilot has.
unsigned int timer; // Used to store last used weapon time.
} PilotOutfit;
// Primary pilot structure. // Primary pilot structure.
typedef struct Pilot { typedef struct Pilot {
unsigned int id; // Pilots id. unsigned int id; // Pilots id.
@ -18,24 +25,30 @@ typedef struct Pilot {
// Current health. // Current health.
double armor, shield, energy; double armor, shield, energy;
void (*think)(struct Pilot*); // AI thinking for the pilot.
void (*update)(struct Pilot*, const double); // Update the pilot. void (*update)(struct Pilot*, const double); // Update the pilot.
void (*render)(struct Pilot*); // Rendering the pilot.
// Outfit management.
PilotOutfit* outfits;
unsigned int properties; // Used for AI etc. unsigned int properties; // Used for AI etc.
// AI. // AI.
void (*think)(struct Pilot*); // Ai thinking for the pilot.
Task* task; // Current action. Task* task; // Current action.
} Pilot; } Pilot;
extern Pilot* player; // The player. extern Pilot* player; // The player.
Pilot* get_pilot(unsigned int id); Pilot* get_pilot(unsigned int id);
// Creation. void pilot_shoot(Pilot* p, int secondary);
void pilot_init(Pilot* dest, Ship* ship, char* name,
const Vec2* vel, const Vec2* pos, const int flags);
unsigned int pilot_create(Ship* ship, char* name, const Vec2* vel, // Creation.
const Vec2* pos, const int flags); void pilot_init(Pilot* dest, Ship* ship, char* name, const double dir,
const Vec2* pos, const Vec2* vel, const int flags);
unsigned int pilot_create(Ship* ship, char* name, const double dir,
const Vec2* pos, const Vec2* vel, const int flags);
// Cleanup. // Cleanup.
void pilot_destroy(Pilot* p); void pilot_destroy(Pilot* p);

View File

@ -16,11 +16,21 @@ typedef struct {
} Keybind; } Keybind;
static Keybind** player_input; // Contains the players keybindings. static Keybind** player_input; // Contains the players keybindings.
// Name of each keybinding. // Name of each keybinding.
const char* keybindNames[] = { "accel", "left", "right" }; const char* keybindNames[] = { "accel", "left", "right", "primary" };
Pilot* player = NULL; // extern in pilot.h Pilot* player = NULL; // extern in pilot.h
static double player_turn = 0.; // Turn velocity from input. static double player_turn = 0.; // Turn velocity from input.
static double player_acc = 0.; // Accel velocity from input. static double player_acc = 0.; // Accel velocity from input.
static int player_primary = 0; // Player is shooting primary weapon.
extern void pilot_render(Pilot* pilot); // Extern is in Pilot.*
static void player_renderGUI(void);
// Render the player.
void player_render(void) {
pilot_render(player);
player_renderGUI();
}
// Used in pilot.c // Used in pilot.c
// Basically uses keyboard input instead of AI input. // Basically uses keyboard input instead of AI input.
@ -29,13 +39,15 @@ void player_think(Pilot* player) {
if(player_turn) if(player_turn)
player->solid->dir_vel -= player->ship->turn * player_turn; player->solid->dir_vel -= player->ship->turn * player_turn;
//if(player_primary) pilot_shoot(player, 0);
vect_pset(&player->solid->force, player->ship->thrust * player_acc, player->solid->dir); vect_pset(&player->solid->force, player->ship->thrust * player_acc, player->solid->dir);
} }
// ================ // ================
// GUI! // GUI!
// ================ // ================
void player_renderGUI(void) { static void player_renderGUI(void) {
} }
@ -99,6 +111,11 @@ static void input_key(int keynum, double value, int abs) {
if(abs) player_turn = value; if(abs) player_turn = value;
else player_turn += value; else player_turn += value;
} }
// Shoot primary weapon. BOOM BOOM.
else if(strcmp(player_input[keynum]->name, "primary")==0) {
if(value==KEY_PRESS) player_primary = 1;
else if(value == KEY_RELEASE) player_primary = 0;
}
//Make sure values are sane. //Make sure values are sane.
player_acc = ABS(player_acc); player_acc = ABS(player_acc);

View File

@ -1,10 +1,12 @@
#pragma once #pragma once
#include <SDL.h> #include <SDL.h>
#include "pilot.h"
extern Pilot* pilot;
typedef enum { KEYBIND_NULL, KEYBIND_KEYBOARD, KEYBIND_JAXIS, KEYBIND_JBUTTON } KeybindType; typedef enum { KEYBIND_NULL, KEYBIND_KEYBOARD, KEYBIND_JAXIS, KEYBIND_JBUTTON } KeybindType;
// GUI. void player_render(void);
void player_renderGUI(void);
int player_isFlag(unsigned int flag); int player_isFlag(unsigned int flag);
void player_setFlag(unsigned int flag); void player_setFlag(unsigned int flag);

View File

@ -6,8 +6,6 @@
#include "pack.h" #include "pack.h"
#include "ship.h" #include "ship.h"
#define MAX_PATH_NAME 30 // Maximum size of the path.
#define XML_NODE_START 1 #define XML_NODE_START 1
#define XML_NODE_TEXT 3 #define XML_NODE_TEXT 3
@ -20,6 +18,8 @@
static Ship* ship_stack = NULL; static Ship* ship_stack = NULL;
static int ships = 0; static int ships = 0;
static Ship* ship_parse(xmlNodePtr parent);
// Get a ship based on it's name. // Get a ship based on it's name.
Ship* get_ship(const char* name) { Ship* get_ship(const char* name) {
Ship* tmp = ship_stack; Ship* tmp = ship_stack;
@ -33,11 +33,13 @@ Ship* get_ship(const char* name) {
return tmp+i; return tmp+i;
} }
Ship* ship_parse(xmlNodePtr parent) { static Ship* ship_parse(xmlNodePtr parent) {
xmlNodePtr cur, node; xmlNodePtr cur, node;
Ship* tmp = CALLOC_L(Ship); Ship* tmp = CALLOC_L(Ship);
ShipOutfit* otmp, *ocur;
char str[MAX_PATH_NAME] = "\0"; char str[PATH_MAX] = "\0";
xmlChar* xstr;
tmp->name = (char*)xmlGetProp(parent, (xmlChar*)"name"); tmp->name = (char*)xmlGetProp(parent, (xmlChar*)"name");
@ -45,18 +47,12 @@ Ship* ship_parse(xmlNodePtr parent) {
while((node = node->next)) { // Load all the data. while((node = node->next)) { // Load all the data.
if(strcmp((char*)node->name, "GFX")==0) { if(strcmp((char*)node->name, "GFX")==0) {
cur = node->children; snprintf(str, strlen((char*)node->children->content)+sizeof(SHIP_GFX),
if(strcmp((char*)cur->name, "text")==0) { SHIP_GFX"%s", (char*)node->children->content);
snprintf(str, strlen((char*)cur->content)+sizeof(SHIP_GFX),
SHIP_GFX"%s", (char*)cur->content);
tmp->gfx_ship = gl_newSprite(str, 6, 6); tmp->gfx_ship = gl_newSprite(str, 6, 6);
} }
} else if(strcmp((char*)node->name, "class")==0)
else if(strcmp((char*)node->name, "class")==0) { tmp->class = atoi((char*)node->children->content);
cur = node->children;
if(strcmp((char*)cur->name, "text")==0)
tmp->class = atoi((char*)cur->content);
}
else if(strcmp((char*)node->name, "movement")==0) { else if(strcmp((char*)node->name, "movement")==0) {
cur = node->children; cur = node->children;
while((cur = cur->next)) { while((cur = cur->next)) {
@ -98,7 +94,28 @@ Ship* ship_parse(xmlNodePtr parent) {
tmp->cap_cargo = atoi((char*)cur->children->content); tmp->cap_cargo = atoi((char*)cur->children->content);
} }
} }
else if(strcmp((char*)node->name, "outfits")==0) {
cur = node->children;
while((cur = cur->next)) {
if(strcmp((char*)cur->name, "outfit")==0)
otmp = MALLOC_L(ShipOutfit);
otmp->data = outfit_get((char*)cur->children->content);
xstr = xmlGetProp(cur, (xmlChar*)"qunatity");
if(!xstr)
WARN("Ship '%s' is missing tag 'quantity for outfit '%s'", tmp->name, otmp->data->name);
otmp->quantity = atoi((char*)xstr);
free(xstr);
otmp->next = NULL;
if((ocur = tmp->outfit) == NULL) tmp->outfit = otmp;
else {
while(ocur->next);
ocur->next = otmp;
} }
}
}
}
tmp->thrust *= tmp->mass; // Helps keep number sane. tmp->thrust *= tmp->mass; // Helps keep number sane.
#define MELEMENT(o,s) if(o == 0) WARN("Ship '%s' missing '"s"' element", tmp->name) #define MELEMENT(o,s) if(o == 0) WARN("Ship '%s' missing '"s"' element", tmp->name)

View File

@ -1,10 +1,25 @@
#pragma once #pragma once
#include "main.h" #include "main.h"
#include "outfit.h"
#include "opengl.h" #include "opengl.h"
enum ship_class { SHIP_CLASS_NULL, SHIP_CLASS_CIVILIAN }; enum ship_class {
SHIP_CLASS_NULL,
SHIP_CLASS_CIV_LIGHT,
SHIP_CLASS_CIV_MEDIUM,
SHIP_CLASS_CIV_HEAVY
};
typedef enum ship_class ship_class; typedef enum ship_class ship_class;
// Small wrapper for the outfits.
typedef struct ShipOutfit {
struct ShipOutfit* next; // Linked list.
Outfit* data; // Data itself.
int quantity;
} ShipOutfit;
// Ship structure.
typedef struct { typedef struct {
char* name; // Ship name. char* name; // Ship name.
ship_class class; // Ship class. ship_class class; // Ship class.
@ -26,6 +41,9 @@ typedef struct {
// Capacity. // Capacity.
int cap_cargo, cap_weapon; int cap_cargo, cap_weapon;
// Outfits
ShipOutfit* outfit;
} Ship; } Ship;
int ships_load(void); int ships_load(void);

158
src/weapon.c Normal file
View File

@ -0,0 +1,158 @@
#include <math.h>
#include <malloc.h>
#include <string.h>
#include "outfit.h"
#include "physics.h"
#include "main.h"
#include "log.h"
#include "weapon.h"
typedef struct Weapon {
Solid* solid; // Actually has its own solid. :D
const Outfit* outfit; // Related outfit that fired.
unsigned int timer; // Mainly used to see when the weapon was fired.
void(*update)(struct Weapon*, const double); // Position update and render.
void(*think)(struct Weapon*); // Some missiles need to be inteligent.
} Weapon;
// Behind Pilot layer.
static Weapon** backLayer = NULL; // Behind pilots.
static int nbackLayer = 0; // Number of elements.
static int mbackLayer = 0; // Allocated memory size.
// Behind player layer.
static Weapon** frontLayer = NULL; // Behind pilots.
static int nfrontLayer = 0; // Number of elements.
static int mfrontLayer = 0; // Allocated memory size.
static Weapon* weapon_create(const Outfit* outfit, const double dir,
const Vec2* pos, const Vec2* vel);
static void weapon_render(const Weapon* w);
static void weapon_update(Weapon* w, const double dt);
static void weapon_free(Weapon* w);
// Update all weapons in the layer.
void weapons_update(const double dt, WeaponLayer layer) {
Weapon** wlayer;
int nlayer;
switch(layer) {
case WEAPON_LAYER_BG:
wlayer = backLayer;
nlayer = nbackLayer;
break;
case WEAPON_LAYER_FG:
wlayer = frontLayer;
nlayer = nfrontLayer;
break;
}
int i;
for(i = 0; i < nlayer; i++)
weapon_update(wlayer[i], dt);
}
// Render the weapons.
static void weapon_render(const Weapon* w) {
int sprite;
gl_texture* t = w->outfit->gfx_space;
// Get the sprite corresponding to the direction facing.
sprite = (int)(w->solid->dir / (2.0*M_PI / (t->sy*t->sx)));
gl_blitSprite(t, &w->solid->pos, sprite % (int)t->sx, sprite / (int)t->sy);
}
// Update the weapon.
static void weapon_update(Weapon* w, const double dt) {
if(w->think)
(*w->think)(w);
(*w->solid->update)(w->solid, dt);
weapon_render(w);
}
static Weapon* weapon_create(const Outfit* outfit, const double dir, const Vec2* pos, const Vec2* vel) {
Vec2 v;
double mass = 1; // Presumer lasers have a mass of 1.
Weapon* w = MALLOC_L(Weapon);
w->outfit = outfit; // Non-Changeable.
w->update = weapon_update;
w->think = NULL;
switch(outfit->type) {
case OUTFIT_TYPE_BOLT:
vect_cset(&v, VY(*vel)+outfit->speed*cos(dir), VANGLE(*vel)+outfit->speed*sin(dir));
w->solid = solid_create(mass, dir, pos, &v);
break;
default:
break;
}
return w;
}
// Add a new weapon.
void weapon_add(const Outfit* outfit, const double dir, const Vec2* pos, const Vec2* vel, WeaponLayer layer) {
if(!outfit_isWeapon(outfit)) {
ERR("Trying to create a weapon from a non-Weapon type Outfit");
return;
}
Weapon* w = weapon_create(outfit, dir, pos, vel);
// Set the propper layer.
Weapon** curLayer = NULL;
int* mLayer = NULL;
int* nLayer = NULL;
switch(layer) {
case WEAPON_LAYER_BG:
curLayer = backLayer;
nLayer = &nbackLayer;
mLayer = &mbackLayer;
break;
case WEAPON_LAYER_FG:
curLayer = frontLayer;
nLayer = &nfrontLayer;
mLayer = &mfrontLayer;
break;
default:
ERR("Invalid WEAPON_LAYER specified.");
return;
}
if(*mLayer > *nLayer) // More memory allocated than what we need.
curLayer[(*nLayer)++] = w;
else { // Need to allocate more memory.
switch(layer) {
case WEAPON_LAYER_BG:
curLayer = backLayer = realloc(curLayer, (++(*mLayer))*sizeof(Weapon));
break;
case WEAPON_LAYER_FG:
curLayer = frontLayer = realloc(curLayer, (++(*mLayer))*sizeof(Weapon*));
break;
}
curLayer[(*nLayer)++] = w;
}
}
// Clear the weapon.
static void weapon_free(Weapon* w) {
solid_free(w->solid);
free(w);
}
// Clear all the weapons, do not free the layers.
void weapon_clear(void) {
int i;
for(i = 0; i < nbackLayer; i++)
weapon_free(backLayer[i]);
nbackLayer = 0;
backLayer = NULL;
for(i = 0; i < nfrontLayer; i++)
weapon_free(frontLayer[i]);
nfrontLayer = 0;
frontLayer = NULL;
}

11
src/weapon.h Normal file
View File

@ -0,0 +1,11 @@
#pragma once
#include "outfit.h"
#include "physics.h"
typedef enum { WEAPON_LAYER_BG, WEAPON_LAYER_FG } WeaponLayer;
void weapon_add(const Outfit* outfit, const double dir,
const Vec2* pos, const Vec2* vel, WeaponLayer layer);
void weapons_update(const double dt, WeaponLayer layer);