diff --git a/gfx/gui/frame.png b/gfx/gui/frame.png new file mode 100644 index 0000000..c92e2d2 Binary files /dev/null and b/gfx/gui/frame.png differ diff --git a/gfx/gui/frame.xcf b/gfx/gui/frame.xcf new file mode 100644 index 0000000..b8b8bc7 Binary files /dev/null and b/gfx/gui/frame.xcf differ diff --git a/src/main.c b/src/main.c index 98a6696..122a607 100644 --- a/src/main.c +++ b/src/main.c @@ -222,10 +222,12 @@ int main(int argc, char** argv) { if(joystick_init()) WARN("Error initializing joystick input"); if(namjoystick != NULL) { + // Use a joystick name to find joystick. joystick_use(joystick_get(namjoystick)); free(namjoystick); } else if(indjoystick >= 0) + // Must be using an id instead. joystick_use(indjoystick); } @@ -234,6 +236,7 @@ int main(int argc, char** argv) { WARN("Error initializing AI"); gl_fontInit(NULL, NULL, 16); + gui_init(); // Init the GUI crap. // Data loading. outfit_load(); @@ -267,6 +270,7 @@ int main(int argc, char** argv) { weapon_exit(); // Destroy all active weapons. space_exit(); // Clean up the universe!!! pilots_free(); // Free the pilots, they where locked up D: + gui_free(); // Free up the gui. ships_free(); outfit_free(); diff --git a/src/main.h b/src/main.h index baef2c0..8a2ec08 100644 --- a/src/main.h +++ b/src/main.h @@ -3,7 +3,10 @@ #define MALLOC_L(type)(malloc(sizeof(type))) #define CALLOC_L(type)(calloc(1, sizeof(type))) -#define ABS(X) ((X<0)?-X:X) +#define ABS(x) ((x<0)?-(x):(x)) + +#define MAX(x,y) (((x)>(y))?(x):(y)) +#define MIN(x,y) (((x)>(y))?(y):(x)) extern char* data; // Modifiable datafile. #define DATA data // Data file. diff --git a/src/opengl.c b/src/opengl.c index 3486090..c609230 100644 --- a/src/opengl.c +++ b/src/opengl.c @@ -17,6 +17,10 @@ #define FONT_DEF "../gfx/fonts/FreeSans.ttf" +// offsets to Adjust the pilot's place onscreen to be in the middle, even with the GUI. +extern double gui_xoff; +extern double gui_yoff; + // The screen info, gives data of current opengl settings. gl_info gl_screen; @@ -256,8 +260,8 @@ void gl_blitSprite(const gl_texture* sprite, const Vec2* pos, const int sx, cons glMatrixMode(GL_PROJECTION); glPushMatrix(); // Projection translation matrix. - glTranslated(VX(*pos) - VX(*gl_camera) - sprite->sw/2., - VY(*pos) -VY(*gl_camera) - sprite->sh/2., 0.); + glTranslated(VX(*pos) - VX(*gl_camera) - sprite->sw/2. + gui_xoff, + VY(*pos) -VY(*gl_camera) - sprite->sh/2. + gui_yoff, 0.); glScalef((double)gl_screen.w/SCREEN_W, (double)gl_screen.h/SCREEN_H, 0.); // Actual blitting.... @@ -293,15 +297,15 @@ void gl_blitStatic(const gl_texture* texture, const Vec2* pos) { // Actual blitting.. glBindTexture(GL_TEXTURE_2D, texture->texture); glBegin(GL_TRIANGLE_STRIP); - glColor4ub(1., 1., 1., 1.); + glColor4d(1., 1., 1., 1.); glTexCoord2d(0., 0.); glVertex2d(0., 0.); - glTexCoord2d(texture->w/texture->rw, 0.); - glVertex2d(texture->w, 0.); - glTexCoord2d(0., texture->h/texture->rh); - glVertex2d(0., texture->h); - glTexCoord2d(texture->w/texture->rw, texture->h/texture->rh); - glVertex2d(texture->w, texture->h); + glTexCoord2d(texture->sw/texture->rw, 0.); + glVertex2d(texture->sw, 0.); + glTexCoord2d(0., texture->sh/texture->rh); + glVertex2d(0., texture->sh); + glTexCoord2d(texture->sw/texture->rw, texture->sh/texture->rh); + glVertex2d(texture->sw, texture->h); glEnd(); glPopMatrix(); // Pop the translation matrix. diff --git a/src/pilot.c b/src/pilot.c index 7fa82d6..66a78e2 100644 --- a/src/pilot.c +++ b/src/pilot.c @@ -75,12 +75,16 @@ void pilot_hit(Pilot* p, double damage_shield, double damage_armor) { // Shields can take part of the blow. p->armor -= p->shield/damage_shield*damage_armor; } + else if(p->armor-damage_armor > 0.) + p->armor -= damage_armor; + else + p->armor = 0.; } // Render the pilot. void pilot_render(Pilot* p) { int sprite; - gl_texture* t = p->ship->gfx_ship; + gl_texture* t = p->ship->gfx_space; // Get the sprite corresponding to the direction facing. sprite = (int)(p->solid->dir / (2.0*M_PI / (t->sy * t->sx))); @@ -90,6 +94,15 @@ void pilot_render(Pilot* p) { // Update the pilot. static void pilot_update(Pilot* pilot, const double dt) { + // Regeneration. + if(pilot->armor < pilot->armor_max) + pilot->armor += pilot->ship->armor_regen*dt; + else + pilot->shield += pilot->ship->shield_regen*dt; + + if(pilot->armor > pilot->armor_max) pilot->armor = pilot->armor_max; + if(pilot->armor > pilot->armor_max) pilot->armor = pilot->armor_max; + if((pilot->solid->dir > 2.*M_PI) || (pilot->solid->dir < 0.0)) pilot->solid->dir = fmod(pilot->solid->dir, 2.*M_PI); @@ -126,9 +139,13 @@ void pilot_init(Pilot* pilot, Ship* ship, char* name, const double dir, const Ve pilot->solid = solid_create(ship->mass, dir, pos, vel); // Max shields armor. - pilot->armor = ship->armor; - pilot->shield = ship->shield; - pilot->energy = ship->energy; + pilot->armor_max = ship->armor; + pilot->shield_max = ship->shield; + pilot->energy_max = ship->energy; + pilot->armor = pilot->armor_max; + pilot->shield = pilot->shield_max; + pilot->energy = pilot->energy_max; + // Initially idle. pilot->task = NULL; diff --git a/src/pilot.h b/src/pilot.h index f3a4832..84e34ac 100644 --- a/src/pilot.h +++ b/src/pilot.h @@ -5,6 +5,10 @@ #include "outfit.h" #include "ship.h" +// Aproximation for pilot size. +#define PILOT_SIZE_APROX 0.8 + +// Creation flags. #define PILOT_PLAYER 1 // Pilot is a player. typedef struct { @@ -24,6 +28,7 @@ typedef struct Pilot { // Current health. double armor, shield, energy; + double armor_max, shield_max, energy_max; void (*think)(struct Pilot*); // AI thinking for the pilot. void (*update)(struct Pilot*, const double); // Update the pilot. diff --git a/src/player.c b/src/player.c index 4c66d0f..5f177bf 100644 --- a/src/player.c +++ b/src/player.c @@ -2,8 +2,11 @@ #include "main.h" #include "pilot.h" #include "log.h" +#include "opengl.h" #include "player.h" +#define POW2(x) ((x)*(x)) + #define KEY_PRESS 1. #define KEY_RELEASE -1. @@ -18,17 +21,199 @@ static Keybind** player_input; // Contains the players keybindings. // Name of each keybinding. const char* keybindNames[] = { "accel", "left", "right", "primary" }; +// Player stuff. 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. +// Pilot stuff for GUI. +extern Pilot** pilot_stack; +extern int pilots; + +// GUI crap. +// Need these offsets to render properly. -- Used in opengl.c +// -- Colors. +typedef struct { + double r, g, b, a; +} Color; +#define COLOR(x) (x).r, (x).g, (x).b, (x).a +Color cRadar_player = { .r = 0.4, .g = 0.8, .b = 0.9, .a = 1. }; +Color cRadar_neut = { .r = 0.8, .g = 0.8, .b = 0.8, .a = 1. }; +Color cShield = { .r = 0.2, .g = 0.2, .b = 0.8, .a = 1. }; +Color cArmor = { .r = 0.5, .g = 0.5, .b = 0.5, .a = 1. }; +Color cEnergy = { .r = 0.2, .g = 0.8, .b = 0.2, .a = 1. }; + +typedef enum { RADAR_RECT, RADAR_CIRCLE } RadarShape; + +typedef struct { + double w,h; // Dimensions. + RadarShape shape; + double res; // Resolution. +} Radar; + +typedef struct { + double w,h; +} Rect; + +typedef struct { + // graphics. + gl_texture* gfx_frame; + Radar radar; + Rect shield, armor, energy; + // Positions. + Vec2 pos_frame; + Vec2 pos_radar; + Vec2 pos_shield, pos_armor, pos_energy; +} GUI; + +GUI gui; // Le Gui! + +double gui_xoff = 0.; +double gui_yoff = 0.; + extern void pilot_render(Pilot* pilot); // Extern is in Pilot.* // Render the player. void player_render(void) { pilot_render(player); - // Render gui. + + // GUI! + // -- Frame. + gl_blitStatic(gui.gfx_frame, &gui.pos_frame); + // -- Radar. + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glTranslated(VX(gui.pos_radar) - gl_screen.w/2. + gui.radar.w/2., + VY(gui.pos_radar) - gl_screen.h/2. - gui.radar.h/2., 0.); + + glBegin(GL_POINTS); + // Player. + glColor4d(COLOR(cRadar_player)); + glVertex2d( 0., 2. ); + glVertex2d( 0., 1. ); + glVertex2d( 0., 0. ); + glVertex2d( 0., -1. ); + glVertex2d( 0., -2. ); + glVertex2d( 2., 0. ); + glVertex2d( 2., 0. ); + glVertex2d( -1., 0. ); + glVertex2d( -2., 0. ); + + int i; + double x, y, sx, sy; + Pilot* p; + switch(gui.radar.shape) { + case RADAR_RECT: + glEnd(); // Put end to those points. + for(i = 1; i < pilots; i++) { + p = pilot_stack[i]; + x = (p->solid->pos.x - player->solid->pos.x) / gui.radar.res; + y = (p->solid->pos.y - player->solid->pos.y) / gui.radar.res; + sx = PILOT_SIZE_APROX/2. * p->ship->gfx_space->sw / gui.radar.res; + sy = PILOT_SIZE_APROX/2. * p->ship->gfx_space->sh / gui.radar.res; + + if((ABS(x) > gui.radar.w / 2+sx) || (ABS(y) > gui.radar.h / 2. + sy)) + continue; // Pilot isn't in range. + + glBegin(GL_QUADS); + glColor4d(COLOR(cRadar_neut)); + glVertex2d(MAX(x-sx, -gui.radar.w/2.), MIN(y+sx, gui.radar.w/2.)); // top left. + glVertex2d(MIN(x+sx, gui.radar.w/2.), MIN(y+sy, gui.radar.h/2.)); // Top right. + glVertex2d(MAX(x+sx, gui.radar.w/2.), MAX(y-sy, -gui.radar.h/2.)); // Bottom right. + glVertex2d(MAX(x-sx, -gui.radar.w/2.), MIN(y-sy, -gui.radar.h/2.)); // Bottom left. + glEnd(); // The Quads. + } + case RADAR_CIRCLE: + for(i = 1; i < pilots; i++) { + p = pilot_stack[i]; + glColor4d(COLOR(cRadar_neut)); + glVertex2d((p->solid->pos.x - player->solid->pos.x) / gui.radar.res, + (p->solid->pos.y - player->solid->pos.y) / gui.radar.res); + } + glEnd(); + break; + } + glPopMatrix(); // GL_PROJECTION. + + // Health. + glBegin(GL_QUADS); // Shield. + glColor4d(COLOR(cShield)); + x = VX(gui.pos_shield) - gl_screen.w/2.; + y = VY(gui.pos_shield) - gl_screen.h/2.; + sx = player->shield / player->shield_max * gui.shield.w; + sy = gui.shield.h; + glVertex2d(x, y); + glVertex2d(x+sx, y); + glVertex2d(x+sx, y-sy); + glVertex2d(x, y-sy); + glEnd(); + + glBegin(GL_QUADS); // Armor. + glColor4d(COLOR(cArmor)); + x = VX(gui.pos_armor) - gl_screen.w/2.; + y = VY(gui.pos_armor) - gl_screen.h/2.; + sx = player->armor / player->armor_max * gui.armor.w; + sy = gui.armor.h; + glVertex2d(x, y); + glVertex2d(x+sx, y); + glVertex2d(x+sx, y-sy); + glVertex2d(x, y-sy); + glEnd(); + + glBegin(GL_QUADS); // Energy. + glColor4d(COLOR(cEnergy)); + x = VX(gui.pos_energy) - gl_screen.w/2.; + y = VY(gui.pos_energy) - gl_screen.h/2.; + sx = player->energy / player->energy_max * gui.energy.w; + sy = gui.energy.h; + glVertex2d(x, y); + glVertex2d(x+sx, y); + glVertex2d(x+sx, y-sy); + glVertex2d(x, y-sy); + glEnd(); +} + +// Init GUI. +int gui_init(void) { +// -- Frame. + gui.gfx_frame = gl_newImage("../gfx/gui/frame.png"); + vect_csetmin(&gui.pos_frame, + gl_screen.w - gui.gfx_frame->w, // x. + gl_screen.h - gui.gfx_frame->h); // y. + gui_xoff = -gui.gfx_frame->w/2.; // Offset is only horizontal and on the right side. + +// -- Radar. + gui.radar.res = 10.; + gui.radar.w = 128.; + gui.radar.h = 128.; + gui.radar.shape = RADAR_RECT; // RADAR_CIRCLE; + vect_csetmin(&gui.pos_radar, + VX(gui.pos_frame) + 11, // x + VY(gui.pos_frame) + gui.gfx_frame->h - 10); // y. + +// -- Bars. + gui.shield.w = gui.armor.w = gui.energy.w = 128; + gui.shield.h = gui.armor.h = gui.energy.h = 10; + vect_csetmin(&gui.pos_shield, + VX(gui.pos_frame) + 10, // x + VY(gui.pos_frame) + gui.gfx_frame->h - 201); // y. + + vect_csetmin(&gui.pos_armor, + VX(gui.pos_frame) + 10, // x + VY(gui.pos_frame) + gui.gfx_frame->h - 218); // y. + + vect_csetmin(&gui.pos_energy, + VX(gui.pos_frame) + 10, // x + VY(gui.pos_frame) + gui.gfx_frame->h - 236); // y. + + return 0; + +} + +// Free the GUI. +void gui_free(void) { + gl_freeTexture(gui.gfx_frame); } // Used in pilot.c diff --git a/src/player.h b/src/player.h index 9f23ed9..c98e3a1 100644 --- a/src/player.h +++ b/src/player.h @@ -6,6 +6,9 @@ extern Pilot* pilot; typedef enum { KEYBIND_NULL, KEYBIND_KEYBOARD, KEYBIND_JAXIS, KEYBIND_JBUTTON } KeybindType; +// Render. +int gui_init(void); +void gui_free(void); void player_render(void); int player_isFlag(unsigned int flag); diff --git a/src/ship.c b/src/ship.c index 1bdd616..0ec4df9 100644 --- a/src/ship.c +++ b/src/ship.c @@ -49,7 +49,7 @@ static Ship* ship_parse(xmlNodePtr parent) { if(strcmp((char*)node->name, "GFX")==0) { 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); + tmp->gfx_space = gl_newSprite(str, 6, 6); } else if(strcmp((char*)node->name, "class")==0) tmp->class = atoi((char*)node->children->content); @@ -121,7 +121,7 @@ static Ship* ship_parse(xmlNodePtr parent) { #define MELEMENT(o,s) if(o == 0) WARN("Ship '%s' missing '"s"' element", tmp->name) if(tmp->name == NULL) WARN("Ship '%s' missing 'name' tag", tmp->name); - if(tmp->gfx_ship == NULL) WARN("Ship '%s' missing 'GFX' element", tmp->name); + if(tmp->gfx_space == NULL) WARN("Ship '%s' missing 'GFX' element", tmp->name); MELEMENT(tmp->thrust, "thrust"); MELEMENT(tmp->turn, "turn"); MELEMENT(tmp->speed, "speed"); @@ -191,7 +191,7 @@ void ships_free(void) { so = so->next; free(sot); } - gl_freeTexture((ship_stack+i)->gfx_ship); + gl_freeTexture((ship_stack+i)->gfx_space); } free(ship_stack); ship_stack = NULL; diff --git a/src/ship.h b/src/ship.h index ec4b355..3ed5037 100644 --- a/src/ship.h +++ b/src/ship.h @@ -28,7 +28,7 @@ typedef struct { double thrust, turn, speed; // Graphics. - gl_texture* gfx_ship, *gfx_target; + gl_texture* gfx_space, *gfx_target; // Characteristics. int crew; diff --git a/src/weapon.c b/src/weapon.c index 0b79ce5..d849bc6 100644 --- a/src/weapon.c +++ b/src/weapon.c @@ -10,8 +10,6 @@ #include "pilot.h" #include "weapon.h" -#define SIZE_APROX 0.8 // Aproximation for circle collision detection. - // Some stuff from pilot. extern Pilot** pilot_stack; extern int pilots; @@ -94,8 +92,8 @@ static void weapon_update(Weapon* w, const double dt, WeaponLayer layer) { int i; for(i = 0; i < pilots; i++) { if((w->parent != pilot_stack[i]->id) && - (DIST(w->solid->pos, pilot_stack[i]->solid->pos) < (SIZE_APROX + - w->outfit->gfx_space->sw/2. + pilot_stack[i]->ship->gfx_ship->sw/2.))) { + (DIST(w->solid->pos, pilot_stack[i]->solid->pos) < (PILOT_SIZE_APROX * + w->outfit->gfx_space->sw/2. + pilot_stack[i]->ship->gfx_space->sw/2.))) { pilot_hit(pilot_stack[i], w->outfit->damage_shield, w->outfit->damage_armor); weapon_destroy(w, layer); return;