[Add] Rudimentary shooting. This needs some work.
[Add] Layers should be working properly.
This commit is contained in:
parent
b13ecc66bb
commit
998a1bf68b
1
.gitignore
vendored
1
.gitignore
vendored
@ -26,5 +26,6 @@
|
||||
*bin/Lephisto
|
||||
*bin/data
|
||||
*pack
|
||||
*core
|
||||
|
||||
|
||||
|
@ -48,5 +48,5 @@ data: pack $(DATAFILES) ../src/pack.c
|
||||
|
||||
clean:
|
||||
@echo -e "\tRemoving data.."
|
||||
rm -rf $(OBJS) $(APPNAME) $(DATA) pack
|
||||
rm -rf $(OBJS) $(APPNAME) $(DATA) pack core
|
||||
|
||||
|
@ -9,7 +9,9 @@
|
||||
<specific type = "1">
|
||||
<sound>laser.wav</sound>
|
||||
<gfx>lasergreen.png</gfx>
|
||||
<speed>450</speed>
|
||||
<delay>500</delay>
|
||||
<speed>550</speed>
|
||||
<range>300</range>
|
||||
<accuracy>30</accuracy>
|
||||
<damage>
|
||||
<armor>20</armor>
|
||||
|
1
src/ai.c
1
src/ai.c
@ -89,6 +89,7 @@ static double pilot_turn = 0.;
|
||||
|
||||
// Destroy the AI part of the pilot.
|
||||
void ai_destroy(Pilot* p) {
|
||||
if(p->task)
|
||||
ai_freetask(p->task);
|
||||
}
|
||||
|
||||
|
60
src/main.c
60
src/main.c
@ -18,9 +18,11 @@
|
||||
#include "rng.h"
|
||||
#include "ai.h"
|
||||
#include "outfit.h"
|
||||
#include "pack.h"
|
||||
#include "weapon.h"
|
||||
#include "pilot.h"
|
||||
|
||||
#define WINDOW_CAPTION "Lephisto"
|
||||
#define APPNAME "Lephisto"
|
||||
#define CONF_FILE "conf"
|
||||
#define MINIMUM_FPS 0.5
|
||||
|
||||
@ -31,14 +33,13 @@ static unsigned int time = 0; // Calculate FPS and movement.
|
||||
|
||||
#define DATA_DEF "data"
|
||||
char* data = NULL;
|
||||
|
||||
static int show_fps = 1; // Default - True.
|
||||
static int max_fps = 0;
|
||||
|
||||
// Prototypes.
|
||||
|
||||
static void print_usage(char** argv);
|
||||
static void display_fps(const double dt);
|
||||
|
||||
// Update.
|
||||
static void update_all(void);
|
||||
|
||||
@ -47,7 +48,7 @@ static void print_usage(char** argv) {
|
||||
LOG("USAGE: %s [OPTION]", argv[0]);
|
||||
LOG("Options are:");
|
||||
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-j n, --joystick n - Use joystick (n)");
|
||||
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 i;
|
||||
|
||||
// Print the version.
|
||||
LOG(""APPNAME" v%d.%d.%d", VMAJOR, VMINOR, VREV);
|
||||
|
||||
// Initialize SDL for possible warnings.
|
||||
SDL_Init(0);
|
||||
// Default values..
|
||||
@ -74,6 +79,7 @@ int main(int argc, char** argv) {
|
||||
input_setKeybind("accel", KEYBIND_KEYBOARD, SDLK_w, 0);
|
||||
input_setKeybind("left", KEYBIND_KEYBOARD, SDLK_a, 0);
|
||||
input_setKeybind("right", KEYBIND_KEYBOARD, SDLK_d, 0);
|
||||
input_setKeybind("primary", KEYBIND_KEYBOARD, SDLK_SPACE, 0);
|
||||
|
||||
// Use Lua to parse configuration file.
|
||||
lua_State* L = luaL_newstate();
|
||||
@ -96,7 +102,7 @@ int main(int argc, char** argv) {
|
||||
|
||||
lua_getglobal(L, "fps");
|
||||
if(lua_isnumber(L, -1))
|
||||
show_fps = (int)lua_tonumber(L, -1);
|
||||
max_fps = (int)lua_tonumber(L, -1);
|
||||
|
||||
// Joystick.
|
||||
lua_getglobal(L, "joystick");
|
||||
@ -153,7 +159,7 @@ int main(int argc, char** argv) {
|
||||
// Parse arguments.
|
||||
static struct option long_options[] = {
|
||||
{ "fullscreen", no_argument, 0, 'f' },
|
||||
{ "fps", optional_argument, 0, 'F' },
|
||||
{ "fps", required_argument, 0, 'F' },
|
||||
{ "data", required_argument, 0, 'd' },
|
||||
{ "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 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) {
|
||||
case 'f':
|
||||
gl_screen.fullscreen = 1;
|
||||
break;
|
||||
case 'F':
|
||||
if(optarg != NULL) show_fps = atoi(optarg);
|
||||
else show_fps = !show_fps;
|
||||
else max_fps = !show_fps;
|
||||
break;
|
||||
case 'd':
|
||||
data = strdup(optarg);
|
||||
@ -195,11 +201,21 @@ int main(int argc, char** argv) {
|
||||
if(gl_init()) {
|
||||
// Initializes video output.
|
||||
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);
|
||||
}
|
||||
|
||||
// Window.
|
||||
SDL_WM_SetCaption(WINDOW_CAPTION, NULL);
|
||||
SDL_WM_SetCaption(APPNAME, NULL);
|
||||
|
||||
// Input.
|
||||
if(indjoystick >= 0 || namjoystick != NULL) {
|
||||
@ -225,11 +241,11 @@ int main(int argc, char** argv) {
|
||||
space_load();
|
||||
|
||||
// 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);
|
||||
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();
|
||||
|
||||
@ -268,19 +284,23 @@ int main(int argc, char** argv) {
|
||||
//
|
||||
// BG | Stars and planets.
|
||||
// | Background particles.
|
||||
// | Back layer weapons.
|
||||
// X
|
||||
// N | NPC ships.
|
||||
// | Normal layer particles (above ships).
|
||||
// | Front layer weapons.
|
||||
// X
|
||||
// FG | Player.
|
||||
// | Foreground particles.
|
||||
// | Text and GUI.
|
||||
// ========================================================
|
||||
static double fps_dt = 1.;
|
||||
static void update_all(void) {
|
||||
// dt in us.
|
||||
double dt = (double)(SDL_GetTicks() - time) / 1000.;
|
||||
time = SDL_GetTicks();
|
||||
|
||||
// TODO: This could use some work.
|
||||
if(dt > MINIMUM_FPS) {
|
||||
Vec2 pos;
|
||||
vect_csetmin(&pos, 10., (double)(gl_screen.h-40));
|
||||
@ -288,20 +308,27 @@ static void update_all(void) {
|
||||
SDL_GL_SwapBuffers();
|
||||
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);
|
||||
|
||||
// --
|
||||
// BG.
|
||||
space_render(dt);
|
||||
planets_render();
|
||||
|
||||
// N
|
||||
weapons_update(dt, WEAPON_LAYER_BG);
|
||||
// N.
|
||||
pilots_update(dt);
|
||||
|
||||
weapons_update(dt, WEAPON_LAYER_FG);
|
||||
// FG.
|
||||
player_renderGUI();
|
||||
|
||||
player_render();
|
||||
display_fps(dt);
|
||||
// --
|
||||
|
||||
SDL_GL_SwapBuffers();
|
||||
}
|
||||
@ -310,7 +337,6 @@ static void update_all(void) {
|
||||
// Spit this out on display.
|
||||
static double fps = 0.;
|
||||
static double fps_cur = 0.;
|
||||
static double fps_dt = 1.;
|
||||
static void display_fps(const double dt) {
|
||||
fps_dt += dt;
|
||||
fps_cur += 1.;
|
||||
|
38
src/outfit.c
38
src/outfit.c
@ -4,6 +4,7 @@
|
||||
|
||||
#include "main.h"
|
||||
#include "log.h"
|
||||
#include "pack.h"
|
||||
#include "outfit.h"
|
||||
|
||||
#define XML_NODE_START 1
|
||||
@ -31,8 +32,27 @@ Outfit* outfit_get(const char* name) {
|
||||
}
|
||||
|
||||
// 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);
|
||||
int outfit_isWeapon(const Outfit* o) {
|
||||
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[] = {
|
||||
@ -40,10 +60,15 @@ const char* outfit_typename[] = {
|
||||
"Bolt Cannon",
|
||||
"Beam Cannon",
|
||||
"Dumb Missile",
|
||||
"Dumb Missile Ammunition",
|
||||
"Seeker Missile",
|
||||
"Smart Missile",
|
||||
"Seeker Missile Ammunition",
|
||||
"Smart Seeker Missile",
|
||||
"Smart Seeker Missile Ammunition",
|
||||
"Swam Missile",
|
||||
"Smart Swarm Missile"
|
||||
"Swarm Missile Ammunition Pack",
|
||||
"Smart Swarm Missile",
|
||||
"Smart Swarm Missile Ammunition Pack"
|
||||
};
|
||||
|
||||
const char* outfit_getType(const Outfit* o) {
|
||||
@ -61,6 +86,8 @@ static void outfit_parseSWeapon(Outfit* tmp, const xmlNodePtr parent) {
|
||||
// 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, "delay")==0)
|
||||
tmp->delay = 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) {
|
||||
@ -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)
|
||||
MELEMENT(tmp->speed, "speed");
|
||||
MELEMENT(tmp->accuracy, "tech");
|
||||
MELEMENT(tmp->delay, "delay");
|
||||
MELEMENT(tmp->damage_armor, "armor' from element 'damage");
|
||||
MELEMENT(tmp->damage_shield, "shield' from element 'damage");
|
||||
#undef MELEMENT
|
||||
@ -181,7 +209,7 @@ int outfit_load(void) {
|
||||
void outfit_free(void) {
|
||||
int 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);
|
||||
free(outfit_stack[i].name);
|
||||
}
|
||||
|
44
src/outfit.h
44
src/outfit.h
@ -1,42 +1,70 @@
|
||||
#pragma once
|
||||
#include "opengl.h"
|
||||
|
||||
#define OUTFIT_PROP_WEAP_PRIMARY (1<<0)
|
||||
#define OUTFIT_PROP_WEAP_SECONDARY (1<<1)
|
||||
|
||||
// Outfit types.
|
||||
typedef enum {
|
||||
OUTFIT_TYPE_NULL,
|
||||
OUTFIT_TYPE_NULL = 0,
|
||||
OUTFIT_TYPE_BOLT,
|
||||
OUTFIT_TYPE_BEAM,
|
||||
OUTFIT_TYPE_MISSILE_DUMB,
|
||||
OUTFIT_TYPE_MISSILE_DUMB_AMMO,
|
||||
OUTFIT_TYPE_MISSILE_SEEK,
|
||||
OUTFIT_TYPE_MISSILE_SEEK_AMMO,
|
||||
OUTFIT_TYPE_MISSILE_SEEK_SMART,
|
||||
OUTFIT_TYPE_MISSILE_SEEK_SMART_AMMO,
|
||||
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;
|
||||
|
||||
// An outfit depends a lot on the type.
|
||||
typedef struct {
|
||||
char* name;
|
||||
|
||||
// General specs.
|
||||
int max;
|
||||
int tech;
|
||||
int mass;
|
||||
|
||||
gl_texture gfx_store;
|
||||
gl_texture gfx_store; // Store graphic.
|
||||
|
||||
int properties; // Properties stored bitwise.
|
||||
|
||||
// Type dependant.
|
||||
OutfitType type;
|
||||
union {
|
||||
struct {
|
||||
double speed;
|
||||
double accuracy;
|
||||
double damage_armor, damage_shield;
|
||||
struct { // Beam/Bolt.
|
||||
unsigned int delay; // Delay between shots.
|
||||
double speed; // Speed of shot. (not applicable to beam.
|
||||
double range;
|
||||
double accuracy; // Desviation accuracy.
|
||||
double damage_armor, damage_shield; // Damage.
|
||||
|
||||
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_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);
|
||||
|
||||
// Load/free outfit stack.
|
||||
|
@ -175,11 +175,11 @@ static void rk4_update(Solid* obj, const double dt) {
|
||||
}
|
||||
|
||||
// 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;
|
||||
|
||||
vect_cset(&dest->force, 0., 0.);
|
||||
dest->dir = 0.;
|
||||
dest->dir = dir;
|
||||
|
||||
if(vel == NULL) vectnull(&dest->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.
|
||||
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);
|
||||
assert(dyn != NULL);
|
||||
solid_init(dyn, mass, vel, pos);
|
||||
solid_init(dyn, mass, dir, pos, vel);
|
||||
return dyn;
|
||||
}
|
||||
|
||||
|
@ -37,7 +37,9 @@ struct Solid {
|
||||
typedef struct Solid Solid;
|
||||
|
||||
// Solid manipulation.
|
||||
void solid_init(Solid* dest, const double mass, const Vec2* vel, const Vec2* pos);
|
||||
Solid* solid_create(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);
|
||||
Solid* solid_create(const double mass, const double dir,
|
||||
const Vec2* pos, const Vec2* vel);
|
||||
void solid_free(Solid* src);
|
||||
|
||||
|
113
src/pilot.c
113
src/pilot.c
@ -5,6 +5,7 @@
|
||||
|
||||
#include "main.h"
|
||||
#include "log.h"
|
||||
#include "weapon.h"
|
||||
#include "pilot.h"
|
||||
|
||||
// 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.
|
||||
static Pilot** pilot_stack;
|
||||
static int pilots = 0;
|
||||
extern Pilot* player;
|
||||
|
||||
// External.
|
||||
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
|
||||
// Internal.
|
||||
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.
|
||||
Pilot* get_pilot(unsigned int id) {
|
||||
@ -31,6 +34,7 @@ Pilot* get_pilot(unsigned int id) {
|
||||
return pilot_stack[i];
|
||||
return NULL;
|
||||
#endif
|
||||
if(id == 0) return player;
|
||||
// Dichotomical search.
|
||||
int i, n;
|
||||
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;
|
||||
}
|
||||
|
||||
// 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.
|
||||
static void pilot_render(Pilot* pilot) {
|
||||
void pilot_render(Pilot* p) {
|
||||
int sprite;
|
||||
gl_texture* texture = pilot->ship->gfx_ship;
|
||||
gl_texture* t = p->ship->gfx_ship;
|
||||
|
||||
// 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.
|
||||
@ -68,17 +97,23 @@ static void pilot_update(Pilot* pilot, const double dt) {
|
||||
// ==Init pilot.===========================================
|
||||
// ship : Ship pilot is flying.
|
||||
// name : Pilot's name, if NULL, ships name will be used.
|
||||
// dir : Initial facing direction. (radians)
|
||||
// vel : Initial velocity.
|
||||
// pos : Initial position.
|
||||
// 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->ship = ship;
|
||||
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.
|
||||
pilot->armor = ship->armor;
|
||||
@ -88,39 +123,73 @@ void pilot_init(Pilot* pilot, Ship* ship, char* name, const Vec2* vel, const Vec
|
||||
// Initially idle.
|
||||
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) {
|
||||
pilot->think = player_think; // Players don't need to thing! :P
|
||||
pilot->render = NULL;
|
||||
pilot->properties |= PILOT_PLAYER;
|
||||
player = pilot;
|
||||
} else
|
||||
} else {
|
||||
pilot->think = ai_think;
|
||||
|
||||
pilot->update = pilot_update;
|
||||
}
|
||||
}
|
||||
|
||||
// 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);
|
||||
if(dyn == NULL) {
|
||||
WARN("Unable to allocate memory.");
|
||||
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.
|
||||
pilot_stack = realloc(pilot_stack, ++pilots*sizeof(Pilot*));
|
||||
pilot_stack[pilots-1] = dyn;
|
||||
}
|
||||
return dyn->id;
|
||||
}
|
||||
|
||||
// Frees and cleans up a pilot.
|
||||
void pilot_destroy(Pilot* p) {
|
||||
int i;
|
||||
|
||||
static void pilot_free(Pilot* p) {
|
||||
solid_free(p->solid);
|
||||
free(p->outfits);
|
||||
free(p->name);
|
||||
ai_destroy(p);
|
||||
free(p);
|
||||
}
|
||||
|
||||
// Destroy pilot from stack.
|
||||
void pilot_destroy(Pilot* p) {
|
||||
int i;
|
||||
for(i = 0; i < pilots; i++)
|
||||
if(pilot_stack[i] == p)
|
||||
break;
|
||||
@ -128,27 +197,27 @@ void pilot_destroy(Pilot* p) {
|
||||
pilot_stack[i] = pilot_stack[i+1];
|
||||
i++;
|
||||
}
|
||||
free(p);
|
||||
pilot_free(p);
|
||||
}
|
||||
|
||||
// Free the prisoned pilot!
|
||||
void pilots_free(void) {
|
||||
int i;
|
||||
for(i = 0; i < pilots; i++) {
|
||||
solid_free(pilot_stack[i]->solid);
|
||||
free(pilot_stack[i]->name);
|
||||
free(pilot_stack[i]);
|
||||
}
|
||||
for(i = 0; i < pilots; i++)
|
||||
pilot_free(pilot_stack[i]);
|
||||
free(pilot_stack);
|
||||
}
|
||||
|
||||
// Update all pilots.
|
||||
void pilots_update(double dt) {
|
||||
int i;
|
||||
for(i = pilots-1; i >= 0; i--) {
|
||||
if(pilot_stack[i]->think != NULL)
|
||||
for(i = 0; i < pilots; i++) {
|
||||
if(pilot_stack[i]->think)
|
||||
pilot_stack[i]->think(pilot_stack[i]);
|
||||
if(pilot_stack[i]->update)
|
||||
pilot_stack[i]->update(pilot_stack[i], dt);
|
||||
if(pilot_stack[i]->render)
|
||||
pilot_stack[i]->render(pilot_stack[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
25
src/pilot.h
25
src/pilot.h
@ -2,10 +2,17 @@
|
||||
#include "main.h"
|
||||
#include "physics.h"
|
||||
#include "ai.h"
|
||||
#include "outfit.h"
|
||||
#include "ship.h"
|
||||
|
||||
#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.
|
||||
typedef struct Pilot {
|
||||
unsigned int id; // Pilots id.
|
||||
@ -18,24 +25,30 @@ typedef struct Pilot {
|
||||
// Current health.
|
||||
double armor, shield, energy;
|
||||
|
||||
void (*think)(struct Pilot*); // AI thinking for 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.
|
||||
|
||||
// AI.
|
||||
void (*think)(struct Pilot*); // Ai thinking for the pilot.
|
||||
Task* task; // Current action.
|
||||
} Pilot;
|
||||
|
||||
extern Pilot* player; // The player.
|
||||
Pilot* get_pilot(unsigned int id);
|
||||
|
||||
// Creation.
|
||||
void pilot_init(Pilot* dest, Ship* ship, char* name,
|
||||
const Vec2* vel, const Vec2* pos, const int flags);
|
||||
void pilot_shoot(Pilot* p, int secondary);
|
||||
|
||||
unsigned int pilot_create(Ship* ship, char* name, const Vec2* vel,
|
||||
const Vec2* pos, const int flags);
|
||||
// Creation.
|
||||
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.
|
||||
void pilot_destroy(Pilot* p);
|
||||
|
21
src/player.c
21
src/player.c
@ -16,11 +16,21 @@ typedef struct {
|
||||
} Keybind;
|
||||
static Keybind** player_input; // Contains the players keybindings.
|
||||
// Name of each keybinding.
|
||||
const char* keybindNames[] = { "accel", "left", "right" };
|
||||
const char* keybindNames[] = { "accel", "left", "right", "primary" };
|
||||
|
||||
Pilot* player = NULL; // extern in pilot.h
|
||||
static double player_turn = 0.; // Turn 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
|
||||
// Basically uses keyboard input instead of AI input.
|
||||
@ -29,13 +39,15 @@ void player_think(Pilot* player) {
|
||||
if(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);
|
||||
}
|
||||
|
||||
// ================
|
||||
// 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;
|
||||
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.
|
||||
player_acc = ABS(player_acc);
|
||||
|
@ -1,10 +1,12 @@
|
||||
#pragma once
|
||||
#include <SDL.h>
|
||||
#include "pilot.h"
|
||||
|
||||
extern Pilot* pilot;
|
||||
|
||||
typedef enum { KEYBIND_NULL, KEYBIND_KEYBOARD, KEYBIND_JAXIS, KEYBIND_JBUTTON } KeybindType;
|
||||
|
||||
// GUI.
|
||||
void player_renderGUI(void);
|
||||
void player_render(void);
|
||||
|
||||
int player_isFlag(unsigned int flag);
|
||||
void player_setFlag(unsigned int flag);
|
||||
|
45
src/ship.c
45
src/ship.c
@ -6,8 +6,6 @@
|
||||
#include "pack.h"
|
||||
#include "ship.h"
|
||||
|
||||
#define MAX_PATH_NAME 30 // Maximum size of the path.
|
||||
|
||||
#define XML_NODE_START 1
|
||||
#define XML_NODE_TEXT 3
|
||||
|
||||
@ -20,6 +18,8 @@
|
||||
static Ship* ship_stack = NULL;
|
||||
static int ships = 0;
|
||||
|
||||
static Ship* ship_parse(xmlNodePtr parent);
|
||||
|
||||
// Get a ship based on it's name.
|
||||
Ship* get_ship(const char* name) {
|
||||
Ship* tmp = ship_stack;
|
||||
@ -33,11 +33,13 @@ Ship* get_ship(const char* name) {
|
||||
return tmp+i;
|
||||
}
|
||||
|
||||
Ship* ship_parse(xmlNodePtr parent) {
|
||||
static Ship* ship_parse(xmlNodePtr parent) {
|
||||
xmlNodePtr cur, node;
|
||||
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");
|
||||
|
||||
@ -45,18 +47,12 @@ Ship* ship_parse(xmlNodePtr parent) {
|
||||
|
||||
while((node = node->next)) { // Load all the data.
|
||||
if(strcmp((char*)node->name, "GFX")==0) {
|
||||
cur = node->children;
|
||||
if(strcmp((char*)cur->name, "text")==0) {
|
||||
snprintf(str, strlen((char*)cur->content)+sizeof(SHIP_GFX),
|
||||
SHIP_GFX"%s", (char*)cur->content);
|
||||
snprintf(str, strlen((char*)node->children->content)+sizeof(SHIP_GFX),
|
||||
SHIP_GFX"%s", (char*)node->children->content);
|
||||
tmp->gfx_ship = gl_newSprite(str, 6, 6);
|
||||
}
|
||||
}
|
||||
else if(strcmp((char*)node->name, "class")==0) {
|
||||
cur = node->children;
|
||||
if(strcmp((char*)cur->name, "text")==0)
|
||||
tmp->class = atoi((char*)cur->content);
|
||||
}
|
||||
else if(strcmp((char*)node->name, "class")==0)
|
||||
tmp->class = atoi((char*)node->children->content);
|
||||
else if(strcmp((char*)node->name, "movement")==0) {
|
||||
cur = node->children;
|
||||
while((cur = cur->next)) {
|
||||
@ -98,7 +94,28 @@ Ship* ship_parse(xmlNodePtr parent) {
|
||||
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.
|
||||
|
||||
#define MELEMENT(o,s) if(o == 0) WARN("Ship '%s' missing '"s"' element", tmp->name)
|
||||
|
20
src/ship.h
20
src/ship.h
@ -1,10 +1,25 @@
|
||||
#pragma once
|
||||
#include "main.h"
|
||||
#include "outfit.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;
|
||||
|
||||
// Small wrapper for the outfits.
|
||||
typedef struct ShipOutfit {
|
||||
struct ShipOutfit* next; // Linked list.
|
||||
Outfit* data; // Data itself.
|
||||
int quantity;
|
||||
} ShipOutfit;
|
||||
|
||||
|
||||
// Ship structure.
|
||||
typedef struct {
|
||||
char* name; // Ship name.
|
||||
ship_class class; // Ship class.
|
||||
@ -26,6 +41,9 @@ typedef struct {
|
||||
|
||||
// Capacity.
|
||||
int cap_cargo, cap_weapon;
|
||||
|
||||
// Outfits
|
||||
ShipOutfit* outfit;
|
||||
} Ship;
|
||||
|
||||
int ships_load(void);
|
||||
|
158
src/weapon.c
Normal file
158
src/weapon.c
Normal 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
11
src/weapon.h
Normal 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);
|
||||
|
Loading…
Reference in New Issue
Block a user