#include "log.h" #include "lephisto.h" #include "toolkit.h" #include "space.h" #include "opengl.h" #include "map.h" #define WINDOW_WIDTH 550 #define WINDOW_HEIGHT 440 #define MAP_WIDTH (WINDOW_WIDTH-150) #define MAP_HEIGHT (WINDOW_HEIGHT-100) #define BUTTON_WIDTH 60 #define BUTTON_HEIGHT 40 static int map_wid = 0; static double map_zoom = 1.; // Zoom of the map. static double map_xpos = 0.; // Map position. static double map_ypos = 0.; static int map_selected = -1; static StarSystem** map_path = NULL; // The path to current selected system. static int map_npath = 0; static int map_drag = 0; // Is the user dragging the map? // Extern. // space.c extern StarSystem* systems_stack; extern int systems_nstack; // player.c extern int planet_target; extern int hyperspace_target; static void map_close(char* str); static void map_update(void); static int map_inPath(StarSystem* sys); static void map_render(double bx, double by, double w, double h); static void map_mouse(SDL_Event* event, double mx, double my); static void map_buttonZoom(char* str); static void map_selectCur(void); // Open the map window. void map_open(void) { if(map_wid) { map_close(NULL); return; } // Set the position to focus on current system. map_xpos = cur_system->pos.x; map_ypos = cur_system->pos.y; map_wid = window_create("Star Map", -1, -1, WINDOW_WIDTH, WINDOW_HEIGHT); window_addText(map_wid, -20, -20, 100, 20, 1, "txtSysname", &gl_defFont, &cDConsole, systems_stack[map_selected].name); window_addText(map_wid, -20, -60, 90, 20, 0, "txtSFaction", &gl_smallFont, &cDConsole, "Faction:"); window_addText(map_wid, -20, -60-gl_smallFont.h-5, 80, 100, 0, "txtFaction", &gl_smallFont, &cBlack, NULL); window_addText(map_wid, -20, -110, 90, 20, 0, "txtSPlanets", &gl_smallFont, &cDConsole, "Planets:"); window_addText(map_wid, -20, -110-gl_smallFont.h-5, 80, 100, 0, "txtPlanets", &gl_smallFont, &cBlack, NULL); window_addCust(map_wid, 20, -40, MAP_WIDTH, MAP_HEIGHT, "cstMap", 1, map_render, map_mouse); window_addButton(map_wid, -20, 20, BUTTON_WIDTH, BUTTON_HEIGHT, "btnClose", "Close", map_close); window_addButton(map_wid, 40, 20, 30, 30, "btnZoomIn", "+", map_buttonZoom); window_addButton(map_wid, 80, 20, 30, 30, "btnZoomOut", "-", map_buttonZoom); map_update(); } static void map_close(char* str) { (void)str; if(map_wid) { window_destroy(map_wid); map_wid = 0; } } static void map_update(void) { int i; StarSystem* sys; int f; char buf[100]; sys = &systems_stack[map_selected]; window_modifyText(map_wid, "txtSysname", sys->name); if(sys->nplanets == 0) // No planets -> no factions. snprintf(buf, 100, "NA"); else { f = -1; for(i = 0; i < sys->nplanets; i++) { if((f == -1) && (sys->planets[i].faction != 0)) f = sys->planets[i].faction; else if(f != sys->planets[i].faction && (sys->planets[i].faction!=0)) { // TODO: more verbosity. snprintf(buf, 100, "Multiple"); break; } } if(i == sys->nplanets) // Saw them all, and all the same. snprintf(buf, 100, "%s", faction_name(f)); } window_modifyText(map_wid, "txtFaction", buf); buf[0] = '\0'; if(sys->nplanets == 0) snprintf(buf, 100, "None"); else { if(sys->nplanets > 0) strcat(buf, sys->planets[0].name); for(i = 1; i < sys->nplanets; i++) { strcat(buf, ",\n"); strcat(buf, sys->planets[i].name); } } window_modifyText(map_wid, "txtPlanets", buf); } // Return 1 if sys is part of the map_path. static int map_inPath(StarSystem* sys) { int i, f; f = pilot_getJumps(player) - 1; for(i = 0; i < map_npath; i++) if(map_path[i] == sys) { if(i > f) { return 2; } else return 1; } return 0; } // Render the map as a custom widget. static void map_render(double bx, double by, double w, double h) { int i, j, n, m; double x, y, r, tx, ty; StarSystem* sys; glColour* col; r = 5.; x = (bx - map_xpos + w/2) * 1.; y = (by - map_ypos + h/2) * 1.; // Background COLOUR(cBlack); glBegin(GL_QUADS); glVertex2d(bx, by); glVertex2d(bx, by+h); glVertex2d(bx+w, by+h); glVertex2d(bx+w, by); glEnd(); // Render the star systems. for(i = 0; i < systems_nstack; i++) { sys = &systems_stack[i]; // Draw the system. if(sys == cur_system) COLOUR(cRadar_targ); else if(sys->nplanets==0) COLOUR(cInert); // TODO: dependant on planet type. else if(areEnemies(player->faction, sys->faction)) COLOUR(cRed); else COLOUR(cYellow); gl_drawCircleInRect(x + sys->pos.x*map_zoom, y + sys->pos.y*map_zoom, r, bx, by, w, h); // Draw the system name. tx = x + 7. + sys->pos.x * map_zoom; ty = y - 5. + sys->pos.y * map_zoom; gl_print(&gl_smallFont, tx + SCREEN_W/2., ty + SCREEN_H/2., &cWhite, sys->name); // Draw the hyperspace paths. glShadeModel(GL_SMOOTH); // Cheaply use transparency instead of actually // calculating from x to y the line must go. :) for(j = 0; j < sys->njumps; j++) { n = map_inPath(&systems_stack[sys->jumps[j]]); m = map_inPath(sys); // Set the colours, is the route the current one? if((hyperspace_target != -1) && (((cur_system == sys) && (j == hyperspace_target)) || ((cur_system == &systems_stack[sys->jumps[j]]) && (sys == &systems_stack[cur_system->jumps[hyperspace_target]])))) col = &cGreen; else if((n > 0) && (m > 0)) { if((n == 2) || (m == 2)) // Out of fuel. col = &cRed; else col = &cYellow; } else col = &cDarkBlue; glBegin(GL_LINE_STRIP); ACOLOUR(*col, 0.); tx = x + sys->pos.x * map_zoom; ty = y + sys->pos.y * map_zoom; glVertex2d(tx, ty); COLOUR(*col); tx += (systems_stack[sys->jumps[j]].pos.x - sys->pos.x)/2. * map_zoom; ty += (systems_stack[sys->jumps[j]].pos.y - sys->pos.y)/2. * map_zoom; glVertex2d(tx, ty); ACOLOUR(*col, 0.); tx = x + systems_stack[sys->jumps[j]].pos.x * map_zoom; ty = y + systems_stack[sys->jumps[j]].pos.y * map_zoom; glVertex2d(tx, ty); glEnd(); } glShadeModel(GL_FLAT); } // Selected planet. if(map_selected != -1) { sys = &systems_stack[map_selected]; COLOUR(cRed); gl_drawCircleInRect(x + sys->pos.x*map_zoom, y + sys->pos.y*map_zoom, r+3., bx, by, w, h); } } // Map event handling. static void map_mouse(SDL_Event* event, double mx, double my) { int i, j; double x, y, t; StarSystem* sys; t = 13.*15.; // Threshold. mx -= MAP_WIDTH/2 - map_xpos; my -= MAP_HEIGHT/2 - map_ypos; switch(event->type) { case SDL_MOUSEBUTTONDOWN: if(event->button.button == SDL_BUTTON_WHEELUP) map_buttonZoom("btnZoomOut"); else if(event->button.button == SDL_BUTTON_WHEELDOWN) map_buttonZoom("btnZoomIn"); // Selecting star system. else { for(i = 0; i < systems_nstack; i++) { sys = &systems_stack[i]; // Get position. x = systems_stack[i].pos.x * map_zoom; y = systems_stack[i].pos.y * map_zoom; if((pow2(mx-x)+pow2(my-y)) < t) { // Select the current system and make a path to it. map_selected = i; if(map_path) free(map_path); map_path = system_getJumpPath(&map_npath, cur_system->name, sys->name); if(map_npath == 0) hyperspace_target = -1; else // See if it a valid hyperspace target. for(j = 0; j < cur_system->njumps; j++) { if(map_path[0] == &systems_stack[cur_system->jumps[j]]) { planet_target = -1; // Override planet_target. hyperspace_target = j; break; } } map_update(); break; } } map_drag = 1; } break; case SDL_MOUSEBUTTONUP: if(map_drag) map_drag = 0; break; case SDL_MOUSEMOTION: if(map_drag) { // Axis is inverted. map_xpos -= event->motion.xrel; map_ypos += event->motion.yrel; } break; } } static void map_buttonZoom(char* str) { if(strcmp(str, "btnZoomIn")==0) { map_zoom += (map_zoom >= 1.) ? 0.5 : 0.25; map_zoom = MIN(2.5, map_zoom); } else if(strcmp(str, "btnZoomOut")==0) { map_zoom -= (map_zoom > 1.) ? 0.5 : 0.25; map_zoom = MAX(0.5, map_zoom); } } // Set the map to sane defaults. void map_clear(void) { map_zoom = 1.; if(cur_system != NULL) { map_xpos = cur_system->pos.x; map_ypos = cur_system->pos.y; } else { map_xpos = 0.; map_ypos = 0.; } if(map_path != NULL) { free(map_path); map_path = NULL; map_npath = 0; } // Default system is current system. map_selectCur(); } static void map_selectCur(void) { int i; if(cur_system != NULL) { for(i = 0; i < systems_nstack; i++) { if(&systems_stack[i] == cur_system) { map_selected = i; break; } } } else { // Probably going to seg fault now.. map_selected = -1; } } // Update the map after a jump. void map_jump(void) { int j; // Set selected system to self. map_selectCur(); map_xpos = cur_system->pos.x; map_ypos = cur_system->pos.y; // Update path if set. if(map_path != NULL) { map_npath--; if(map_npath == 0) { // Path is empty. free(map_path); map_path = NULL; } else { // Get rid of bottom of the path. memcpy(&map_path[0], &map_path[1], sizeof(StarSystem*) * map_npath); map_path = realloc(map_path, sizeof(StarSystem*) * map_npath); // Set the next jump to be the next in path. for(j = 0; j < cur_system->njumps; j++) { if(map_path[0] == &systems_stack[cur_system->jumps[j]]) { planet_target = -1; // Override planet_target. hyperspace_target = j; break; } } } } }