#include #include "main.h" #include "pilot.h" #include "log.h" #include "opengl.h" #include "pack.h" #include "xml.h" #include "player.h" #define XML_NODE_START 1 #define XML_NODE_TEXT 3 #define XML_GUI_ID "GUIs" // XML section identifier. #define XML_GUI_TAG "gui" #define GUI_DATA "../dat/gui.xml" #define GUI_GFX "../gfx/gui/" #define POW2(x) ((x)*(x)) #define GFX_GUI_FRAME "../gfx/gui/frame.png" #define GFX_GUI_TARG_PILOT "../gfx/gui/pilot.png" #define GFX_GUI_TARG_PLANET "../gfx/gui/planet.png" #define KEY_PRESS 1. #define KEY_RELEASE -1. // Keybind structure. typedef struct { char* name; // Keybinding name, taken from keybindNames[] KeybindType type; // type, defined in player.h. 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. // Name of each keybinding. const char* keybindNames[] = { "accel", "left", "right", "primary", "target", "target_nearest", "mapzoomin", "mapzoomout", "end" }; // Need to terminate in "end". // 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. static unsigned int player_target = PLAYER_ID; // Targetted pilot. // Pilot stuff for GUI. extern Pilot** pilot_stack; extern int pilots; // GUI crap. // -- Colors. // Standard colors. glColor cInert = { .r = 0.6, .g = 0.6, .b = 0.6, .a = 1. }; glColor cNeutral = { .r = 0.9, .g = 1.0, .b = 0.3, .a = 1. }; glColor cFriend = { .r = 0.0, .g = 1.0, .b = 0.0, .a = 1. }; glColor cHostile = { .r = 0.9, .g = 0.2, .b = 0.2, .a = 1. }; glColor cRadar_player = { .r = 0.4, .g = 0.8, .b = 0.4, .a = 1. }; glColor cRadar_targ = { .r = 0.0, .g = 0.7, .b = 1.0, .a = 1. }; glColor cRadar_weap = { .r = 0.8, .g = 0.2, .b = 0.2, .a = 1. }; // Bars. glColor cShield = { .r = 0.2, .g = 0.2, .b = 0.8, .a = 1. }; glColor cArmor = { .r = 0.5, .g = 0.5, .b = 0.5, .a = 1. }; glColor cEnergy = { .r = 0.2, .g = 0.8, .b = 0.2, .a = 1. }; typedef struct { double w,h; // Dimensions. RadarShape shape; double res; // Resolution. } Radar; // Radar res. #define RADAR_RES_MAX 100. #define RADAR_RES_MIN 10. #define RADAR_RES_INTERVAL 10. #define RADAR_RES_DEFAULT 40. typedef struct { double w,h; } Rect; typedef struct { // Graphics. gl_font smallFont; gl_texture* gfx_frame; gl_texture* gfx_targetPilot, *gfx_targetPlanet; Radar radar; Rect shield, armor, energy; // Positions. Vec2 pos_frame; Vec2 pos_radar; Vec2 pos_shield, pos_armor, pos_energy; Vec2 pos_target, pos_target_health, pos_target_name, pos_target_faction; Vec2 pos_msg; } GUI; GUI gui; // Le Gui! double gui_xoff = 0.; double gui_yoff = 0.; // Messages. #define MSG_SIZE_MAX 80 int msg_timeout = 5000; int msg_max = 5; // Max messages on screen. typedef struct { char str[MSG_SIZE_MAX]; unsigned int t; } Msg; static Msg* msg_stack; // External. extern void pilot_render(const Pilot* pilot); // Extern is in Pilot.* extern void weapon_minimap(const double res, const double w, const double h, const RadarShape shape); // weapon.c extern void planets_minimap(const double res, const double w, const double h, const RadarShape shape); // space.c // Internal. static void rect_parse(const xmlNodePtr parent, double* x, double* y, double* w, double* h); static int gui_parse(const xmlNodePtr parent, const char* name); static void gui_renderPilot(const Pilot* p); static void gui_renderBar(const glColor* c, const Vec2* p, const Rect* r, const double w); void player_message(const char* fmt, ...) { va_list ap; int i; if(fmt == NULL) return; // Message not valid. // Copy old messages back. for(i = 1; i < msg_max; i++) if(msg_stack[msg_max-i-1].str[0] != '\0') { strcpy(msg_stack[msg_max-i].str, msg_stack[msg_max-i-1].str); msg_stack[msg_max-i].t = msg_stack[msg_max-i-1].t; } // Add the new one. va_start(ap, fmt); vsprintf(msg_stack[0].str, fmt, ap); va_end(ap); msg_stack[0].t = SDL_GetTicks() + msg_timeout; } // Render the player. void player_render(void) { int i, j; Pilot* p; Vec2 v; glColor* c; // Render the player target graphics. if(player_target != PLAYER_ID) { p = pilot_get(player_target); if(pilot_isFlag(p, PILOT_HOSTILE)) c = &cHostile; else c = &cNeutral; vect_csetmin(&v, VX(p->solid->pos) - p->ship->gfx_space->sw * PILOT_SIZE_APROX/2., VY(p->solid->pos) + p->ship->gfx_space->sh * PILOT_SIZE_APROX/2.); gl_blitSprite(gui.gfx_targetPilot, &v, 0, 0, c); // Top left. VX(v) += p->ship->gfx_space->sw * PILOT_SIZE_APROX; gl_blitSprite(gui.gfx_targetPilot, &v, 1, 0, c); // Top right. VY(v) -= p->ship->gfx_space->sh * PILOT_SIZE_APROX; gl_blitSprite(gui.gfx_targetPilot, &v, 1, 1, c); // Bottom right. VX(v) -= p->ship->gfx_space->sw * PILOT_SIZE_APROX; gl_blitSprite(gui.gfx_targetPilot, &v, 0, 1, c); // Bottom left. } // Render the player. pilot_render(player); // GUI! // -- Frame. gl_blitStatic(gui.gfx_frame, &gui.pos_frame, NULL); // -- Radar. glMatrixMode(GL_PROJECTION); glPushMatrix(); if(gui.radar.shape == RADAR_RECT) 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.); else if(gui.radar.shape == RADAR_CIRCLE) glTranslated(VX(gui.pos_radar) - gl_screen.w/2., VY(gui.pos_radar) - gl_screen.h/2., 0.); // Planets. COLOR(cFriend); planets_minimap(gui.radar.res, gui.radar.w, gui.radar.h, gui.radar.shape); // Weapons. glBegin(GL_POINTS); COLOR(cRadar_weap); weapon_minimap(gui.radar.res, gui.radar.w, gui.radar.h, gui.radar.shape); glEnd(); // Render the pilots. for(j = 0, i = 1; i < pilots; i++) { // Skip the player. if(pilot_stack[i]->id == player_target) j = i; else gui_renderPilot(pilot_stack[i]); } // Render the targetted pilot. if(j != 0) gui_renderPilot(pilot_stack[j]); // Player. glBegin(GL_POINTS); // Player. -- Drawn last. COLOR(cRadar_player); glVertex2d( 0., 2. ); // We represent the player with a small '+' glVertex2d( 0., 1. ); glVertex2d( 0., 0. ); glVertex2d( 0., -1. ); glVertex2d( 0., -2. ); glVertex2d( 2., 0. ); glVertex2d( 1., 0. ); glVertex2d( -1., 0. ); glVertex2d( -2., 0. ); glEnd(); glPopMatrix(); // GL_PROJECTION. // Health. gui_renderBar(&cShield, &gui.pos_shield, &gui.shield, player->shield / player->shield_max); gui_renderBar(&cArmor, &gui.pos_armor, &gui.armor, player->armor / player->armor_max); gui_renderBar(&cEnergy, &gui.pos_energy, &gui.energy, player->energy / player->energy_max); // Target. if(player_target != PLAYER_ID) { p = pilot_get(player_target); gl_blitStatic(p->ship->gfx_target, &gui.pos_target, NULL); // Target name. gl_print(NULL, &gui.pos_target_name, NULL, "%s", p->name); gl_print(&gui.smallFont, &gui.pos_target_faction, NULL, "%s", p->faction->name); // Target status. if(p->armor < p->armor_max * PILOT_DISABLED) // Disable the pilot. gl_print(&gui.smallFont, &gui.pos_target_health, NULL, "Disabled"); else if(p->shield > p->shield_max / 100.) // On shields. gl_print(&gui.smallFont, &gui.pos_target_health, NULL, "%s: %.0f%%", "Shield", p->shield/p->shield_max*100.); else // On armor. gl_print(&gui.smallFont, &gui.pos_target_health, NULL, "%s: %.0f%%", "Armor", p->armor/p->armor_max*100.); } // Messages. VX(v) = VX(gui.pos_msg); VY(v) = VY(gui.pos_msg) + (double)(gl_defFont.h*msg_max)*1.2; for(i = 0; i < msg_max; i++) { VY(v) -= (double)gl_defFont.h*1.2; if(msg_stack[msg_max-i-1].str[0] != '\0') { if(msg_stack[msg_max-i-1].t < SDL_GetTicks()) msg_stack[msg_max-i-1].str[0] = '\0'; else gl_print(NULL, &v, NULL, "%s", msg_stack[msg_max-i-1].str); } } } // Renders a pilot. static void gui_renderPilot(const Pilot* p) { int x, y, sx, sy; double w, h; 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(sx < 1.) sx = 1.; if(sy < 1.) sy = 1.; if(((gui.radar.shape == RADAR_RECT) && ((ABS(x) > gui.radar.w/2.+sx) || (ABS(y) > gui.radar.h/2.+sy))) || ((gui.radar.shape == RADAR_CIRCLE) && ((x*x + y*y) > (int)(gui.radar.w*gui.radar.w)))) return; // Pilot isn't in range. if(gui.radar.shape == RADAR_RECT) { w = gui.radar.w/2.; h = gui.radar.h/2.; } else if(gui.radar.shape == RADAR_CIRCLE) { w = gui.radar.w; h = gui.radar.w; } glBegin(GL_QUADS); // Colors. if(p->id == player_target) COLOR(cRadar_targ); else if(pilot_isFlag(p, PILOT_HOSTILE)) COLOR(cHostile); else COLOR(cNeutral); // Image. glVertex2d(MAX(x-sx, -w), MIN(y+sy, h)); // Top left. glVertex2d(MIN(x+sx, w), MIN(y+sy, h)); // Top right. glVertex2d(MIN(x+sx, w), MAX(y-sy, -h)); // Bottom right. glVertex2d(MAX(x-sx, -w), MAX(y-sy, -h)); // Bottom left. glEnd(); } // Render a bar. static void gui_renderBar(const glColor* c, const Vec2* p, const Rect* r, const double w) { int x, y, sx, sy; glBegin(GL_QUADS); COLOR(*c); x = VX(*p) - gl_screen.w/2.; y = VY(*p) - gl_screen.h/2.; sx = w * r->w; sy = r->h; glVertex2d(x, y); glVertex2d(x+sx, y); glVertex2d(x+sx, y-sy); glVertex2d(x, y-sy); glEnd(); } // Init GUI. int gui_init(void) { // Font. gl_fontInit(&gui.smallFont, NULL, 10); // -- Radar. gui.radar.res = RADAR_RES_DEFAULT; // -- messages. vect_csetmin(&gui.pos_msg, 20,30); msg_stack = calloc(msg_max, sizeof(Msg)); return 0; } // Attempts to load the actual gui. int gui_load(const char* name) { uint32_t bufsize; char* buf = pack_readfile(DATA, GUI_DATA, &bufsize); char* tmp; int found = 0; xmlNodePtr node; xmlDocPtr doc = xmlParseMemory(buf, bufsize); node = doc->xmlChildrenNode; if(!xml_isNode(node, XML_GUI_ID)) { ERR("Malformed '"GUI_DATA"' file: missing root element '"XML_GUI_ID"'"); return -1; } node = node->xmlChildrenNode; // First system node. if(node == NULL) { ERR("Malformed '"GUI_DATA"' file: does not contain elements"); return -1; } do { if(xml_isNode(node, XML_GUI_TAG)) { tmp = xml_nodeProp(node, "name"); // Mallocs. // Is this the gui we are looking for? if(strcmp(tmp, name)==0) { found = 1; // Parse the xml node. if(gui_parse(node, name)) WARN("Trouble loading GUI '%s'", name); free(tmp); break; } free(tmp); } } while((node = node->next)); xmlFreeDoc(doc); free(buf); xmlCleanupParser(); if(!found) { WARN("GUI '%s' not found in '"GUI_DATA"'",name); return -1; } return 0; } static void rect_parse(const xmlNodePtr parent, double* x, double* y, double* w, double* h) { xmlNodePtr cur; int param; param = 0; cur = parent->children; do { if(xml_isNode(cur, "x")) { if(x != NULL) { *x = (double)atoi((char*)cur->children->content); param |= (1<<0); } else WARN("Extra parameter 'x' found for GUI node '%s'", parent->name); } else if(xml_isNode(cur, "y")) { if(y != NULL) { *y = (double)atoi((char*)cur->children->content); param |= (1<<1); } else WARN("Extra parameter 'y' found for GUI node '%s'", parent->name); } else if(xml_isNode(cur, "w")) { if(w != NULL) { *w = (double)atoi((char*)cur->children->content); param |= (1<<2); } else WARN("Extra parameter 'w' found for GUI node '%s'", parent->name); } else if(xml_isNode(cur, "h")) { if(h != NULL) { *h = (double)atoi((char*)cur->children->content); param |= (1<<3); } else WARN("Extra parameter 'h' found for GUI node '%s'", parent->name); } } while((cur = cur->next)); // Check to see if we got everything we asked for. if(x && !(param & (1<<0))) WARN("Missing parameter 'x' for GUI node '%s'", parent->name); else if(y && !(param & (1<<1))) WARN("Missing parameter 'y' for GUI node '%s'", parent->name); else if(w && !(param & (1<<2))) WARN("Missing parameter 'w' for GUI node '%s'", parent->name); else if(h && !(param & (1<<3))) WARN("Missing parameter 'h' for GUI node '%s'", parent->name); } // Parse a gui node. static int gui_parse(const xmlNodePtr parent, const char* name) { xmlNodePtr cur, node; double x, y; char* tmp, *tmp2; // Gfx. // Set a property and not a node because it must be loaded first. tmp2 = xml_nodeProp(parent, "gfx"); if(tmp2 == NULL) { ERR("GUI '%s' has no gfx property", name); return -1; } // Load gfx. tmp = malloc((strlen(tmp2)+strlen(GUI_GFX)+12) * sizeof(char)); // Frame. snprintf(tmp, strlen(tmp2)+strlen(GUI_GFX)+5, GUI_GFX"%s.png", tmp2); gui.gfx_frame = gl_newImage(tmp); // Pilot. snprintf(tmp, strlen(tmp2)+strlen(GUI_GFX)+11, GUI_GFX"%s_pilot.png", tmp2); gui.gfx_targetPilot = gl_newSprite(tmp, 2, 2); // Planet. snprintf(tmp, strlen(tmp2)+strlen(GUI_GFX)+12, GUI_GFX"%s_planet.png", tmp2); gui.gfx_targetPlanet = gl_newSprite(tmp, 2, 2); free(tmp); free(tmp2); // Frame (based on gfx). vect_csetmin(&gui.pos_frame, gl_screen.w - gui.gfx_frame->w, // x. gl_screen.h - gui.gfx_frame->h); // h. // Let's parse the data now. node = parent->children; do { // Offset. if(xml_isNode(node, "offset")) { rect_parse(node, &x, &y, NULL, NULL); gui_xoff = x; gui_yoff = y; } else if(xml_isNode(node, "radar")) { tmp = xml_nodeProp(node,"type"); // Make sure type is valid. if(strcmp(tmp, "rectangle")==0) gui.radar.shape = RADAR_RECT; else if(strcmp(tmp, "circle")==0) gui.radar.shape = RADAR_CIRCLE; else { WARN("Radar for GUI '%s' is missing 'type' tag or has invalid 'type' tag", name); gui.radar.shape = RADAR_RECT; } free(tmp); // Load the appropriate measurements. if(gui.radar.shape == RADAR_RECT) rect_parse(node, &x, &y, &gui.radar.w, &gui.radar.h); else if(gui.radar.shape == RADAR_CIRCLE) rect_parse(node, &x, &y, &gui.radar.w, NULL); vect_csetmin(&gui.pos_radar, VX(gui.pos_frame) + x, VY(gui.pos_frame) + gui.gfx_frame->h - y); } // Health bars. else if(xml_isNode(node, "health")) { cur = node->children; do { if(xml_isNode(cur, "shield")) { rect_parse(cur, &x, &y, &gui.shield.w, &gui.shield.h); vect_csetmin(&gui.pos_shield, VX(gui.pos_frame) + x, VY(gui.pos_frame) + gui.gfx_frame->h - y); } if(xml_isNode(cur, "armor")) { rect_parse(cur, &x, &y, &gui.armor.w, &gui.armor.h); vect_csetmin(&gui.pos_armor, VX(gui.pos_frame) + x, VY(gui.pos_frame) + gui.gfx_frame->h - y); } if(xml_isNode(cur, "energy")) { rect_parse(cur, &x, &y, &gui.energy.w, &gui.energy.h); vect_csetmin(&gui.pos_energy, VX(gui.pos_frame) + x, VY(gui.pos_frame) + gui.gfx_frame->h - y); } } while((cur = cur->next)); } // Target. else if(xml_isNode(node, "target")) { cur = node->children; do { if(xml_isNode(cur, "gfx")) { rect_parse(cur, &x, &y, NULL, NULL); vect_csetmin(&gui.pos_target, VX(gui.pos_frame) + x, VY(gui.pos_frame) + gui.gfx_frame->h - y - SHIP_TARGET_H); } if(xml_isNode(cur, "name")) { rect_parse(cur, &x, &y, NULL, NULL); vect_csetmin(&gui.pos_target_name, VX(gui.pos_frame) + x, VY(gui.pos_frame) + gui.gfx_frame->h - y - gl_defFont.h); } if(xml_isNode(cur, "faction")) { rect_parse(cur, &x, &y, NULL, NULL); vect_csetmin(&gui.pos_target_faction, VX(gui.pos_frame) + x, VY(gui.pos_frame) + gui.gfx_frame->h - y - gui.smallFont.h); } if(xml_isNode(cur, "health")) { rect_parse(cur, &x, &y, NULL, NULL); vect_csetmin(&gui.pos_target_health, VX(gui.pos_frame) + x, VY(gui.pos_frame) + gui.gfx_frame->h - y - gui.smallFont.h); } } while((cur = cur->next)); } } while((node = node->next)); return 0; } // Free the GUI. void gui_free(void) { gl_freeFont(&gui.smallFont); gl_freeTexture(gui.gfx_frame); gl_freeTexture(gui.gfx_targetPilot); gl_freeTexture(gui.gfx_targetPlanet); free(msg_stack); } // Used in pilot.c // Basically uses keyboard input instead of AI input. void player_think(Pilot* player) { player->solid->dir_vel = 0.; 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); } // ================ // INPUT! // ================ // Set the default input keys. void input_setDefault(void) { 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); input_setKeybind("target", KEYBIND_KEYBOARD, SDLK_TAB, 0); input_setKeybind("target_nearest", KEYBIND_KEYBOARD, SDLK_r, 0); input_setKeybind("mapzoomin", KEYBIND_KEYBOARD, SDLK_UP, 0); input_setKeybind("mapzoomout", KEYBIND_KEYBOARD, SDLK_DOWN, 0); } // Initialization/exit functions (does not assign keys). void input_init(void) { Keybind* tmp; int i; for(i = 0; strcmp(keybindNames[i], "end"); i++); // Get number of bindings. player_input = malloc(i*sizeof(Keybind*)); // Create a null keybinding for each. for(i = 0; strcmp(keybindNames[i], "end"); i++) { tmp = MALLOC_L(Keybind); tmp->name = (char*)keybindNames[i]; tmp->type = KEYBIND_NULL; tmp->key = 0; tmp->reverse = 1.; player_input[i] = tmp; } } void input_exit(void) { int i; for(i = 0; strcmp(keybindNames[i], "end"); i++) free(player_input[i]); free(player_input); } // Binds key of type [type] to action keybind. void input_setKeybind(char* keybind, KeybindType type, int key, int reverse) { int i; for(i = 0; strcmp(keybindNames[i], "end"); i++) if(strcmp(keybind, player_input[i]->name)==0) { player_input[i]->type = type; player_input[i]->key = key; player_input[i]->reverse = reverse ? -1. : 1.; return; } WARN("Unable to set keybind '%s', That command does not exist.", keybind); } // == Run input method. ================================================ // keynum : Index of the player_input keybind. // value : Value of keypress (defined above). // abs : Whether or not it's an abs value (For those pesky joysticks. // ===================================================================== static void input_key(int keynum, double value, int abs) { if(strcmp(player_input[keynum]->name, "accel")==0) { if(abs)player_acc = value; else player_acc += value; } else if(strcmp(player_input[keynum]->name, "left")==0) { if(abs)player_turn = -value; else player_turn -= value; } else if(strcmp(player_input[keynum]->name, "right")==0) { 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; } // Targetting. else if(strcmp(player_input[keynum]->name, "target")==0) { if(value == KEY_PRESS) player_target = pilot_getNext(player_target); } else if(strcmp(player_input[keynum]->name, "target_nearest")==0) { if(value == KEY_PRESS) player_target = pilot_getHostile(); } // Zoom in. else if(strcmp(player_input[keynum]->name, "mapzoomin")==0) { if(value == KEY_PRESS && gui.radar.res < RADAR_RES_MAX) gui.radar.res += RADAR_RES_INTERVAL; } // Zoom out. else if(strcmp(player_input[keynum]->name, "mapzoomout")==0) { if(value == KEY_PRESS && gui.radar.res > RADAR_RES_MIN) gui.radar.res -= RADAR_RES_INTERVAL; } //Make sure values are sane. player_acc = ABS(player_acc); if(player_acc > 1.) player_acc = 1.; if(player_turn > 1.) player_turn = 1.; else if(player_turn < -1.) player_turn = -1.; } // --Events-- 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(const unsigned int axis, const int value) { int i; for(i = 0; strcmp(keybindNames[i], "end"); i++) if(player_input[i]->type == KEYBIND_JAXIS && player_input[i]->key == axis) { input_key(i, -(player_input[i]->reverse) * (double)value / 32767., 1); return; } } // Joystick button down. static void input_joydown(const unsigned int button) { int i; for(i = 0; strcmp(keybindNames[i], "end");i++) if(player_input[i]->type == KEYBIND_JBUTTON && player_input[i]->key == button) { input_key(i, KEY_RELEASE, 0); return; } } // Joystick button up. static void input_joyup(const unsigned int button) { int i; for(i = 0; strcmp(keybindNames[i], "end"); i++) if(player_input[i]->type == KEYBIND_JBUTTON && player_input[i]->key == button) { input_key(i, KEY_RELEASE, 0); return; } } // Keyboard. // Key down. static void input_keydown(SDLKey key) { int i; for(i = 0; strcmp(keybindNames[i], "end"); i++) if(player_input[i]->type == KEYBIND_KEYBOARD && player_input[i]->key == key) { input_key(i, KEY_PRESS, 0); return; } // Fire Escape. SDL_Event quit; if(key == SDLK_ESCAPE) { quit.type = SDL_QUIT; SDL_PushEvent(&quit); } } // Key up. static void input_keyup(SDLKey key) { int i; for(i = 0; strcmp(keybindNames[i], "end"); i++) if(player_input[i]->type == KEYBIND_KEYBOARD && player_input[i]->key == key) { input_key(i, KEY_RELEASE, 0); return; } } // Global input. // Just seperates the event types. void input_handle(SDL_Event* event) { switch(event->type) { case SDL_JOYAXISMOTION: input_joyaxis(event->jaxis.axis, event->jaxis.value); break; case SDL_JOYBUTTONDOWN: input_joydown(event->jbutton.button); break; case SDL_JOYBUTTONUP: input_joyup(event->jbutton.button); break; case SDL_KEYDOWN: input_keydown(event->key.keysym.sym); break; case SDL_KEYUP: input_keyup(event->key.keysym.sym); break; } }