#include #include #include "toolkit.h" #include "dialogue.h" #include "log.h" #include "lephisto.h" #include "pilot.h" #include "space.h" #include "player.h" #include "mission.h" #include "ltime.h" #include "save.h" #include "land.h" #include "rng.h" #include "nebulae.h" #include "menu.h" #define MAIN_WIDTH 130 #define MAIN_HEIGHT 250 #define MENU_WIDTH 130 #define MENU_HEIGHT 200 #define INFO_WIDTH 360 #define INFO_HEIGHT 280 #define OUTFITS_WIDTH 400 #define OUTFITS_HEIGHT 200 #define CARGO_WIDTH 300 #define CARGO_HEIGHT 300 #define MISSIONS_WIDTH 600 #define MISSIONS_HEIGHT 400 #define DEATH_WIDTH 130 #define DEATH_HEIGHT 150 #define BUTTON_WIDTH 90 #define BUTTON_HEIGHT 30 #define menu_Open(f) (menu_open |= (f)) #define menu_Close(f) (menu_open ^= (f)) int menu_open = 0; /* Main menu. */ void menu_main_close(void); static void menu_main_load(char* str); static void menu_main_new(char* str); static void menu_main_exit(char* str); /* Small menu. */ static void menu_small_close(char* str); static void edit_options(char* str); static void menu_small_exit(char* str); static void exit_game(void); /* Information menu. */ static void menu_info_close(char* str); /* Outfits submenu. */ static void info_outfits_menu(char* str); /* Cargo submenu. */ static void info_cargo_menu(char* str); static void cargo_update(char* str); static void cargo_jettison(char* str); /* Mission submenu. */ static void info_missions_menu(char* str); static void mission_menu_abort(char* str); static void mission_menu_genList(int first); static void mission_menu_update(char* str); /* Death menu. */ static void menu_death_main(char* str); /* Generic. */ static void menu_generic_close(char* str); void menu_main(void) { unsigned int bwid, wid; glTexture* tex; tex = gl_newImage("../gfx/saracraft_logo1.png"); nebu_prep(300., 0.); /* Needed for nebuale to not spaz out. */ /* Create background image window. */ bwid = window_create("BG", -1, -1, SCREEN_W, SCREEN_H); window_addRect(bwid, 0, 0, SCREEN_W, SCREEN_H, "rctBG", &cBlack, 0); window_addCust(bwid, 0, 0, SCREEN_W, SCREEN_H, "cstBG", 0, (void(*)(double, double, double, double))nebu_render, NULL); window_addImage(bwid, (SCREEN_W-tex->sw)/2., -1, "imgLogo", tex, 0); window_addText(bwid, 0., 50., SCREEN_W, 30., 1, "txtBG", NULL, &cWhite, lephisto_version()); /* Create menu window. */ wid = window_create("Main Menu", -1, -1, MAIN_WIDTH, MAIN_HEIGHT); window_addButton(wid, 20, 20 + (BUTTON_HEIGHT+20)*3, BUTTON_WIDTH, BUTTON_HEIGHT, "btnLoad", "Load Game", menu_main_load); window_addButton(wid, 20, 20 + (BUTTON_HEIGHT+20)*2, BUTTON_WIDTH, BUTTON_HEIGHT, "btnNew", "New Game", menu_main_new); window_addButton(wid, 20, 20 + (BUTTON_HEIGHT+20), BUTTON_WIDTH, BUTTON_HEIGHT, "btnOptions", "Options", (void(*)(char*)) edit_options); window_addButton(wid, 20, 20, BUTTON_WIDTH, BUTTON_HEIGHT, "btnExit", "Exit", menu_main_exit); menu_Open(MENU_MAIN); } void menu_main_close(void) { window_destroy(window_get("Main Menu")); gl_freeTexture(window_getImage(window_get("BG"), "imgLogo")); window_destroy(window_get("BG")); menu_Close(MENU_MAIN); } static void menu_main_load(char* str) { (void)str; load_game_menu(); } static void menu_main_new(char* str) { (void)str; menu_main_close(); player_new(); } static void menu_main_exit(char* str) { (void)str; unsigned int wid; wid = window_get("BG"); /* * Ugly hack to prevent player.c from segfaulting due to the fact * that game will attempt to render while waiting for the quit event * pushed by exit_game() to be handled without actually having a player * nor anything of the likes (nor toolkit to stop rendering) while not * leaking any texture. */ gl_freeTexture(window_getImage(wid, "imgLogo")); window_modifyImage(wid, "imgLogo", NULL); exit_game(); } /* Ze ingame menu. */ /* Small ingame menu. */ void menu_small(void) { if((player == NULL) || player_isFlag(PLAYER_DESTROYED) || pilot_isFlag(player, PILOT_DEAD) || (menu_isOpen(MENU_MAIN) || menu_isOpen(MENU_SMALL) || menu_isOpen(MENU_DEATH))) return; /* It's already open.. */ unsigned int wid; wid = window_create("Menu", -1, -1, MENU_WIDTH, MENU_HEIGHT); window_setCancel(wid, menu_small_close); window_addButton(wid, 20, 20 + BUTTON_HEIGHT*2 + 20*2, BUTTON_WIDTH, BUTTON_HEIGHT, "btnResume", "Resume", menu_small_close); window_addButton(wid, 20, 20 + BUTTON_HEIGHT + 20, BUTTON_WIDTH, BUTTON_HEIGHT, "btnOptions", "Options", (void(*)(char*))edit_options); window_addButton(wid, 20, 20, BUTTON_WIDTH, BUTTON_HEIGHT, "btnExit", "Exit", menu_small_exit); menu_Open(MENU_SMALL); } static void menu_small_close(char* str) { (void)str; window_destroy(window_get("Menu")); menu_Close(MENU_SMALL); } static void menu_small_exit(char* str) { (void)str; window_destroy(window_get("Menu")); menu_Close(MENU_SMALL); menu_main(); } /* Edit the options. */ static void edit_options(char* str) { (void)str; /* @todo Make options menu */ } /* Exit the game. */ static void exit_game(void) { /* If landed we must save anyways. */ if(landed) { /* Increment time to match takeoff. */ ltime_inc(RNG(2*LTIME_UNIT_LENGTH, 3*LTIME_UNIT_LENGTH)); save_all(); } SDL_Event quit; quit.type = SDL_QUIT; SDL_PushEvent(&quit); } /* Info menu. */ void menu_info(void) { if(menu_isOpen(MENU_INFO)) return; char str[128]; char* lt; unsigned int wid; wid = window_create("Info", -1, -1, INFO_WIDTH, INFO_HEIGHT); /* Pilot generics. */ lt = ltime_pretty(ltime_get()); window_addText(wid, 20, 20, 120, INFO_HEIGHT-60, 0, "txtDPilot", &gl_smallFont, &cDConsole, "Pilot:\n" "Date:\n" "Combat\n" " Rating:" "\n" "Ship:\n" "Fuel:\n"); snprintf(str, 128, "%s\n" "%s\n" "\n" "%s\n" "\n" "%s\n" "%d %d jumps)", player_name, lt, player_rating(), player->name, (int)player->fuel, pilot_getJumps(player)); window_addText(wid, 80, 20, INFO_WIDTH-120-BUTTON_WIDTH, INFO_HEIGHT-60, 0, "txtPilot", &gl_smallFont, &cBlack, str); free(lt); /* Menu. */ window_addButton(wid, -20, (20 + BUTTON_HEIGHT)*4 + 20, BUTTON_WIDTH, BUTTON_HEIGHT, player->ship->name, "Ship", ship_view); window_addButton(wid, -20, (20 + BUTTON_HEIGHT)*3 + 20, BUTTON_WIDTH, BUTTON_HEIGHT, "btnOutfits", "Outfits", info_outfits_menu); window_addButton(wid, -20, (20 + BUTTON_HEIGHT)*2 + 20, BUTTON_WIDTH, BUTTON_HEIGHT, "btnCargo", "Cargo", info_cargo_menu); window_addButton(wid, -20, 20 + BUTTON_HEIGHT + 20, BUTTON_WIDTH, BUTTON_HEIGHT, "btnMissions", "Missions", info_missions_menu); window_addButton(wid, -20, 20, BUTTON_WIDTH, BUTTON_HEIGHT, "btnClose", "Close", menu_info_close); menu_Open(MENU_INFO); } static void menu_info_close(char* str) { if(strcmp(str, "btnClose")==0) window_destroy(window_get("Info")); menu_Close(MENU_INFO); } static void info_outfits_menu(char* str) { (void) str; char* buf; unsigned int wid; /* Create the window. */ wid = window_create("Outfits", -1, -1, OUTFITS_WIDTH, OUTFITS_HEIGHT); /* Text. */ window_addText(wid, 20, -40, 100, OUTFITS_HEIGHT-40, 0, "txtLabel", &gl_smallFont, &cDConsole, "Ship Outfits:"); buf = pilot_getOutfits(player); window_addText(wid, 20, -45-gl_smallFont.h, OUTFITS_WIDTH-40, OUTFITS_HEIGHT-60, 0, "txtOutfits", &gl_smallFont, &cBlack, buf); free(buf); /* Buttons. */ window_addButton(wid, -20, 20, BUTTON_WIDTH, BUTTON_HEIGHT, "closeOutfits", "Close", menu_generic_close); } /* Show the players cargo. */ static void info_cargo_menu(char* str) { (void)str; unsigned int wid; char** buf; int nbuf; int i; /* Create the window. */ wid = window_create("Cargo", -1, -1, CARGO_WIDTH, CARGO_HEIGHT); /* Buttons. */ window_addButton(wid, -20, 20, BUTTON_WIDTH, BUTTON_HEIGHT, "closeCargo", "Back", menu_generic_close); window_addButton(wid, -40 - BUTTON_WIDTH, 20, BUTTON_WIDTH, BUTTON_HEIGHT, "btnJettisonCargo", "Jettison", cargo_jettison); window_disableButton(wid, "btnJettisonCargo"); /* List. */ if(player->ncommodities == 0) { /* No cargo. */ buf = malloc(sizeof(char*)); buf[0] = strdup("None"); nbuf = 1; } else { /* List the players cargo. */ buf = malloc(sizeof(char*)*player->ncommodities); for(i = 0; i < player->ncommodities; i++) { buf[i] = malloc(sizeof(char)*128); snprintf(buf[i], 128, "%s%s %d", player->commodities[i].commodity->name, (player->commodities[i].id != 0) ? "*" : "", player->commodities[i].quantity); } nbuf = player->ncommodities; } window_addList(wid, 20, -40, CARGO_WIDTH - 40, CARGO_HEIGHT - BUTTON_HEIGHT - 80, "lstCargo", buf, nbuf, 0, cargo_update); cargo_update(NULL); } static void cargo_update(char* str) { (void)str; unsigned int wid; int pos; if(player->ncommodities == 0) return; /* No cargo. */ wid = window_get("Cargo"); pos = toolkit_getListPos(wid, "lstCargo"); /* Can jettison all but mission cargo when not landed. */ if(landed || (player->commodities[pos].id != 0)) window_disableButton(wid, "btnJettisonCargo"); else window_enableButton(wid, "btnJettisonCargo"); } static void cargo_jettison(char* str) { (void)str; unsigned int wid; int pos; if(player->ncommodities == 0) return; /* No cargo, redundant check. */ wid = window_get("Cargo"); pos = toolkit_getListPos(wid, "lstCargo"); /* Remove the cargo. */ commodity_Jettison(player->id, player->commodities[pos].commodity, player->commodities[pos].quantity); pilot_rmCargo(player, player->commodities[pos].commodity, player->commodities[pos].quantity); /* We reopen the menu to recreate the list now. */ menu_generic_close("closeCargo"); info_cargo_menu(NULL); } /* Show the player's active missions. */ static void info_missions_menu(char* str) { (void)str; unsigned int wid; wid = window_create("Missions", -1, -1, MISSIONS_WIDTH, MISSIONS_HEIGHT); /* Buttons. */ window_addButton(wid, -20, 20, BUTTON_WIDTH, BUTTON_HEIGHT, "closeMissions", "Back", menu_generic_close); window_addButton(wid, -20, 40+BUTTON_HEIGHT, BUTTON_WIDTH, BUTTON_HEIGHT, "btnAbortMission", "Abort", mission_menu_abort); /* Text. */ window_addText(wid, 300+40, -60, 200, 40, 0, "txtSReward", &gl_smallFont, &cDConsole, "Reward:"); window_addText(wid, 300+100, -60, 140, 40, 0, "txtReward", &gl_smallFont, &cBlack, NULL); window_addText(wid, 300+40, -100, 200, MISSIONS_HEIGHT - BUTTON_WIDTH - 120, 0, "txtDesc", &gl_smallFont, &cBlack, NULL); /* List. */ mission_menu_genList(1); } static void mission_menu_genList(int first) { int i, j; char** misn_names; unsigned int wid; wid = window_get("Missions"); if(!first) window_destroyWidget(wid, "lstMission"); /* List. */ misn_names = malloc(sizeof(char*) * MISSION_MAX); j = 0; for(i = 0; i < MISSION_MAX; i++) if(player_missions[i].id != 0) misn_names[j++] = strdup(player_missions[i].title); if(j == 0) { /* No missions. */ free(misn_names); misn_names = malloc(sizeof(char*)); misn_names[0] = strdup("No Missions"); j = 1; } window_addList(wid, 20, -40, 300, MISSIONS_HEIGHT-60, "lstMission", misn_names, j, 0, mission_menu_update); mission_menu_update(NULL); } static void mission_menu_update(char* str) { char* active_misn; Mission* misn; unsigned int wid; (void)str; wid = window_get("Missions"); active_misn = toolkit_getList(wid, "lstMission"); if(strcmp(active_misn, "No Missions")==0) { window_modifyText(wid, "txtReward", "None"); window_modifyText(wid, "txtDesc", "You currently have no active missions."); window_disableButton(wid, "btnAbortMission"); return; } misn = &player_missions[toolkit_getListPos(wid, "lstMission")]; window_modifyText(wid, "txtReward", misn->reward); window_modifyText(wid, "txtDesc", misn->desc); window_enableButton(wid, "btnAbortMission"); } static void mission_menu_abort(char* str) { (void)str; char* selected_misn; int pos; unsigned int wid; Mission* misn; wid = window_get("Missions"); selected_misn = toolkit_getList(wid, "lstMission"); if(dialogue_YesNo("Abort Mission", "Are you sure you want to abort this mission?")) { pos = toolkit_getListPos(wid, "lstMission"); misn = &player_missions[pos]; mission_cleanup(misn); memmove(misn, &player_missions[pos+1], sizeof(Mission) * (MISSION_MAX-pos-1)); mission_menu_genList(0); } } /* Pilot dead. */ void menu_death(void) { unsigned int wid; wid = window_create("Death", -1, -1, DEATH_WIDTH, DEATH_HEIGHT); window_addButton(wid, 20, 20 + (BUTTON_HEIGHT + 20), BUTTON_WIDTH, BUTTON_HEIGHT, "btnMain", "Main Menu", menu_death_main); window_addButton(wid, 20, 20, BUTTON_WIDTH, BUTTON_HEIGHT, "btnExit", "Exit Game", (void(*)(char*)) exit_game); menu_Open(MENU_DEATH); } static void menu_death_main(char* str) { (void)str; unsigned int wid; wid = window_get("Death"); window_destroy(wid); menu_Close(MENU_DEATH); menu_main(); } /* Generic close approach. */ static void menu_generic_close(char* str) { window_destroy(window_get(str+5)); /* closeFoo -> Foo. */ }