naev 0.11.5
map.c
1/*
2 * See Licensing and Copyright notice in naev.h
3 */
5#include <float.h>
6#include <math.h>
7#include <stdio.h>
8#include <stdlib.h>
9
10#include "naev.h"
13#include "map.h"
14
15#include "conf.h"
16#include "array.h"
17#include "colour.h"
18#include "dialogue.h"
19#include "faction.h"
20#include "gui.h"
21#include "log.h"
22#include "mapData.h"
23#include "map_find.h"
24#include "map_system.h"
25#include "map_overlay.h"
26#include "mission.h"
27#include "nebula.h"
28#include "ndata.h"
29#include "nmath.h"
30#include "nstring.h"
31#include "nxml.h"
32#include "opengl.h"
33#include "player.h"
34#include "space.h"
35#include "toolkit.h"
36#include "utf8.h"
37
38#define BUTTON_WIDTH 100
39#define BUTTON_HEIGHT 30
40#define MAP_LOOP_PROT 1000
41#define MAP_TEXT_INDENT 45
42#define MAP_MARKER_CYCLE 750
43#define MAP_MOVE_THRESHOLD 20.
44#define EASE_ALPHA ease_QuadraticInOut
46static const int RCOL_X = -10;
47static const int RCOL_TEXT_W = 135;
48static const int RCOL_HEADER_W = 140;
49//static const int RCOL_W = RCOL_HEADER_W - RCOL_X*2; /**< Real width of the right column. */
50/* Below is a hack because older GCC claims the above line is not constant... */
51static const int RCOL_W = 140 - (-10*2);
52static const int BBAR_H = 60;
57typedef struct FactionPresence_ {
58 const char *name;
59 double value;
60 int known;
62
66typedef struct CstMapWidget_ {
67 double xoff;
68 double yoff;
69 double zoom;
70 double xpos;
71 double ypos;
72 double xtarget;
73 double ytarget;
74 int drag;
77 double alpha_env;
78 double alpha_path;
79 double alpha_names;
80 double alpha_commod;
82 MapMode mode;
84
85/* map decorator stack */
86static MapDecorator* decorator_stack = NULL;
88static int map_selected = -1;
89static MapMode map_mode = MAPMODE_TRAVEL;
90static StarSystem **map_path = NULL;
91static int cur_commod = -1;
92static int cur_commod_mode = 0;
93static Commodity **commod_known = NULL;
94static char** map_modes = NULL;
95static int listMapModeVisible = 0;
96static double commod_av_gal_price = 0;
97static double map_dt = 0.;
98static int map_minimal_mode = 0;
99static double map_flyto_speed = 1500.;
100static double map_mx = 0.;
101static double map_my = 0.;
102static char map_show_notes = 0;
104/*
105 * extern
106 */
107/* space.c */
108extern StarSystem *systems_stack;
109
110/*land.c*/
111extern int landed;
112extern Spob* land_spob;
113
114/*
115 * prototypes
116 */
117/* Update. */
118static void map_update_autonav( unsigned int wid );
119static void map_update_status( unsigned int wid, const char *buf );
120static void map_update( unsigned int wid );
121/* Render. */
122static void map_render( double bx, double by, double w, double h, void *data );
123static void map_renderPath( double x, double y, double zoom, double radius, double alpha );
124static void map_renderMarkers( double x, double y, double zoom, double r, double a );
125static void map_renderCommod( double bx, double by, double x, double y,
126 double zoom, double w, double h, double r, int editor, double a );
127static void map_renderCommodIgnorance( double x, double y, double zoom,
128 const StarSystem *sys, const Commodity *c, double a );
129static void map_drawMarker( double x, double y, double zoom,
130 double r, double a, int num, int cur, int type );
131/* Mouse. */
132static void map_focusLose( unsigned int wid, const char* wgtname );
133static int map_mouse( unsigned int wid, const SDL_Event* event, double mx, double my,
134 double w, double h, double rx, double ry, void *data );
135/* Misc. */
136static void map_setup (void);
137static void map_updateInternal( CstMapWidget *cst, double dt );
138static void map_reset( CstMapWidget* cst, MapMode mode );
139static CstMapWidget* map_globalCustomData( unsigned int wid );
140static int map_keyHandler( unsigned int wid, SDL_Keycode key, SDL_Keymod mod, int isrepeat );
141static void map_buttonZoom( unsigned int wid, const char* str );
142static void map_setMinimal( unsigned int wid, int value );
143static void map_buttonMarkSystem( unsigned int wid, const char* str );
144static void map_buttonSystemMap( unsigned int wid, const char* str );
145static void map_buttonMinimal( unsigned int wid, const char* str );
146static void map_buttonCommodity( unsigned int wid, const char* str );
147static void map_selectCur (void);
148static void map_genModeList(void);
149static void map_update_commod_av_price();
150static void map_onClose( unsigned int wid, const char *str );
151
157int map_init (void)
158{
159 return ovr_init();
160}
161
165void map_exit (void)
166{
167 if (decorator_stack != NULL) {
168 for (int i=0; i<array_size(decorator_stack); i++)
169 gl_freeTexture( decorator_stack[i].image );
170 array_free( decorator_stack );
171 decorator_stack = NULL;
172 }
173
174 ovr_exit();
175}
176
180static int map_keyHandler( unsigned int wid, SDL_Keycode key, SDL_Keymod mod, int isrepeat )
181{
182 (void) mod;
183 (void) isrepeat;
184
185 if ((key == SDLK_SLASH) || (key == SDLK_f)) {
186 map_inputFind( wid, NULL );
187 return 1;
188 }
189
190 return 0;
191}
192
193static void map_setup (void)
194{
195 /* Mark systems as discovered as necessary. */
196 for (int i=0; i<array_size(systems_stack); i++) {
197 StarSystem *sys = &systems_stack[i];
198 sys_rmFlag( sys, SYSTEM_DISCOVERED | SYSTEM_INTEREST );
199
200 /* Check to see if system has landable spobs. */
201 sys_rmFlag( sys, SYSTEM_HAS_LANDABLE );
202 for (int j=0; j<array_size(sys->spobs); j++) {
203 Spob *p = sys->spobs[j];
204 if (!spob_isKnown(p))
205 continue;
206 if (!spob_hasService(p, SPOB_SERVICE_LAND))
207 continue;
208 sys_setFlag( sys, SYSTEM_HAS_KNOWN_LANDABLE );
209 spob_updateLand( p );
210 if (p->can_land)
211 sys_setFlag( sys, SYSTEM_HAS_LANDABLE );
212 }
213
214 int known = 1;
215 for (int j=0; j<array_size(sys->jumps); j++) {
216 const JumpPoint *jp = &sys->jumps[j];
217 if (jp_isFlag(jp, JP_EXITONLY) || jp_isFlag(jp, JP_HIDDEN))
218 continue;
219 if (!jp_isFlag(jp, JP_KNOWN)) {
220 known = 0;
221 break;
222 }
223 }
224 if (known) {
225 /* Check spobs. */
226 for (int j=0; j<array_size(sys->spobs); j++) {
227 const Spob *p = sys->spobs[j];
228 if (!spob_isKnown(p)) {
229 known = 0;
230 break;
231 }
232 }
233 }
234
235 if (known)
236 sys_setFlag( sys, SYSTEM_DISCOVERED );
237 }
238
239 /* mark systems as needed */
241}
242
246void map_open (void)
247{
248 unsigned int wid;
249 StarSystem *cur;
250 int w, h, x, y, rw;
251 //int tw, th;
252 CstMapWidget *cst;
253 const char *title = _("Star Map");
254 const glColour cBG = { 0., 0., 0., 0.95 };
255
256 map_minimal_mode = player.map_minimal;
257 listMapModeVisible = 0;
258
259 /* Not under manual control. */
260 if (pilot_isFlag( player.p, PILOT_MANUAL_CONTROL ))
261 return;
262
263 /* Destroy window if exists. */
264 wid = window_get(MAP_WDWNAME);
265 if (wid > 0) {
266 if (window_isTop(wid))
267 window_destroy( wid );
268 return;
269 }
270
271 /* Set up stuff. */
272 map_setup();
273
274 /* Attempt to select current map if none is selected */
275 if (map_selected == -1)
276 map_selectCur();
277
278 /* get the selected system. */
279 cur = system_getIndex( map_selected );
280
281 /* create the window. */
282 wid = window_create( MAP_WDWNAME, title, -1, -1, -1, -1 );
283 window_setDynamic( wid, 1 );
285 window_onClose( wid, map_onClose );
286 window_handleKeys( wid, map_keyHandler );
287 window_dimWindow( wid, &w, &h );
288 window_setBorder( wid, 0 );
289
290 /*
291 * The map itself.
292 */
293 map_show( wid, 0, 0, w, h, 1., RCOL_W/2., BBAR_H/2. ); /* Reset zoom. */
294
295 /* Map title. */
296#if 0
297 rw = gl_printWidthRaw( NULL, title );
298 tw = rw+30;
299 th = gl_defFont.h + 20;
300 window_addRect( wid, (w-tw)/2., h-th, tw, th, "rctTBar", &cBG, 0 );
301 window_addText( wid, (w-rw)/2., h-gl_defFont.h-10., rw, gl_defFont.h, 1, "txtTitle",
302 &gl_defFont, NULL, title );
303#endif
304
305 /* Overlay background. */
306 window_addRect( wid, w-RCOL_W, 0, RCOL_W, h, "rctRCol", &cBG, 0 );
307 window_addRect( wid, 0, 0, w, BBAR_H, "rctBBar", &cBG, 0 );
308
309 /*
310 * SIDE TEXT
311 *
312 * $System
313 *
314 * Faction:
315 * $Faction (or Multiple)
316 *
317 * Status:
318 * $Status
319 *
320 * Spobs:
321 * $Spob1, $Spob2, ...
322 *
323 * Services:
324 * $Services
325 *
326 * ...
327 * [Autonav]
328 * [ Find ]
329 * [ Close ]
330 */
331 x = RCOL_X; /* Right column X offset. */
332 rw = RCOL_TEXT_W; /* Right column indented width maximum. */
333 y = -20;
334
335 /* System Name */
336 window_addText( wid, -90 + 80, y, 160, 20, 1, "txtSysname",
337 &gl_defFont, NULL, _(cur->name) );
338 y -= 10;
339
340 /* Faction image */
341 window_addImage( wid, -90 + 32, y - 32, 0, 0, "imgFaction", NULL, 0 );
342 y -= 64 + 10;
343
344 /* Faction */
345 window_addText( wid, x, y, RCOL_HEADER_W, 20, 0, "txtSFaction",
346 &gl_smallFont, &cFontGrey, _("Faction:") );
347 window_addText( wid, x, y-gl_smallFont.h-5, rw, 300, 0, "txtFaction",
348 &gl_smallFont, NULL, NULL );
349 y -= 2 * gl_smallFont.h + 5 + 15;
350
351 /* Standing */
352 window_addText( wid, x, y, RCOL_HEADER_W, 20, 0, "txtSStanding",
353 &gl_smallFont, &cFontGrey, _("Standing:") );
354 window_addText( wid, x, y-gl_smallFont.h-5, rw, 300, 0, "txtStanding",
355 &gl_smallFont, NULL, NULL );
356 y -= 2 * gl_smallFont.h + 5 + 15;
357
358 /* Presence. */
359 window_addText( wid, x, y, RCOL_HEADER_W, 20, 0, "txtSPresence",
360 &gl_smallFont, &cFontGrey, _("Presence:") );
361 window_addText( wid, x, y-gl_smallFont.h-5, rw, 300, 0, "txtPresence",
362 &gl_smallFont, NULL, NULL );
363 y -= 2 * gl_smallFont.h + 5 + 15;
364
365 /* Spobs */
366 window_addText( wid, x, y, RCOL_HEADER_W, 20, 0, "txtSSpobs",
367 &gl_smallFont, &cFontGrey, _("Space Objects:") );
368 window_addText( wid, x, y-gl_smallFont.h-5, rw, 300, 0, "txtSpobs",
369 &gl_smallFont, NULL, NULL );
370 y -= 2 * gl_smallFont.h + 5 + 15;
371
372 /* Services */
373 window_addText( wid, x, y, RCOL_HEADER_W, 20, 0, "txtSServices",
374 &gl_smallFont, &cFontGrey, _("Services:") );
375 window_addText( wid, x, y-gl_smallFont.h-5, rw, 300, 0, "txtServices",
376 &gl_smallFont, NULL, NULL );
377
378 /* Close button */
379 y = 15;
380 window_addButton( wid, -20, y, BUTTON_WIDTH, BUTTON_HEIGHT,
381 "btnClose", _("Close"), window_close );
382 /* Commodity button */
383 window_addButton( wid, -20 - (BUTTON_WIDTH+20), y, BUTTON_WIDTH, BUTTON_HEIGHT, "btnCommod", _("Mode"), map_buttonCommodity );
384 /* Find button */
385 window_addButtonKey( wid, -20 - 2*(BUTTON_WIDTH+20), y, BUTTON_WIDTH, BUTTON_HEIGHT,
386 "btnFind", _("Find"), map_inputFind, SDLK_f );
387 /* Autonav button */
388 window_addButtonKey( wid, -20 - 3*(BUTTON_WIDTH+20), y, BUTTON_WIDTH, BUTTON_HEIGHT,
389 "btnAutonav", _("Autonav"), player_autonavStartWindow, SDLK_a );
390 /* MInimal button */
391 window_addButtonKey( wid, -20 - 4*(BUTTON_WIDTH+20), y, BUTTON_WIDTH, BUTTON_HEIGHT,
392 "btnMinimal", NULL, map_buttonMinimal, SDLK_v );
393 map_setMinimal( wid, map_minimal_mode );
394 /* System info button */
395 window_addButtonKey( wid, -20 - 5*(BUTTON_WIDTH+20), y, BUTTON_WIDTH, BUTTON_HEIGHT,
396 "btnSystem", _("System Info"), map_buttonSystemMap, SDLK_s );
397 /* Mark this system button */
398 window_addButtonKey( wid, -20 - 6*(BUTTON_WIDTH+20), y, BUTTON_WIDTH, BUTTON_HEIGHT,
399 "btnMarkSystem", _("Toggle Note"), map_buttonMarkSystem, SDLK_n );
400
401 /*
402 * Bottom stuff
403 *
404 * [+] [-] Nebula, Interference
405 */
406 /* Zoom buttons */
407 window_addButtonKey( wid, -60, 30 + BUTTON_HEIGHT, 30, BUTTON_HEIGHT, "btnZoomIn", "+", map_buttonZoom, SDLK_EQUALS );
408 window_addButtonKey( wid, -20, 30 + BUTTON_HEIGHT, 30, BUTTON_HEIGHT, "btnZoomOut", "-", map_buttonZoom, SDLK_MINUS );
409 /* Situation text */
410 window_addText( wid, 20, 15, w - 40 - 7*(BUTTON_WIDTH+20), 30, 0,
411 "txtSystemStatus", &gl_smallFont, NULL, NULL );
412
413 /* Fuel. */
414 window_addText( wid, -20, 40+BUTTON_HEIGHT*2, rw, 30, 0,
415 "txtPlayerStatus", &gl_smallFont, NULL, NULL );
416
417 map_genModeList();
418 cst = map_globalCustomData(wid);
419 map_reset( cst, map_mode );
420 map_update( wid );
421
422 /*
423 * Disable Autonav button if player lacks fuel or if target is not a valid hyperspace target.
424 */
425 if ((player.p->fuel < player.p->fuel_consumption) || pilot_isFlag( player.p, PILOT_NOJUMP)
426 || map_selected == cur_system - systems_stack || array_size(map_path) == 0)
427 window_disableButton( wid, "btnAutonav" );
428
429 /*
430 * The find window is not reentrant. A player can open the map window when they are in the result of the find window that comes from an outfitter or a shipyard.
431 */
432 if ( window_exists( "wdwFind" ) ) {
433 window_disableButton( wid, "btnFind" );
434 }
435}
436
437/*
438 * Prepares economy info for rendering. Called when cur_commod changes.
439 */
440static void map_update_commod_av_price (void)
441{
442 Commodity *c;
443
444 if (cur_commod == -1 || map_selected == -1) {
445 commod_av_gal_price = 0;
446 return;
447 }
448
449 c = commod_known[cur_commod];
450 if (cur_commod_mode == 0) {
451 double totPrice = 0;
452 int totPriceCnt = 0;
453 for (int i=0; i<array_size(systems_stack); i++) {
454 StarSystem *sys = system_getIndex( i );
455
456 /* if system is not known, reachable, or marked. and we are not in the editor */
457 if ((!sys_isKnown(sys) && !sys_isFlag(sys, SYSTEM_MARKED | SYSTEM_CMARKED)
458 && !space_sysReachable(sys)))
459 continue;
460 if ((sys_isKnown(sys)) && (system_hasSpob(sys))) {
461 double sumPrice = 0;
462 int sumCnt = 0;
463 double thisPrice;
464 for (int j=0 ; j<array_size(sys->spobs); j++) {
465 Spob *p = sys->spobs[j];
466 for (int k=0; k<array_size(p->commodities); k++) {
467 if (p->commodities[k] == c) {
468 if (p->commodityPrice[k].cnt > 0) { /*commodity is known about*/
469 thisPrice = p->commodityPrice[k].sum / p->commodityPrice[k].cnt;
470 sumPrice += thisPrice;
471 sumCnt += 1;
472 break;
473 }
474 }
475 }
476 }
477 if (sumCnt>0) {
478 totPrice += sumPrice / sumCnt;
479 totPriceCnt++;
480 }
481 }
482 }
483 if (totPriceCnt > 0)
484 totPrice /= totPriceCnt;
485 commod_av_gal_price = totPrice;
486
487 }
488 else
489 commod_av_gal_price = 0;
490}
491
492static void map_update_autonav( unsigned int wid )
493{
494 char buf[STRMAX];
495 StarSystem *sys;
496 int autonav, th;
497 int jumps = floor(player.p->fuel / player.p->fuel_consumption);
498 int p = 0;
499 int rw = RCOL_HEADER_W;
500 p += scnprintf(&buf[p], sizeof(buf)-p, "#n%s#0", _("Fuel: ") );
501 p += scnprintf(&buf[p], sizeof(buf)-p, n_("%d jump", "%d jumps", jumps), jumps );
502 sys = map_getDestination( &autonav );
503 p += scnprintf(&buf[p], sizeof(buf)-p, "\n#n%s#0", _("Autonav: ") );
504 if (sys==NULL)
505 /*p +=*/ scnprintf(&buf[p], sizeof(buf)-p, _("Off") );
506 else {
507 if (autonav > jumps)
508 p += scnprintf(&buf[p], sizeof(buf)-p, "#r" );
509 p += scnprintf(&buf[p], sizeof(buf)-p, n_("%d jump", "%d jumps", autonav), autonav );
510 if (autonav > jumps)
511 /*p +=*/ scnprintf(&buf[p], sizeof(buf)-p, "#0" );
512 }
513 th = gl_printHeightRaw( &gl_smallFont, rw, buf );
514 window_resizeWidget( wid, "txtPlayerStatus", rw, th );
515 window_moveWidget( wid, "txtPlayerStatus", RCOL_X, 40+BUTTON_HEIGHT*2 );
516 window_modifyText( wid, "txtPlayerStatus", buf );
517}
518
519static void map_update_status( unsigned int wid, const char *buf )
520{
521 int w, h;
522 window_modifyText( wid, "txtSystemStatus", buf );
523 if (buf==NULL)
524 return;
525 window_dimWidget( wid, "txtSystemStatus", &w, NULL );
526 h = gl_printHeightRaw( &gl_smallFont, w, buf );
527 window_moveWidget( wid, "txtSystemStatus", 20, (BBAR_H-h)/2 );
528 window_resizeWidget( wid, "txtSystemStatus", w, h );
529}
530
536static void map_update( unsigned int wid )
537{
538 int multiple;
539 StarSystem *sys;
540 int f, fh, h, x, y;
541 unsigned int services, services_u, services_h, services_f, services_r;
542 int hasSpobs;
543 char t;
544 char buf[STRMAX];
545 int p;
546 double w;
547
548 /* Needs map to update. */
549 if (!map_isOpen())
550 return;
551
552 /* Propagate updates to map_mode, if an. */
553 map_globalCustomData(wid)->mode = map_mode;
554
555 /* Get selected system. */
556 sys = system_getIndex( map_selected );
557
558 /* Not known and no markers. */
559 if (!(sys_isFlag(sys, SYSTEM_MARKED | SYSTEM_CMARKED)) &&
560 !sys_isKnown(sys) && !space_sysReachable(sys)) {
561 map_selectCur();
562 sys = system_getIndex( map_selected );
563 }
564 /* Average commodity price */
565 map_update_commod_av_price();
566
567 /* Economy button */
568 if (map_mode == MAPMODE_TRADE) {
569 const Commodity *c = commod_known[cur_commod];
570 if (cur_commod_mode == 1) {
571 snprintf( buf, sizeof(buf),
572 _("Showing %s prices relative to %s:\n"
573 "Positive/blue indicate profit while negative/orange values indicate loss when sold at the corresponding system."),
574 _(c->name), _(sys->name) );
575 map_update_status( wid, buf );
576 }
577 else {
578 snprintf(buf, sizeof(buf), _("Showing known %s prices.\nGalaxy-wide average: %.2f"), _(c->name), commod_av_gal_price);
579 map_update_status( wid, buf );
580 }
581 }
582 else
583 map_update_status( wid, NULL );
584
585 /*
586 * Right Text
587 */
588 x = RCOL_X; /* Side bar X offset. */
589 w = RCOL_TEXT_W; /* Width of the side bar. */
590 y = -20 - 20 - 64 - gl_defFont.h; /* Initialized to position for txtSFaction. */
591
592 if (!sys_isKnown(sys)) { /* System isn't known, erase all */
593 /*
594 * Right Text
595 */
596 if (sys_isFlag(sys, SYSTEM_MARKED | SYSTEM_CMARKED))
597 window_modifyText( wid, "txtSysname", _(sys->name) );
598 else
599 window_modifyText( wid, "txtSysname", _("Unknown") );
600
601 /* Faction */
602 window_modifyImage( wid, "imgFaction", NULL, 0, 0 );
603 window_moveWidget( wid, "txtSFaction", x, y);
604 window_moveWidget( wid, "txtFaction", x, y - gl_smallFont.h - 5 );
605 window_modifyText( wid, "txtFaction", _("Unknown") );
606 y -= 2 * gl_smallFont.h + 5 + 15;
607
608 /* Standing */
609 window_moveWidget( wid, "txtSStanding", x, y );
610 window_moveWidget( wid, "txtStanding", x, y - gl_smallFont.h - 5 );
611 window_modifyText( wid, "txtStanding", _("Unknown") );
612 y -= 2 * gl_smallFont.h + 5 + 15;
613
614 /* Presence. */
615 window_moveWidget( wid, "txtSPresence", x, y );
616 window_moveWidget( wid, "txtPresence", x, y - gl_smallFont.h - 5 );
617 window_modifyText( wid, "txtPresence", _("Unknown") );
618 y -= 2 * gl_smallFont.h + 5 + 15;
619
620 /* Spobs */
621 window_moveWidget( wid, "txtSSpobs", x, y );
622 window_moveWidget( wid, "txtSpobs", x, y - gl_smallFont.h - 5 );
623 window_modifyText( wid, "txtSpobs", _("Unknown") );
624 y -= 2 * gl_smallFont.h + 5 + 15;
625
626 /* Services */
627 window_moveWidget( wid, "txtSServices", x, y );
628 window_moveWidget( wid, "txtServices", x, y -gl_smallFont.h - 5 );
629 window_modifyText( wid, "txtServices", _("Unknown") );
630
631 /* Update autonav stuff. */
632 map_update_autonav( wid );
633
634 /*
635 * Bottom Text
636 */
637 map_update_status( wid, NULL );
638 return;
639 }
640
641 /* System is known */
642 window_modifyText( wid, "txtSysname", _(sys->name) );
643
644 f = -1;
645 multiple = 0;
646 for (int i=0; i<array_size(sys->spobs); i++) {
647 if (!spob_isKnown(sys->spobs[i]))
648 continue;
649 if ((sys->spobs[i]->presence.faction >= 0)
650 && (!faction_isKnown(sys->spobs[i]->presence.faction)) )
651 continue;
652
653 if ((f == -1) && (sys->spobs[i]->presence.faction >= 0)) {
654 f = sys->spobs[i]->presence.faction;
655 }
656 else if (f != sys->spobs[i]->presence.faction
657 && (sys->spobs[i]->presence.faction >= 0)) {
658 snprintf( buf, sizeof(buf), _("Multiple") );
659 multiple = 1;
660 break;
661 }
662 }
663 if (f == -1) {
664 window_modifyImage( wid, "imgFaction", NULL, 0, 0 );
665 window_modifyText( wid, "txtFaction", _("N/A") );
666 window_modifyText( wid, "txtStanding", _("N/A") );
667 h = gl_smallFont.h;
668 fh = gl_smallFont.h;
669 }
670 else {
671 const char *fcttext;
672 const glTexture *logo;
673 int logow, logoh;
674 if (!multiple) /* saw them all and all the same */
675 snprintf( buf, sizeof(buf), "%s", faction_longname(f) );
676
677 /* Modify the image. */
678 logo = faction_logo(f);
679 logow = logo == NULL ? 0 : logo->w * (double)FACTION_LOGO_SM / MAX( logo->w, logo->h );
680 logoh = logo == NULL ? 0 : logo->h * (double)FACTION_LOGO_SM / MAX( logo->w, logo->h );
681 window_modifyImage( wid, "imgFaction", logo, logow, logoh );
682 if (logo != NULL)
683 window_moveWidget( wid, "imgFaction",
684 -90 + logow/2, -20 - 32 - 10 - gl_defFont.h + logoh/2);
685 fcttext = faction_getStandingText( f );
686
687 /* Modify the text */
688 window_modifyText( wid, "txtFaction", buf );
689 window_modifyText( wid, "txtStanding", fcttext );
690
691 h = gl_printHeightRaw( &gl_smallFont, w, buf );
692 fh = gl_printHeightRaw( &gl_smallFont, w, fcttext );
693 }
694
695 /* Faction */
696 window_moveWidget( wid, "txtSFaction", x, y);
697 window_moveWidget( wid, "txtFaction", x, y-gl_smallFont.h - 5 );
698 y -= gl_smallFont.h + h + 5 + 15;
699
700 /* Standing */
701 window_moveWidget( wid, "txtSStanding", x, y );
702 window_moveWidget( wid, "txtStanding", x, y-gl_smallFont.h - 5 );
703 y -= gl_smallFont.h + fh + 5 + 15;
704
705 window_moveWidget( wid, "txtSPresence", x, y );
706 window_moveWidget( wid, "txtPresence", x, y-gl_smallFont.h-5 );
707 map_updateFactionPresence( wid, "txtPresence", sys, 0 );
708 /* Scroll down. */
709 h = window_getTextHeight( wid, "txtPresence" );
710 y -= 40 + (h - gl_smallFont.h);
711
712 /* Get spobs */
713 hasSpobs = 0;
714 p = 0;
715 buf[0] = '\0';
716 for (int i=0; i<array_size(sys->spobs); i++) {
717 const char *prefix, *suffix;
718 Spob *s = sys->spobs[i];
719
720 if (!spob_isKnown(s))
721 continue;
722
723 /* Colourize output. */
724 spob_updateLand( s );
725 t = spob_getColourChar( s );
726 prefix = spob_getSymbol( s );
727 //suffix = (spob_isFlag( s, SPOB_MARKED ) ? _(" #o(M)") : "");
728 suffix = "";
729
730 if (!hasSpobs)
731 p += scnprintf( &buf[p], sizeof(buf)-p, "#%c%s%s%s#n",
732 t, prefix, spob_name( s ), suffix );
733 else
734 p += scnprintf( &buf[p], sizeof(buf)-p, ",\n#%c%s%s%s#n",
735 t, prefix, spob_name( s ), suffix );
736 hasSpobs = 1;
737 }
738 if (hasSpobs == 0) {
739 strncpy( buf, _("None"), sizeof(buf)-1 );
740 buf[sizeof(buf)-1] = '\0';
741 }
742 /* Update text. */
743 window_modifyText( wid, "txtSpobs", buf );
744 window_moveWidget( wid, "txtSSpobs", x, y );
745 window_moveWidget( wid, "txtSpobs", x, y-gl_smallFont.h-5 );
746 /* Scroll down. */
747 h = gl_printHeightRaw( &gl_smallFont, w, buf );
748 y -= 40 + (h - gl_smallFont.h);
749
750 /* Get the services */
751 window_moveWidget( wid, "txtSServices", x, y );
752 window_moveWidget( wid, "txtServices", x, y-gl_smallFont.h-5 );
753 services = 0;
754 services_u = 0;
755 services_h = 0;
756 services_f = 0;
757 services_r = 0;
758 for (int i=0; i<array_size(sys->spobs); i++) {
759 const Spob *pnt = sys->spobs[i];
760 if (!spob_isKnown(pnt))
761 continue;
762
763 if (!spob_hasService( pnt, SPOB_SERVICE_INHABITED ))
764 services_u |= pnt->services;
765 else if (pnt->can_land) {
766 if (areAllies(pnt->presence.faction,FACTION_PLAYER))
767 services_f |= pnt->services;
768 else
769 services |= pnt->services;
770 }
771 else if (areEnemies(pnt->presence.faction,FACTION_PLAYER))
772 services_h |= pnt->services;
773 else
774 services_r |= pnt->services;
775 }
776 buf[0] = '\0';
777 p = 0;
778 /*snprintf(buf, sizeof(buf), "%f\n", sys->prices[0]);*/ /*Hack to control prices. */
779 for (int i=SPOB_SERVICE_LAND; i<=SPOB_SERVICE_SHIPYARD; i<<=1) {
780 if (services_f & i)
781 p += scnprintf( &buf[p], sizeof(buf)-p, "#F+ %s\n", _(spob_getServiceName(i)) );
782 else if (services & i)
783 p += scnprintf( &buf[p], sizeof(buf)-p, "#N~ %s\n", _(spob_getServiceName(i)) );
784 else if (services_h & i)
785 p += scnprintf( &buf[p], sizeof(buf)-p, "#H!! %s\n", _(spob_getServiceName(i)) );
786 else if (services_r & i)
787 p += scnprintf( &buf[p], sizeof(buf)-p, "#R* %s\n", _(spob_getServiceName(i)) );
788 else if (services_u & i)
789 p += scnprintf( &buf[p], sizeof(buf)-p, "#I= %s\n", _(spob_getServiceName(i)) );
790 }
791 if (buf[0] == '\0')
792 /*p +=*/ scnprintf( &buf[p], sizeof(buf)-p, _("None"));
793
794 window_modifyText( wid, "txtServices", buf );
795
796 /*
797 * System Status, if not showing commodity info
798 */
799 if ((map_mode==MAPMODE_TRAVEL) || (map_mode==MAPMODE_DISCOVER)) {
800 int found;
801 buf[0] = '\0';
802 p = 0;
803
804 /* Special feature text. */
805 if (sys->features != NULL)
806 p += scnprintf(&buf[p], sizeof(buf)-p, "%s", _(sys->features) );
807
808 /* Mention spob features. */
809 for (int i=0; i<array_size(sys->spobs); i++) {
810 const Spob *spob = sys->spobs[i];
811 if (spob->feature == NULL)
812 continue;
813 if (!spob_isKnown(spob))
814 continue;
815 if (buf[0] != '\0')
816 p += scnprintf(&buf[p], sizeof(buf)-p, p_("system features", ", "));
817 p += scnprintf(&buf[p], sizeof(buf)-p, "%s", _(spob->feature));
818 }
819
820 /* Mention trade lanes if applicable. */
821 found = 0;
822 for (int i=0; i<array_size(sys->jumps); i++) {
823 if (sys->jumps[i].hide<=0.) {
824 found = 1;
825 break;
826 }
827 }
828 if (found) {
829 if (buf[0] != '\0')
830 p += scnprintf(&buf[p], sizeof(buf)-p, p_("system features", ", "));
831 p += scnprintf(&buf[p], sizeof(buf)-p, "#g%s#0", _("Trade Lane") );
832 }
833
834 /* Nebula. */
835 if (sys->nebu_density > 0.) {
836 const char *adj;
837 double dmg;
838 if (buf[0] != '\0')
839 p += scnprintf(&buf[p], sizeof(buf)-p, p_("system features", ", "));
840
841 /* Density. */
842 if (sys->nebu_density > 700.)
843 adj = p_("adj Nebula", "Dense ");
844 else if (sys->nebu_density < 300.)
845 adj = p_("adj Nebula", "Light ");
846 else
847 adj = "";
848
849 /* Volatility */
850 dmg = sys->nebu_volatility;
851 if (sys->nebu_volatility > 50.) {
852 p += scnprintf(&buf[p], sizeof(buf)-p, "#r" );
853 p += scnprintf(&buf[p], sizeof(buf)-p, _("Volatile %sNebula (%.1f %s)"), adj, dmg, UNIT_POWER);
854 }
855 else if (sys->nebu_volatility > 20.) {
856 p += scnprintf(&buf[p], sizeof(buf)-p, "#o" );
857 p += scnprintf(&buf[p], sizeof(buf)-p, _("Dangerous %sNebula (%.1f %s)"), adj, dmg, UNIT_POWER);
858 }
859 else if (sys->nebu_volatility > 0.) {
860 p += scnprintf(&buf[p], sizeof(buf)-p, "#y" );
861 p += scnprintf(&buf[p], sizeof(buf)-p, _("Unstable %sNebula (%.1f %s)"), adj, dmg, UNIT_POWER);
862 }
863 else
864 p += scnprintf(&buf[p], sizeof(buf)-p, _("%sNebula"), adj);
865 p += scnprintf(&buf[p], sizeof(buf)-p, "#0" );
866 }
867 /* Interference. */
868 if (sys->interference > 0.) {
869 double itf;
870 if (buf[0] != '\0')
871 p += scnprintf(&buf[p], sizeof(buf)-p, p_("system features", ", "));
872
873 itf = sys->interference;
874 if (sys->interference > 700.) {
875 p += scnprintf(&buf[p], sizeof(buf)-p, "#r" );
876 p += scnprintf(&buf[p], sizeof(buf)-p, _("Dense Interference (%.0f%%)"), itf);
877 }
878 else if (sys->interference > 300.) {
879 p += scnprintf(&buf[p], sizeof(buf)-p, "#o" );
880 p += scnprintf(&buf[p], sizeof(buf)-p, _("Medium Interference (%.0f%%)"), itf);
881 }
882 else {
883 p += scnprintf(&buf[p], sizeof(buf)-p, "#y" );
884 p += scnprintf(&buf[p], sizeof(buf)-p, _("Light Interference (%.0f%%)"), itf);
885 }
886 p += scnprintf(&buf[p], sizeof(buf)-p, "#0" );
887 }
888 /* Asteroids. */
889 if (array_size(sys->asteroids) > 0) {
890 double density = sys->asteroid_density;
891
892 if (buf[0] != '\0')
893 p += scnprintf(&buf[p], sizeof(buf)-p, p_("system features", ", "));
894
895 if (density >= 1000.) {
896 p += scnprintf(&buf[p], sizeof(buf)-p, "#o" );
897 p += scnprintf(&buf[p], sizeof(buf)-p, _("Dense Asteroids"));
898 }
899 else if (density <= 300.) {
900 p += scnprintf(&buf[p], sizeof(buf)-p, "#y" );
901 p += scnprintf(&buf[p], sizeof(buf)-p, _("Light Asteroids"));
902 }
903 else
904 p += scnprintf(&buf[p], sizeof(buf)-p, _("Asteroids"));
905 /*p +=*/ scnprintf(&buf[p], sizeof(buf)-p, "#0" );
906 }
907 /* Update the string. */
908 map_update_status( wid, buf );
909 }
910
911 /* Player info. */
912 map_update_autonav( wid );
913}
914
920int map_isOpen (void)
921{
922 return window_exists(MAP_WDWNAME);
923}
924
936static void map_drawMarker( double x, double y, double zoom,
937 double r, double a, int num, int cur, int type )
938{
939 (void) zoom;
940 const glColour* colours[] = {
941 &cMarkerNew, &cMarkerPlot, &cMarkerHigh, &cMarkerLow, &cMarkerComputer, &cMarkerNew
942 };
943 double alpha;
944 glColour col;
945
946 /* Calculate the angle. */
947 if ((num == 1) || (num == 2) || (num == 4))
948 alpha = M_PI/4.;
949 else if (num == 3)
950 alpha = M_PI/6.;
951 else if (num == 5)
952 alpha = M_PI/10.;
953 else
954 alpha = M_PI/2.;
955
956 alpha += M_PI*2. * (double)cur/(double)num;
957
958 x = x + 3.0*r * cos(alpha);
959 y = y + 3.0*r * sin(alpha);
960 r *= 2.0;
961
962 /* Special case notes marker. */
963 if (type==5) {
964 col = cFontOrange;
965 col.a *= a;
966 glUseProgram(shaders.notemarker.program);
967 gl_renderShader( x, y, r, r, alpha, &shaders.notemarker, &col, 1 );
968 return;
969 }
970
971 glUseProgram(shaders.sysmarker.program);
972 if (type==0) {
973 col_blend( &col, colours[type], &cWhite, MIN(1.0, 0.75 + 0.25*sin(2.0*M_PI*map_dt)) );
974 x += 0.25*r * cos(alpha);
975 y += 0.25*r * sin(alpha);
976 r *= 1.25;
977 glUniform1i( shaders.sysmarker.parami, 1 );
978 }
979 else {
980 col_blend( &col, colours[type], &cWhite, MIN(1.0, 1.0 + 0.25*sin(2.0*M_PI*map_dt)) );
981 glUniform1i( shaders.sysmarker.parami, 0 );
982 }
983 col.a *= a;
984 gl_renderShader( x, y, r, r, alpha, &shaders.sysmarker, &col, 1 );
985}
986
995static void map_render( double bx, double by, double w, double h, void *data )
996{
997 CstMapWidget *cst = data;
998 double x,y,z,r;
999 double dt = naev_getrealdt();
1000
1001 /* Update timer. */
1002 map_dt += dt;
1003 map_updateInternal( cst, dt );
1004
1005 /* Parameters. */
1006 map_renderParams( bx, by, cst->xpos, cst->ypos, w, h, cst->zoom, &x, &y, &r );
1007 z = cst->zoom;
1008
1009 /* background */
1010 gl_renderRect( bx, by, w, h, &cBlack );
1011
1012 if (cst->alpha_decorators > 0.)
1013 map_renderDecorators( x, y, z, 0, EASE_ALPHA(cst->alpha_decorators) );
1014
1015 /* Render faction disks. */
1016 if (cst->alpha_faction > 0.)
1017 map_renderFactionDisks( x, y, z, r, 0, EASE_ALPHA(cst->alpha_faction) );
1018
1019 /* Render environmental features. */
1020 if (cst->alpha_env > 0.)
1021 map_renderSystemEnvironment( x, y, z, 0, EASE_ALPHA(cst->alpha_env) );
1022
1023 /* Render jump routes. */
1024 map_renderJumps( x, y, z, r, 0 );
1025
1026 /* Render the player's jump route. */
1027 if (cst->alpha_path > 0.)
1028 map_renderPath( x, y, z, r, EASE_ALPHA(cst->alpha_path) );
1029
1030 /* Render systems. */
1031 map_renderSystems( bx, by, x, y, z, w, h, r, cst->mode );
1032
1033 /* Render system markers and notes. */
1034 if (cst->alpha_markers > 0.)
1035 map_renderMarkers( x, y, z, r, EASE_ALPHA(cst->alpha_markers) );
1036
1037 /* Render system names and notes. */
1038 if (cst->alpha_names > 0.)
1039 map_renderNames( bx, by, x, y, z, w, h, 0, EASE_ALPHA(cst->alpha_names) );
1040
1041 /* Render commodity info. */
1042 if (cst->alpha_commod > 0.)
1043 map_renderCommod( bx, by, x, y, z, w, h, r, 0, EASE_ALPHA(cst->alpha_commod) );
1044
1045 /* We want the notes on top of everything. */
1046 if (cst->alpha_markers > 0.)
1047 map_renderNotes( bx, by, x, y, z, w, h, 0, EASE_ALPHA(cst->alpha_markers) );
1048
1049 /* Selected system. */
1050 if (map_selected != -1) {
1051 const StarSystem *sys = system_getIndex( map_selected );
1052 glUseProgram( shaders.selectspob.program );
1053 glUniform1f( shaders.selectspob.dt, map_dt ); /* good enough. */
1054 gl_renderShader( x + sys->pos.x * z, y + sys->pos.y * z,
1055 1.7*r, 1.7*r, 0., &shaders.selectspob, &cRadar_tSpob, 1 );
1056 }
1057
1058 /* Current spob. */
1059 gl_renderCircle( x + cur_system->pos.x * z,
1060 y + cur_system->pos.y * z,
1061 1.5*r, &cRadar_tSpob, 0 );
1062
1063 glClear( GL_DEPTH_BUFFER_BIT );
1064}
1065
1069void map_renderParams( double bx, double by, double xpos, double ypos,
1070 double w, double h, double zoom, double *x, double *y, double *r )
1071{
1072 *r = round(CLAMP(6., 20., 8.*zoom));
1073 *x = round((bx - xpos + w/2) * 1.);
1074 *y = round((by - ypos + h/2) * 1.);
1075}
1076
1082void map_renderDecorators( double x, double y, double zoom, int editor, double alpha )
1083{
1084 const glColour ccol = { .r=1., .g=1., .b=1., .a=2./3.*alpha };
1086 /* Fade in the decorators to allow toggling between commodity and nothing */
1087 for (int i=0; i<array_size(decorator_stack); i++) {
1088 int visible;
1089 MapDecorator *decorator = &decorator_stack[i];
1090
1091 /* only if pict couldn't be loaded */
1092 if (decorator->image == NULL)
1093 continue;
1094
1095 visible = 0;
1096 if (!editor) {
1097 for (int j=0; j<array_size(systems_stack) && visible==0; j++) {
1098 const StarSystem *sys = system_getIndex( j );
1099
1100 if (sys_isFlag(sys, SYSTEM_HIDDEN))
1101 continue;
1102
1103 if (!sys_isKnown(sys))
1104 continue;
1105
1106 if ((decorator->x < sys->pos.x + decorator->detection_radius) &&
1107 (decorator->x > sys->pos.x - decorator->detection_radius) &&
1108 (decorator->y < sys->pos.y + decorator->detection_radius) &&
1109 (decorator->y > sys->pos.y - decorator->detection_radius)) {
1110 visible = 1;
1111 }
1112 }
1113 }
1114
1115 if (editor || visible==1) {
1116 double tx = x + decorator->x*zoom;
1117 double ty = y + decorator->y*zoom;
1118
1119 int sw = decorator->image->sw*zoom;
1120 int sh = decorator->image->sh*zoom;
1121
1122 gl_renderScale( decorator->image,
1123 tx - sw*0.5, ty - sh*0.5, sw, sh, &ccol );
1124 }
1125 }
1126}
1127
1131void map_renderFactionDisks( double x, double y, double zoom, double r, int editor, double alpha )
1132{
1133 for (int i=0; i<array_size(systems_stack); i++) {
1134 glColour c;
1135 double tx, ty;
1136 StarSystem *sys = system_getIndex( i );
1137
1138 if (sys_isFlag(sys,SYSTEM_HIDDEN))
1139 continue;
1140
1141 if ((!sys_isFlag(sys, SYSTEM_HAS_KNOWN_LANDABLE) || !sys_isKnown(sys)) && !editor)
1142 continue;
1143
1144 tx = x + sys->pos.x*zoom;
1145 ty = y + sys->pos.y*zoom;
1146
1147 /* System has faction and is known or we are in editor. */
1148 if (sys->faction != -1) {
1149 const glColour *col;
1150 double presence = sqrt(sys->ownerpresence);
1151
1152 /* draws the disk representing the faction */
1153 double sr = (40. + presence * 3.) * zoom * 0.5;
1154
1155 col = faction_colour(sys->faction);
1156 c.r = col->r;
1157 c.g = col->g;
1158 c.b = col->b;
1159 c.a = 0.6 * alpha;
1160
1161 glUseProgram(shaders.factiondisk.program);
1162 glUniform1f(shaders.factiondisk.paramf, r / sr );
1163 gl_renderShader( tx, ty, sr, sr, 0., &shaders.factiondisk, &c, 1 );
1164 }
1165 }
1166}
1167
1171void map_renderSystemEnvironment( double x, double y, double zoom, int editor, double alpha )
1172{
1173 for (int i=0; i<array_size(systems_stack); i++) {
1174 double tx, ty;
1175 /* Fade in the disks to allow toggling between commodity and nothing */
1176 StarSystem *sys = system_getIndex( i );
1177
1178 if (sys_isFlag(sys,SYSTEM_HIDDEN))
1179 continue;
1180
1181 if (!sys_isKnown(sys) && !editor)
1182 continue;
1183
1184 tx = x + sys->pos.x*zoom;
1185 ty = y + sys->pos.y*zoom;
1186
1187 /* Draw background. */
1188 /* TODO draw asteroids too! */
1189 if (sys->nebu_density > 0.) {
1190 mat4 projection;
1191 double sw, sh;
1192 sw = (50. + sys->nebu_density * 50. / 1000.) * zoom;
1193 sh = sw;
1194
1195 /* Set the vertex. */
1196 projection = gl_view_matrix;
1197 mat4_translate( &projection, tx-sw/2., ty-sh/2., 0. );
1198 mat4_scale( &projection, sw, sh, 1. );
1199
1200 /* Start the program. */
1201 glUseProgram(shaders.nebula_map.program);
1202
1203 /* Set shader uniforms. */
1204 glUniform1f(shaders.nebula_map.hue, sys->nebu_hue);
1205 glUniform1f(shaders.nebula_map.alpha, alpha);
1206 gl_uniformMat4(shaders.nebula_map.projection, &projection);
1207 glUniform1f(shaders.nebula_map.time, map_dt / 10.0);
1208 glUniform2f(shaders.nebula_map.globalpos, sys->pos.x, sys->pos.y );
1209 glUniform1f(shaders.nebula_map.volatility, sys->nebu_volatility );
1210
1211 /* Draw. */
1212 glEnableVertexAttribArray( shaders.nebula_map.vertex );
1213 gl_vboActivateAttribOffset( gl_squareVBO, shaders.nebula_map.vertex, 0, 2, GL_FLOAT, 0 );
1214 glDrawArrays( GL_TRIANGLE_STRIP, 0, 4 );
1215
1216 /* Clean up. */
1217 glDisableVertexAttribArray( shaders.nebula_map.vertex );
1218 glUseProgram(0);
1219 gl_checkErr();
1220 }
1221 else if (sys->map_shader != NULL) {
1222 mat4 projection;
1223 double sw, sh;
1224 sw = 100. * zoom;
1225 sh = sw;
1226
1227 /* Set the vertex. */
1228 projection = gl_view_matrix;
1229 mat4_translate( &projection, tx-sw/2., ty-sh/2., 0. );
1230 mat4_scale( &projection, sw, sh, 1. );
1231
1232 /* Start the program. */
1233 glUseProgram( sys->ms->program );
1234
1235 /* Set shader uniforms. */
1236 gl_uniformMat4(sys->ms->projection, &projection);
1237 glUniform1f(sys->ms->time, map_dt);
1238 glUniform2f(sys->ms->globalpos, sys->pos.x, sys->pos.y );
1239 glUniform1f(sys->ms->alpha, alpha);
1240
1241 /* Draw. */
1242 glEnableVertexAttribArray( sys->ms->vertex );
1243 gl_vboActivateAttribOffset( gl_squareVBO, sys->ms->vertex, 0, 2, GL_FLOAT, 0 );
1244 glDrawArrays( GL_TRIANGLE_STRIP, 0, 4 );
1245
1246 /* Clean up. */
1247 glDisableVertexAttribArray( sys->ms->vertex );
1248 glUseProgram(0);
1249 gl_checkErr();
1250 }
1251 }
1252}
1253
1257void map_renderJumps( double x, double y, double zoom, double radius, int editor )
1258{
1259 for (int i=0; i<array_size(systems_stack); i++) {
1260 double x1,y1;
1261 StarSystem *sys = system_getIndex( i );
1262
1263 if (sys_isFlag(sys,SYSTEM_HIDDEN))
1264 continue;
1265
1266 if (!sys_isKnown(sys) && !editor)
1267 continue; /* we don't draw hyperspace lines */
1268
1269 x1 = x + sys->pos.x * zoom;
1270 y1 = y + sys->pos.y * zoom;
1271
1272 for (int j=0; j < array_size(sys->jumps); j++) {
1273 double x2,y2, rx,ry, r, rw,rh;
1274 const glColour *col, *cole;
1275 StarSystem *jsys = sys->jumps[j].target;
1276 if (sys_isFlag(jsys,SYSTEM_HIDDEN))
1277 continue;
1278 if (!space_sysReachableFromSys(jsys,sys) && !editor)
1279 continue;
1280
1281 /* Choose colours. */
1282 cole = &cAquaBlue;
1283 for (int k=0; k < array_size(jsys->jumps); k++) {
1284 if (jsys->jumps[k].target == sys) {
1285 if (jp_isFlag(&jsys->jumps[k], JP_EXITONLY))
1286 cole = &cGrey80;
1287 else if (jp_isFlag(&jsys->jumps[k], JP_HIDDEN))
1288 cole = &cRed;
1289 break;
1290 }
1291 }
1292 if (jp_isFlag(&sys->jumps[j], JP_EXITONLY))
1293 col = &cGrey80;
1294 else if (jp_isFlag(&sys->jumps[j], JP_HIDDEN))
1295 col = &cRed;
1296 else
1297 col = &cAquaBlue;
1298
1299 x2 = x + jsys->pos.x * zoom;
1300 y2 = y + jsys->pos.y * zoom;
1301 rx = x2-x1;
1302 ry = y2-y1;
1303 r = atan2( ry, rx );
1304 rw = MOD(rx,ry)/2.;
1305
1306 if (sys->jumps[j].hide<=0.) {
1307 col = &cGreen;
1308 rh = 2.5;
1309 }
1310 else {
1311 rh = 1.5;
1312 }
1313
1314 glUseProgram( shaders.jumplane.program );
1315 gl_uniformColour( shaders.jumplane.paramv, cole );
1316 glUniform1f( shaders.jumplane.paramf, radius );
1317 gl_renderShader( (x1+x2)/2., (y1+y2)/2., rw, rh, r, &shaders.jumplane, col, 1 );
1318 }
1319 }
1320}
1321
1325void map_renderSystems( double bx, double by, double x, double y,
1326 double zoom, double w, double h, double r, MapMode mode )
1327{
1328 for (int i=0; i<array_size(systems_stack); i++) {
1329 double tx, ty;
1330 StarSystem *sys = system_getIndex( i );
1331
1332 if (sys_isFlag(sys,SYSTEM_HIDDEN))
1333 continue;
1334
1335 /* if system is not known, reachable, or marked. and we are not in the editor */
1336 if ((!sys_isKnown(sys) && !sys_isFlag(sys, SYSTEM_MARKED | SYSTEM_CMARKED)
1337 && !space_sysReachable(sys)) && mode != MAPMODE_EDITOR)
1338 continue;
1339
1340 tx = x + sys->pos.x*zoom;
1341 ty = y + sys->pos.y*zoom;
1342
1343 /* Skip if out of bounds. */
1344 if (!rectOverlap(tx-r, ty-r, 2.*r, 2.*r, bx, by, w, h))
1345 continue;
1346
1347 /* Draw an outer ring. */
1348 if (mode == MAPMODE_EDITOR || mode == MAPMODE_TRAVEL || mode == MAPMODE_TRADE)
1349 gl_renderCircle( tx, ty, r, &cInert, 0 );
1350
1351 /* Ignore not known systems when not in the editor. */
1352 if (mode != MAPMODE_EDITOR && !sys_isKnown(sys))
1353 continue;
1354
1355 if (mode == MAPMODE_EDITOR || mode == MAPMODE_TRAVEL || mode == MAPMODE_TRADE) {
1356 const glColour *col;
1357 if (!system_hasSpob(sys))
1358 continue;
1359 if (!sys_isFlag(sys, SYSTEM_HAS_KNOWN_LANDABLE) && mode != MAPMODE_EDITOR)
1360 continue;
1361 /* Spob colours */
1362 if (mode != MAPMODE_EDITOR && !sys_isKnown(sys))
1363 col = &cInert;
1364 else if (sys->faction < 0)
1365 col = &cInert;
1366 else if (mode == MAPMODE_EDITOR)
1367 col = &cNeutral;
1368 else if (areEnemies(FACTION_PLAYER,sys->faction))
1369 col = &cHostile;
1370 else if (!sys_isFlag(sys, SYSTEM_HAS_LANDABLE))
1371 col = &cRestricted;
1372 else if (areAllies(FACTION_PLAYER,sys->faction))
1373 col = &cFriend;
1374 else
1375 col = &cNeutral;
1376
1377 if (mode == MAPMODE_EDITOR) {
1378 /* Radius slightly shorter. */
1379 gl_renderCircle( tx, ty, 0.5 * r, col, 1 );
1380 }
1381 else
1382 gl_renderCircle( tx, ty, 0.65 * r, col, 1 );
1383 }
1384 else if (mode == MAPMODE_DISCOVER) {
1385 gl_renderCircle( tx, ty, r, &cInert, 0 );
1386 if (sys_isFlag( sys, SYSTEM_DISCOVERED ))
1387 gl_renderCircle( tx, ty, 0.65 * r, &cGreen, 1 );
1388 }
1389 }
1390}
1391
1395static void map_renderPath( double x, double y, double zoom, double radius, double alpha )
1396{
1397 StarSystem *sys1 = cur_system;
1398 int jmax, jcur;
1399
1400 if (array_size(map_path) == 0)
1401 return;
1402
1403 /* Player must exist. */
1404 if (player.p==NULL)
1405 return;
1406
1407 jmax = pilot_getJumps(player.p); /* Maximum jumps. */
1408 jcur = jmax; /* Jump range remaining. */
1409
1410 for (int j=0; j<array_size(map_path); j++) {
1411 glColour col;
1412 double x1,y1, x2,y2, rx,ry, rw,rh, r;
1413 StarSystem *sys2 = map_path[j];
1414 if (sys_isFlag(sys1,SYSTEM_HIDDEN) || sys_isFlag(sys2,SYSTEM_HIDDEN))
1415 continue;
1416 if (jcur == jmax && jmax > 0)
1417 col = cGreen;
1418 else if (jcur < 1)
1419 col = cRed;
1420 else
1421 col = cYellow;
1422 col.a = alpha;
1423
1424 x1 = x + sys1->pos.x * zoom;
1425 y1 = y + sys1->pos.y * zoom;
1426 x2 = x + sys2->pos.x * zoom;
1427 y2 = y + sys2->pos.y * zoom;
1428 rx = x2-x1;
1429 ry = y2-y1;
1430 r = atan2( ry, rx );
1431 rw = (MOD(rx,ry)+radius)/2.;
1432 rh = 5.;
1433
1434 glUseProgram( shaders.jumplanegoto.program );
1435 glUniform1f( shaders.jumplanegoto.dt, map_dt );
1436 glUniform1f( shaders.jumplanegoto.paramf, radius );
1437 glUniform1i( shaders.jumplanegoto.parami, (jcur >= 1) );
1438 gl_renderShader( (x1+x2)/2., (y1+y2)/2., rw, rh, r, &shaders.jumplanegoto, &col, 1 );
1439
1440 jcur--;
1441 sys1 = sys2;
1442 }
1443}
1444
1448void map_renderNotes( double bx, double by, double x, double y,
1449 double zoom, double w, double h, int editor, double alpha )
1450{
1451 (void) w;
1452 (void) h;
1453
1454 if ((zoom <= 0.5) || editor)
1455 return;
1456
1457 if (map_show_notes)
1458 glClear( GL_DEPTH_BUFFER_BIT );
1459
1460 /* Find mouse over system and draw. */
1461 for (int i=0; i<array_size(systems_stack); i++) {
1462 double tx,ty, tw,th;
1463 glColour col;
1464 glFont *font;
1465 StarSystem *sys = &systems_stack[i];
1466
1467 if (!sys_isFlag(sys,SYSTEM_PMARKED))
1468 continue;
1469
1470 if (sys->note == NULL)
1471 continue;
1472
1473 /* Set up position. */
1474 tx = x + sys->pos.x*zoom;
1475 ty = y + sys->pos.y*zoom;
1476
1477 /* Mouse is over. */
1478 if (!map_show_notes && ((pow2(tx-map_mx-bx)+pow2(ty-map_my-by)) > pow2(MAP_MOVE_THRESHOLD)))
1479 continue;
1480
1481 if (!map_show_notes)
1482 glClear( GL_DEPTH_BUFFER_BIT );
1483
1484 font = (zoom >= 1.5) ? &gl_defFont : &gl_smallFont;
1485 tx += 12.*zoom;
1486 ty -= font->h*2.;
1487 tw = gl_printWidthRaw( font, sys->note )+8.;
1488 th = font->h+8.;
1489
1490 /* Background. */
1491 col = cBlack;
1492 col.a = alpha*0.8;
1493 gl_renderRect( tx-4., ty-4., tw, th, &col );
1494
1495 /* Render note */
1496 col = cFontOrange;
1497 col.a = alpha;
1498 gl_printRaw( font, tx, ty, &col, -1, sys->note );
1499 }
1500}
1501
1505void map_renderNames( double bx, double by, double x, double y,
1506 double zoom, double w, double h, int editor, double alpha )
1507{
1508 double tx,ty, vx,vy, d,n;
1509 int textw;
1510 char buf[32];
1511 glColour col;
1512 glFont *font;
1513
1514 if (zoom <= 0.5)
1515 return;
1516
1517 for (int i=0; i<array_size(systems_stack); i++) {
1518 StarSystem *sys = system_getIndex( i );
1519
1520 if (sys_isFlag(sys,SYSTEM_HIDDEN))
1521 continue;
1522
1523 /* Skip system. */
1524 if (!editor && !sys_isKnown(sys))
1525 continue;
1526
1527 font = (zoom >= 1.5) ? &gl_defFont : &gl_smallFont;
1528
1529 textw = gl_printWidthRaw( font, _(sys->name) );
1530 tx = x + (sys->pos.x+12.) * zoom;
1531 ty = y + (sys->pos.y) * zoom - font->h*0.5;
1532
1533 /* Skip if out of bounds. */
1534 if (!rectOverlap(tx, ty, textw, font->h, bx, by, w, h))
1535 continue;
1536
1537 col = cWhite;
1538 col.a = alpha;
1539 gl_printRaw( font, tx, ty, &col, -1, _(sys->name) );
1540 }
1541
1542 /* Raw hidden values if we're in the editor. */
1543 if (!editor || (zoom <= 1.0))
1544 return;
1545
1546 for (int i=0; i<array_size(systems_stack); i++) {
1547 StarSystem *sys = system_getIndex( i );
1548 for (int j=0; j<array_size(sys->jumps); j++) {
1549 StarSystem *jsys = sys->jumps[j].target;
1550 /* Calculate offset. */
1551 vx = jsys->pos.x - sys->pos.x;
1552 vy = jsys->pos.y - sys->pos.y;
1553 n = sqrt( pow2(vx) + pow2(vy) );
1554 vx /= n;
1555 vy /= n;
1556 d = MAX(n*0.3*zoom, 15);
1557 tx = x + zoom*sys->pos.x + d*vx;
1558 ty = y + zoom*sys->pos.y + d*vy;
1559 /* Display. */
1560 n = sys->jumps[j].hide;
1561 if (n == 0.)
1562 snprintf( buf, sizeof(buf), "#gH: %.2f", n );
1563 else
1564 snprintf( buf, sizeof(buf), "H: %.2f", n );
1565 col = cGrey70;
1566 col.a = alpha;
1567 gl_printRaw( &gl_smallFont, tx, ty, &col, -1, buf );
1568 }
1569 }
1570}
1571
1575static void map_renderMarkers( double x, double y, double zoom, double r, double a )
1576{
1577 for (int i=0; i<array_size(systems_stack); i++) {
1578 double tx, ty;
1579 int j, n, m;
1580 StarSystem *sys = system_getIndex( i );
1581
1582 /* We only care about marked now. */
1583 if (!sys_isFlag(sys, SYSTEM_MARKED | SYSTEM_CMARKED | SYSTEM_PMARKED))
1584 continue;
1585
1586 /* Get the position. */
1587 tx = x + sys->pos.x*zoom;
1588 ty = y + sys->pos.y*zoom;
1589
1590 /* Count markers. */
1591 n = (sys_isFlag(sys, SYSTEM_CMARKED)) ? 1 : 0;
1592 n += (sys_isFlag(sys, SYSTEM_PMARKED)) ? 1 : 0;
1593 n += sys->markers_plot;
1594 n += sys->markers_high;
1595 n += sys->markers_low;
1596 n += sys->markers_computer;
1597
1598 /* Draw the markers. */
1599 j = 0;
1600 if (sys_isFlag(sys, SYSTEM_PMARKED)) { /* Notes have be first. */
1601 map_drawMarker( tx, ty, zoom, r, a, n, j, 5 );
1602 j++;
1603 }
1604 if (sys_isFlag(sys, SYSTEM_CMARKED)) {
1605 map_drawMarker( tx, ty, zoom, r, a, n, j, 0 );
1606 j++;
1607 }
1608 for (m=0; m<sys->markers_plot; m++) {
1609 map_drawMarker( tx, ty, zoom, r, a, n, j, 1 );
1610 j++;
1611 }
1612 for (m=0; m<sys->markers_high; m++) {
1613 map_drawMarker( tx, ty, zoom, r, a, n, j, 2 );
1614 j++;
1615 }
1616 for (m=0; m<sys->markers_low; m++) {
1617 map_drawMarker( tx, ty, zoom, r, a, n, j, 3 );
1618 j++;
1619 }
1620 for (m=0; m<sys->markers_computer; m++) {
1621 map_drawMarker( tx, ty, zoom, r, a, n, j, 4 );
1622 j++;
1623 }
1624 }
1625}
1626
1627/*
1628 * Makes all systems dark grey.
1629 */
1630static void map_renderSysBlack( double bx, double by, double x, double y, double zoom, double w, double h, double r, int editor )
1631{
1632 for (int i=0; i<array_size(systems_stack); i++) {
1633 double tx,ty;
1634 glColour ccol;
1635 StarSystem *sys = system_getIndex( i );
1636
1637 if (sys_isFlag(sys,SYSTEM_HIDDEN))
1638 continue;
1639
1640 /* if system is not known, reachable, or marked. and we are not in the editor */
1641 if ((!sys_isKnown(sys) && !sys_isFlag(sys, SYSTEM_MARKED | SYSTEM_CMARKED)
1642 && !space_sysReachable(sys)) && !editor)
1643 continue;
1644
1645 tx = x + sys->pos.x*zoom;
1646 ty = y + sys->pos.y*zoom;
1647
1648 /* Skip if out of bounds. */
1649 if (!rectOverlap(tx - r, ty - r, r, r, bx, by, w, h))
1650 continue;
1651
1652 /* If system is known fill it. */
1653 if ((sys_isKnown(sys)) && (system_hasSpob(sys))) {
1654 ccol = cGrey10;
1655 gl_renderCircle( tx, ty, r, &ccol, 1 );
1656 }
1657 }
1658}
1659
1660/*
1661 * Renders the economy information
1662 */
1663void map_renderCommod( double bx, double by, double x, double y,
1664 double zoom, double w, double h, double r, int editor, double a )
1665{
1666 Commodity *c;
1667 glColour ccol;
1668
1669 /* If not plotting commodities, return */
1670 if ((cur_commod == -1) || (map_selected == -1) || (commod_known == NULL))
1671 return;
1672
1673 c = commod_known[cur_commod];
1674 if (cur_commod_mode == 1) { /*showing price difference to selected system*/
1675 double curMaxPrice, curMinPrice;
1676 StarSystem *sys = system_getIndex( map_selected );
1677 /* Get commodity price in selected system. If selected system is current
1678 system, and if landed, then get price of commodity where we are */
1679 curMaxPrice = 0.;
1680 curMinPrice = 0.;
1681 if (sys == cur_system && landed) {
1682 int k;
1683 for (k=0; k<array_size(land_spob->commodities); k++) {
1684 if (land_spob->commodities[k] == c) {
1685 /* current spob has the commodity of interest */
1686 curMinPrice = land_spob->commodityPrice[k].sum / land_spob->commodityPrice[k].cnt;
1687 curMaxPrice = curMinPrice;
1688 break;
1689 }
1690 }
1691 if (k==array_size(land_spob->commodities)) { /* commodity of interest not found */
1692 map_renderCommodIgnorance( x, y, zoom, sys, c, a );
1693 map_renderSysBlack( bx, by, x, y, zoom, w, h, r, editor );
1694 return;
1695 }
1696 }
1697 else {
1698 /* not currently landed, so get max and min price in the selected system. */
1699 if ((sys_isKnown(sys)) && (system_hasSpob(sys))) {
1700 double minPrice = HUGE_VAL;
1701 double maxPrice = 0;
1702 for (int j=0; j<array_size(sys->spobs); j++) {
1703 Spob *p = sys->spobs[j];
1704 for (int k=0; k<array_size(p->commodities); k++) {
1705 double thisPrice;
1706 if (p->commodities[k] != c)
1707 continue;
1708 if (p->commodityPrice[k].cnt <= 0) /* commodity is not known about */
1709 continue;
1710 thisPrice = p->commodityPrice[k].sum / p->commodityPrice[k].cnt;
1711 maxPrice = MAX( thisPrice, maxPrice );
1712 minPrice = MIN( thisPrice, minPrice );
1713 break;
1714 }
1715
1716 }
1717 if (maxPrice == 0) { /* no prices are known here */
1718 map_renderCommodIgnorance( x, y, zoom, sys, c, a );
1719 map_renderSysBlack( bx, by, x, y, zoom, w, h, r, editor );
1720 return;
1721 }
1722 curMaxPrice = maxPrice;
1723 curMinPrice = minPrice;
1724 }
1725 else {
1726 map_renderCommodIgnorance( x, y, zoom, sys, c, a );
1727 map_renderSysBlack( bx, by, x, y, zoom, w, h, r, editor );
1728 return;
1729 }
1730 }
1731 for (int i=0; i<array_size(systems_stack); i++) {
1732 double tx, ty;
1733 sys = system_getIndex( i );
1734
1735 if (sys_isFlag(sys,SYSTEM_HIDDEN))
1736 continue;
1737
1738 /* if system is not known, reachable, or marked. and we are not in the editor */
1739 if ((!sys_isKnown(sys) && !sys_isFlag(sys, SYSTEM_MARKED | SYSTEM_CMARKED)
1740 && !space_sysReachable(sys)) && !editor)
1741 continue;
1742
1743 tx = x + sys->pos.x*zoom;
1744 ty = y + sys->pos.y*zoom;
1745
1746 /* Skip if out of bounds. */
1747 if (!rectOverlap(tx - r, ty - r, r, r, bx, by, w, h))
1748 continue;
1749
1750 /* If system is known fill it. */
1751 if ((sys_isKnown(sys)) && (system_hasSpob(sys))) {
1752 double minPrice = HUGE_VAL;
1753 double maxPrice = 0;
1754 for (int j=0; j<array_size(sys->spobs); j++) {
1755 Spob *p = sys->spobs[j];
1756 for (int k=0; k<array_size(p->commodities); k++) {
1757 double thisPrice;
1758 if (p->commodities[k] != c)
1759 continue;
1760 if (p->commodityPrice[k].cnt <= 0) /*commodity is not known about */
1761 continue;
1762 thisPrice = p->commodityPrice[k].sum / p->commodityPrice[k].cnt;
1763 maxPrice = MAX( thisPrice, maxPrice );
1764 minPrice = MIN( thisPrice, minPrice );
1765 break;
1766 }
1767 }
1768
1769 /* Calculate best and worst profits */
1770 if (maxPrice > 0) {
1771 /* Commodity sold at this system */
1772 double best = maxPrice - curMinPrice;
1773 double worst= minPrice - curMaxPrice;
1774 if (best >= 0) { /* draw circle above */
1775 ccol = cLightBlue;
1776 ccol.a = a;
1777 gl_print(&gl_smallFont, x + (sys->pos.x+11) * zoom, y + (sys->pos.y-22)*zoom, &ccol, "%.1f",best);
1778 best = tanh ( 2*best / curMinPrice );
1779 col_blend( &ccol, &cFontBlue, &cFontYellow, best );
1780 ccol.a = a;
1781 gl_renderCircle( tx, ty /*+ r*/ , /*(0.1 + best) **/ r, &ccol, 1 );
1782 }
1783 else {/* draw circle below */
1784 ccol = cOrange;
1785 ccol.a = a;
1786 gl_print(&gl_smallFont, x + (sys->pos.x+12) * zoom, y + (sys->pos.y)*zoom-gl_smallFont.h*0.5, &ccol, _("%.1f ¤"),worst);
1787 worst = tanh ( -2*worst/ curMaxPrice );
1788 col_blend( &ccol, &cFontOrange, &cFontYellow, worst );
1789 ccol.a = a;
1790 gl_renderCircle( tx, ty /*- r*/ , /*(0.1 - worst) **/ r, &ccol, 1 );
1791 }
1792 }
1793 else {
1794 /* Commodity not sold here */
1795 ccol = cGrey10;
1796 ccol.a = a;
1797 gl_renderCircle( tx, ty, r, &ccol, 1 );
1798 }
1799 }
1800 }
1801 }
1802 else { /* cur_commod_mode == 0, showing actual prices */
1803 /* First calculate av price in all systems
1804 * This has already been done in map_update_commod_av_price
1805 * Now display the costs */
1806 for (int i=0; i<array_size(systems_stack); i++) {
1807 double tx, ty;
1808 StarSystem *sys = system_getIndex( i );
1809
1810 if (sys_isFlag(sys,SYSTEM_HIDDEN))
1811 continue;
1812
1813 /* if system is not known, reachable, or marked. and we are not in the editor */
1814 if ((!sys_isKnown(sys) && !sys_isFlag(sys, SYSTEM_MARKED | SYSTEM_CMARKED)
1815 && !space_sysReachable(sys)) && !editor)
1816 continue;
1817
1818 tx = x + sys->pos.x*zoom;
1819 ty = y + sys->pos.y*zoom;
1820
1821 /* Skip if out of bounds. */
1822 if (!rectOverlap(tx - r, ty - r, r, r, bx, by, w, h))
1823 continue;
1824
1825 /* If system is known fill it. */
1826 if ((sys_isKnown(sys)) && (system_hasSpob(sys))) {
1827 double sumPrice = 0;
1828 int sumCnt = 0;
1829 for (int j=0; j<array_size(sys->spobs); j++) {
1830 Spob *p = sys->spobs[j];
1831 for (int k=0; k<array_size(p->commodities); k++) {
1832 double thisPrice;
1833 if (p->commodities[k] != c)
1834 continue;
1835 if (p->commodityPrice[k].cnt <= 0) /* commodity is not known about */
1836 continue;
1837 thisPrice = p->commodityPrice[k].sum / p->commodityPrice[k].cnt;
1838 sumPrice += thisPrice;
1839 sumCnt += 1;
1840 break;
1841 }
1842 }
1843
1844 if (sumCnt > 0) {
1845 /* Commodity sold at this system */
1846 /* Colour as a % of global average */
1847 double frac;
1848 sumPrice /= sumCnt;
1849 if (sumPrice < commod_av_gal_price) {
1850 frac = tanh(5*(commod_av_gal_price / sumPrice - 1));
1851 col_blend( &ccol, &cFontOrange, &cFontYellow, frac );
1852 }
1853 else {
1854 frac = tanh(5*(sumPrice / commod_av_gal_price - 1));
1855 col_blend( &ccol, &cFontBlue, &cFontYellow, frac );
1856 }
1857 ccol.a = a;
1858 gl_print(&gl_smallFont, x + (sys->pos.x+12)*zoom, y + (sys->pos.y)*zoom - gl_smallFont.h*0.5, &ccol, _("%.1f ¤"),sumPrice);
1859 gl_renderCircle( tx, ty, r, &ccol, 1 );
1860 }
1861 else {
1862 /* Commodity not sold here */
1863 ccol = cGrey10;
1864 ccol.a = a;
1865 gl_renderCircle( tx, ty, r, &ccol, 1 );
1866 }
1867 }
1868 }
1869 }
1870}
1871
1872/*
1873 * Renders the economy information.
1874 */
1875static void map_renderCommodIgnorance( double x, double y, double zoom,
1876 const StarSystem *sys, const Commodity *c, double a )
1877{
1878 int textw;
1879 char buf[80], *line2;
1880 size_t charn;
1881 glColour col = cFontRed;
1882 col.a = a;
1883
1884 snprintf( buf, sizeof(buf), _("No price info for\n%s here"), _(c->name) );
1885 line2 = u8_strchr( buf, '\n', &charn );
1886 if (line2 != NULL) {
1887 *line2++ = '\0';
1888 textw = gl_printWidthRaw( &gl_smallFont, line2 );
1889 gl_printRaw( &gl_smallFont, x + (sys->pos.x)*zoom - textw*0.5, y + (sys->pos.y-15.)*zoom, &col, -1, line2 );
1890 }
1891 textw = gl_printWidthRaw( &gl_smallFont, buf );
1892 gl_printRaw( &gl_smallFont,x + sys->pos.x *zoom- textw*0.5, y + (sys->pos.y+10.)*zoom, &col, -1, buf );
1893}
1894
1895static int factionPresenceCompare( const void *a, const void *b )
1896{
1897 FactionPresence *fpa, *fpb;
1898 fpa = (FactionPresence*) a;
1899 fpb = (FactionPresence*) b;
1900 if (fpa->value < fpb->value)
1901 return 1;
1902 else if (fpb->value < fpa->value)
1903 return -1;
1904 return strcmp( fpa->name, fpb->name );
1905}
1915void map_updateFactionPresence( const unsigned int wid, const char *name, const StarSystem *sys, int omniscient )
1916{
1917 size_t l;
1918 char buf[STRMAX_SHORT] = {'\0'};
1919 FactionPresence *presence;
1920
1921 /* Build the faction presence array. */
1922 presence = array_create( FactionPresence );
1923 for (int i=0; i<array_size(sys->presence); i++) {
1924 int matched;
1925 FactionPresence fp;
1926 if (sys->presence[i].value <= 0.)
1927 continue;
1928
1929 /* Determine properties. */
1930 fp.known = 1;
1931 if (!omniscient && !faction_isKnown( sys->presence[i].faction )) {
1932 fp.name = N_("Unknown");
1933 fp.known = 0;
1934 }
1935 else if (omniscient)
1936 fp.name = faction_name( sys->presence[i].faction );
1937 else
1938 fp.name = faction_mapname( sys->presence[i].faction );
1939 fp.value = sys->presence[i].value;
1940
1941 /* Try to add to existing. */
1942 matched = 0;
1943 for (int j=0; j<array_size(presence); j++) {
1944 if (strcmp(fp.name,presence[j].name)==0) {
1945 presence[j].value += fp.value;
1946 matched = 1;
1947 break;
1948 }
1949 }
1950 /* Insert new. */
1951 if (!matched)
1952 array_push_back( &presence, fp );
1953 }
1954 qsort( presence, array_size(presence), sizeof(FactionPresence), factionPresenceCompare );
1955
1956 l = 0;
1957 for (int i=0; i<array_size(presence); i++) {
1958 char col;
1959 FactionPresence *p = &presence[i];
1960 if (faction_exists( p->name ))
1961 col = faction_getColourChar( faction_get(p->name) );
1962 else
1963 col = 'N';
1964
1965 /* Use map grey instead of default neutral colour */
1966 l += scnprintf( &buf[l], sizeof(buf) - l, "%s#0%s: #%c%.0f", (l==0) ? "" : "\n",
1967 _(p->name), col, p->value );
1968 }
1969
1970 if (array_size(presence)==0)
1971 snprintf( buf, sizeof(buf), _("None") );
1972
1973 window_modifyText( wid, name, buf );
1974
1975 /* Cleanup. */
1976 array_free(presence);
1977}
1978
1982static void map_focusLose( unsigned int wid, const char* wgtname )
1983{
1984 (void) wgtname;
1985 CstMapWidget *cst = map_globalCustomData( wid );
1986 cst->drag = 0;
1987}
1988
1999static int map_mouse( unsigned int wid, const SDL_Event* event, double mx, double my,
2000 double w, double h, double rx, double ry, void *data )
2001{
2002 (void) rx;
2003 (void) ry;
2004 CstMapWidget *cst = data;
2005
2006 const double t = 15.*15.; /* threshold */
2007
2008 switch (event->type) {
2009 case SDL_MOUSEWHEEL:
2010 /* Must be in bounds. */
2011 if ((mx < 0.) || (mx > w) || (my < 0.) || (my > h))
2012 return 0;
2013 if (event->wheel.y > 0)
2014 map_buttonZoom( wid, "btnZoomIn" );
2015 else if (event->wheel.y < 0)
2016 map_buttonZoom( wid, "btnZoomOut" );
2017 return 1;
2018
2019 case SDL_MOUSEBUTTONDOWN:
2020 /* Must be in bounds. */
2021 if ((mx < 0.) || (mx > w) || (my < 0.) || (my > h))
2022 return 0;
2023 window_setFocus( wid, "cstMap" );
2024
2025 /* selecting star system */
2026 mx -= w/2 - cst->xpos;
2027 my -= h/2 - cst->ypos;
2028 cst->drag = 1;
2029
2030 for (int i=0; i<array_size(systems_stack); i++) {
2031 double x, y;
2032 StarSystem *sys = system_getIndex( i );
2033
2034 if (sys_isFlag(sys, SYSTEM_HIDDEN))
2035 continue;
2036
2037 /* must be reachable */
2038 if (!sys_isFlag(sys, SYSTEM_MARKED | SYSTEM_CMARKED)
2039 && !space_sysReachable(sys))
2040 continue;
2041
2042 /* get position */
2043 x = sys->pos.x * cst->zoom;
2044 y = sys->pos.y * cst->zoom;
2045
2046 if ((pow2(mx-x)+pow2(my-y)) < t) {
2047 if (map_selected != -1) {
2048 if (sys == system_getIndex( map_selected ) && sys_isKnown(sys)) {
2049 map_system_open( map_selected );
2050 cst->drag = 0;
2051 }
2052 }
2053 map_select( sys, (SDL_GetModState() & KMOD_SHIFT) );
2054 break;
2055 }
2056 }
2057 return 1;
2058
2059 case SDL_MOUSEBUTTONUP:
2060 cst->drag = 0;
2061 break;
2062
2063 case SDL_MOUSEMOTION:
2064 if (cst->drag) {
2065 /* axis is inverted */
2066 cst->xtarget = cst->xpos -= rx;
2067 cst->ytarget = cst->ypos += ry;
2068 }
2069 map_mx = mx;
2070 map_my = my;
2071 break;
2072 }
2073
2074 return 0;
2075}
2082static void map_buttonZoom( unsigned int wid, const char* str )
2083{
2084 CstMapWidget *cst = map_globalCustomData(wid);
2085
2086 /* Transform coords to normal. */
2087 cst->xpos /= cst->zoom;
2088 cst->ypos /= cst->zoom;
2089 cst->xtarget /= cst->zoom;
2090 cst->ytarget /= cst->zoom;
2091
2092 /* Apply zoom. */
2093 if (strcmp(str,"btnZoomIn")==0) {
2094 cst->zoom *= 1.2;
2095 cst->zoom = MIN(2.5, cst->zoom);
2096 }
2097 else if (strcmp(str,"btnZoomOut")==0) {
2098 cst->zoom *= 0.8;
2099 cst->zoom = MAX(0.5, cst->zoom);
2100 }
2101
2102 map_setZoom( wid, cst->zoom );
2103
2104 /* Transform coords back. */
2105 cst->xpos *= cst->zoom;
2106 cst->ypos *= cst->zoom;
2107 cst->xtarget *= cst->zoom;
2108 cst->ytarget *= cst->zoom;
2109}
2110
2114static void map_genModeList(void)
2115{
2116 int totGot = 0;
2117 const char *odd_template, *even_template;
2118
2119 map_onClose( 0, NULL ); /* so commod_known, map_modes are freed */
2120 commod_known = calloc( commodity_getN(), sizeof(Commodity*) );
2121 for (int i=0; i<array_size(systems_stack); i++) {
2122 StarSystem *sys = system_getIndex( i );
2123 for (int j=0 ; j<array_size(sys->spobs); j++) {
2124 Spob *p = sys->spobs[j];
2125 for (int k=0; k<array_size(p->commodities); k++) {
2126 if (p->commodityPrice[k].cnt > 0 ) {/*commodity is known about*/
2127 int l;
2128 /* find out which commodity this is */
2129 for (l=0 ; l<totGot; l++) {
2130 if ( p->commodities[k] == commod_known[l] )
2131 break;
2132 }
2133 if (l == totGot) {
2134 commod_known[totGot] = p->commodities[k];
2135 totGot++;
2136 }
2137 }
2138 }
2139 }
2140 }
2141 map_modes = array_create_size( char*, 2*totGot + 1 );
2142 array_push_back( &map_modes, strdup(_("Travel (Default)")) );
2143 array_push_back( &map_modes, strdup(_("Discovery")) );
2144
2145 even_template = _("%s: Cost");
2146 odd_template = _("%s: Trade");
2147 for (int i=0; i<totGot; i++) {
2148 const char *commod_text = _(commod_known[i]->name);
2149 SDL_asprintf( &array_grow( &map_modes ), even_template, commod_text );
2150 SDL_asprintf( &array_grow( &map_modes ), odd_template, commod_text );
2151 }
2152}
2153
2160static void map_modeUpdate( unsigned int wid, const char* str )
2161{
2162 (void) str;
2163 if (listMapModeVisible==2) {
2164 listMapModeVisible=1;
2165 }
2166 else if (listMapModeVisible == 1) {
2167 int listpos = toolkit_getListPos( wid, "lstMapMode" );
2168 /* TODO: make this more robust. */
2169 if (listpos == 0) {
2170 map_mode = MAPMODE_TRAVEL;
2171 //cur_commod = -1;
2172 //cur_commod_mode = 0;
2173 }
2174 else if (listpos == 1) {
2175 map_mode = MAPMODE_DISCOVER;
2176 //cur_commod = -1;
2177 //cur_commod_mode = 0;
2178 }
2179 else {
2180 map_mode = MAPMODE_TRADE;
2181 cur_commod = (listpos - MAPMODE_TRADE) / 2;
2182 cur_commod_mode = (listpos - MAPMODE_TRADE) % 2 ; /* if 0, showing cost, if 1 showing difference */
2183 }
2184 }
2185 map_update(wid);
2186}
2187
2191static void map_modeActivate( unsigned int wid, const char* str )
2192{
2193 map_modeUpdate( wid, str );
2194 listMapModeVisible = 0;
2195 window_destroyWidget( wid, str );
2196}
2197
2198static void map_setMinimal( unsigned int wid, int value )
2199{
2200 map_minimal_mode = value;
2201 player.map_minimal = value;
2202 window_buttonCaption( wid, "btnMinimal", (value) ? _("Normal View") : _("Minimal View") );
2203}
2204
2208static void map_buttonMarkSystem( unsigned int wid, const char* str )
2209{
2210 (void) wid;
2211 (void) str;
2212 if (map_selected != -1) {
2213 StarSystem *sys = system_getIndex( map_selected );
2214
2215 /* Remove old note */
2216 if (sys->note != NULL) {
2217 free(sys->note);
2218 sys->note = NULL;
2219 }
2220
2221 /* Switch marking */
2222 if (sys_isFlag(sys, SYSTEM_PMARKED))
2223 sys_rmFlag(sys, SYSTEM_PMARKED);
2224 else {
2225 sys->note = dialogue_input(_("Add System Note"), 0, 60, _("Write a note about the #o%s#0 system:"), sys_isKnown(sys) ? _(sys->name) : _("Unknown") );
2226 if (sys->note != NULL)
2227 sys_setFlag(sys, SYSTEM_PMARKED);
2228 }
2229 }
2230}
2231
2235static void map_buttonSystemMap( unsigned int wid, const char* str )
2236{
2237 (void) wid;
2238 (void) str;
2239 if (map_selected != -1)
2240 if (sys_isKnown(system_getIndex( map_selected )))
2241 map_system_open( map_selected );
2242}
2243
2247static void map_buttonMinimal( unsigned int wid, const char* str )
2248{
2249 (void) str;
2250 map_setMinimal( wid, !map_minimal_mode );
2251}
2252
2259static void map_buttonCommodity( unsigned int wid, const char* str )
2260{
2261 (void) str;
2262 SDL_Keymod mods;
2263 char **this_map_modes;
2264 /* Clicking the mode button - by default will show (or remove) the list of map modes.
2265 If ctrl is pressed, will toggle between current mode and default */
2266 mods = SDL_GetModState();
2267 if (mods & (KMOD_LCTRL | KMOD_RCTRL)) {/* toggle on/off */
2268 static int cur_commod_last = 0;
2269 static int cur_commod_mode_last = 0;
2270 static int map_mode_last = MAPMODE_TRAVEL;
2271 if (map_mode == MAPMODE_TRAVEL) {
2272 map_mode = map_mode_last;
2273 cur_commod = cur_commod_last;
2274 if (cur_commod == -1)
2275 cur_commod = 0;
2276 cur_commod_mode = cur_commod_mode_last;
2277 }
2278 else {
2279 map_mode_last = map_mode;
2280 map_mode = MAPMODE_TRAVEL;
2281 cur_commod_last = cur_commod;
2282 cur_commod_mode_last = cur_commod_mode;
2283 cur_commod = -1;
2284 }
2285 if (cur_commod >= (array_size(map_modes)-1)/2 )
2286 cur_commod = -1;
2287 /* And hide the list if it was visible. */
2288 if (listMapModeVisible) {
2289 listMapModeVisible = 0;
2290 window_destroyWidget( wid, "lstMapMode" );
2291 }
2292 map_update(wid);
2293 }
2294 else { /* no keyboard modifier */
2295 if (listMapModeVisible) {/* Hide the list widget */
2296 listMapModeVisible = 0;
2297 window_destroyWidget( wid, "lstMapMode" );
2298 }
2299 else { /* show the list widget */
2300 int defpos;
2301 this_map_modes = calloc( sizeof(char*), array_size(map_modes) );
2302 for (int i=0; i<array_size(map_modes);i++) {
2303 this_map_modes[i]=strdup(map_modes[i]);
2304 }
2305 listMapModeVisible = 2;
2306 if (map_mode == MAPMODE_TRAVEL)
2307 defpos = 0;
2308 else if (map_mode == MAPMODE_DISCOVER)
2309 defpos = 1;
2310 else
2311 defpos = cur_commod*2 + MAPMODE_TRADE - cur_commod_mode;
2312
2313 window_addList( wid, -10, 60, 200, 200, "lstMapMode",
2314 this_map_modes, array_size(map_modes), defpos, map_modeUpdate, map_modeActivate );
2315 }
2316 }
2317}
2318
2322static void map_onClose( unsigned int wid, const char *str )
2323{
2324 (void) wid;
2325 (void) str;
2326 free( commod_known );
2327 commod_known = NULL;
2328 for (int i=0; i<array_size(map_modes); i++)
2329 free( map_modes[i] );
2330 array_free( map_modes );
2331 map_modes = NULL;
2332}
2333
2334void map_cleanup (void)
2335{
2336 map_close();
2337 map_clear();
2338}
2339
2343void map_close (void)
2344{
2345 unsigned int wid = window_get(MAP_WDWNAME);
2346 if (wid > 0)
2347 window_destroy(wid);
2348}
2349
2353void map_clear (void)
2354{
2355 array_free(map_path);
2356 map_path = NULL;
2357 map_selected = -1;
2358}
2359
2360static void map_updateInternal( CstMapWidget *cst, double dt )
2361{
2362 double dx, dy, mod;
2363 double mapmin = 1.-map_minimal_mode;
2364
2365#define AMAX(x) (x) = MIN( 1., (x) + dt )
2366#define AMIN(x) (x) = MAX( 0., (x) - dt )
2367#define ATAR(x,y) \
2368if ((x) < y) (x) = MIN( y, (x) + dt ); \
2369else (x) = MAX( y, (x) - dt )
2370 switch (cst->mode) {
2371 case MAPMODE_EDITOR: /* fall through */
2372 case MAPMODE_TRAVEL:
2373 ATAR( cst->alpha_decorators, mapmin );
2374 ATAR( cst->alpha_faction, mapmin );
2375 ATAR( cst->alpha_env, mapmin );
2376 AMAX( cst->alpha_path );
2377 AMAX( cst->alpha_names );
2378 AMIN( cst->alpha_commod );
2379 AMAX( cst->alpha_markers );
2380 break;
2381
2382 case MAPMODE_DISCOVER:
2383 ATAR( cst->alpha_decorators, 0.5 * mapmin );
2384 ATAR( cst->alpha_faction, 0.5 * mapmin );
2385 ATAR( cst->alpha_env, mapmin );
2386 ATAR( cst->alpha_path, 0.5 );
2387 AMAX( cst->alpha_names );
2388 AMIN( cst->alpha_commod );
2389 AMAX( cst->alpha_markers );
2390 break;
2391
2392 case MAPMODE_TRADE:
2393 AMIN( cst->alpha_decorators );
2394 AMIN( cst->alpha_faction );
2395 AMIN( cst->alpha_env );
2396 ATAR( cst->alpha_path, 0.5 );
2397 AMIN( cst->alpha_names );
2398 AMAX( cst->alpha_commod );
2399 ATAR( cst->alpha_markers, 0.5 );
2400 break;
2401 }
2402#undef AMAX
2403#undef AMIN
2404#undef ATAR
2405
2406 dx = (cst->xtarget - cst->xpos);
2407 dy = (cst->ytarget - cst->ypos);
2408 mod = MOD(dx,dy);
2409 if (mod > 1e-5) {
2410 double angle = ANGLE(dx,dy);
2411 /* TODO we should really do this with some nicer easing. */
2412 mod = MIN( mod, dt*map_flyto_speed);
2413 cst->xpos += mod * cos(angle);
2414 cst->ypos += mod * sin(angle);
2415 }
2416}
2417
2421static void map_reset( CstMapWidget* cst, MapMode mode )
2422{
2423 cst->mode = mode;
2424 map_updateInternal( cst, 1000. );
2425}
2426
2430static CstMapWidget* map_globalCustomData( unsigned int wid )
2431{
2432 if (wid==0)
2433 wid = window_get(MAP_WDWNAME);
2434 return (wid > 0) ? window_custGetData( wid, "cstMap" ) : NULL;
2435}
2436
2440static void map_selectCur (void)
2441{
2442 if (cur_system != NULL)
2443 map_selected = cur_system - systems_stack;
2444 else
2445 /* will probably segfault now */
2446 map_selected = -1;
2447}
2448
2455StarSystem* map_getDestination( int *jumps )
2456{
2457 if (array_size( map_path ) == 0)
2458 return NULL;
2459
2460 if (jumps != NULL)
2461 *jumps = array_size( map_path );
2462
2463 return array_back( map_path );
2464}
2465
2469void map_jump (void)
2470{
2471 /* set selected system to self */
2472 map_selectCur();
2473
2474 /* update path if set */
2475 if (array_size(map_path) != 0) {
2476 array_erase( &map_path, &map_path[0], &map_path[1] );
2477 if (array_size(map_path) == 0)
2479 else { /* get rid of bottom of the path */
2480 int j;
2481 /* set the next jump to be to the next in path */
2482 for (j=0; j<array_size(cur_system->jumps); j++) {
2483 if (map_path[0] == cur_system->jumps[j].target) {
2484 /* Restore selected system. */
2485 map_selected = array_back( map_path ) - systems_stack;
2486
2488 break;
2489 }
2490 }
2491 /* Overrode jump route manually, must clear target. */
2492 if (j>=array_size(cur_system->jumps))
2494 }
2495 }
2496 else
2498
2499 gui_setNav();
2500}
2501
2507void map_select( const StarSystem *sys, char shifted )
2508{
2509 int autonav;
2510 unsigned int wid = 0;
2511
2512 if (window_exists(MAP_WDWNAME))
2513 wid = window_get(MAP_WDWNAME);
2514
2515 if (sys == NULL) {
2516 map_selectCur();
2517 autonav = 0;
2518 }
2519 else {
2520 map_selected = sys - systems_stack;
2521
2522 /* select the current system and make a path to it */
2523 if (!shifted) {
2524 array_free( map_path );
2525 map_path = NULL;
2526 }
2527
2528 /* Try to make path if is reachable. */
2529 if (space_sysReachable(sys)) {
2530 const vec2 *posstart = NULL;
2531 if (player.p != NULL) {
2532 posstart = &player.p->solid.pos;
2533 }
2534 map_path = map_getJumpPath( cur_system->name, posstart, sys->name, 0, 1, map_path, NULL );
2535
2536 if (array_size(map_path)==0) {
2539 autonav = 0;
2540 }
2541 else {
2542 /* see if it is a valid hyperspace target */
2543 for (int i=0; i<array_size(cur_system->jumps); i++) {
2544 if (map_path[0] == cur_system->jumps[i].target) {
2547 break;
2548 }
2549 }
2550 autonav = 1;
2551 }
2552 }
2553 else { /* unreachable. */
2555 autonav = 0;
2556 }
2557 }
2558
2559 if (wid != 0) {
2560 if (autonav)
2561 window_enableButton( wid, "btnAutonav" );
2562 else
2563 window_disableButton( wid, "btnAutonav" );
2564 }
2565
2566 map_update(wid);
2567 gui_setNav();
2568}
2569
2575void map_cycleMissions(int dir)
2576{
2577 // StarSystem* systems_stack = system_getAll();
2578 StarSystem *dest = map_getDestination( NULL );
2579 StarSystem *target;
2580 int found_next_i = -1;
2581 int found_prev_i = -1;
2582 int found_b = 0;
2583 int i;
2584
2585 /* Select current selection - do nothing */
2586 if (dir==0)
2587 return;
2588
2589 /* Default : points to current system */
2590 if (dest==NULL)
2591 dest = cur_system;
2592
2593 /* Universally find prev and next mission system */
2594 for (i=0;i<array_size(systems_stack);i++) {
2595 if (!sys_isFlag(&systems_stack[i], SYSTEM_MARKED | SYSTEM_PMARKED) || !space_sysReachable(&systems_stack[i]) )
2596 continue;
2597
2598 /* Pre-select first in case we will wrap */
2599 if (found_next_i<0)
2600 found_next_i = i;
2601
2602 /* We found next system */
2603 if (found_b) {
2604 found_next_i = i;
2605 break;
2606 }
2607
2608 /* We found currently selected system */
2609 if (&systems_stack[i]==dest)
2610 found_b=1;
2611 else
2612 found_prev_i = i; /* Follow trail as we go */
2613 }
2614
2615 /* No trail for prev system - current one was first one in list - just finish loop and find last one */
2616 if (found_prev_i<0)
2617 for (;i<array_size(systems_stack);i++)
2618 if (sys_isMarked(&systems_stack[i]) && space_sysReachable(&systems_stack[i]))
2619 found_prev_i = i;
2620
2621 /* Select found system or return if no suitable was found */
2622 if (dir>0 && found_next_i>=0)
2623 target = &systems_stack[found_next_i];
2624 else if (dir<0 && found_prev_i>=0)
2625 target = &systems_stack[found_prev_i];
2626 else
2627 return;
2628
2629 /* Select and center system. */
2630 map_select( target, 0 );
2631 map_center( window_get( MAP_WDWNAME ), target->name );
2632
2633 /* Autonav to selected system */
2634 //player_hyperspacePreempt( 1 );
2635 //player_autonavStart();
2636}
2637
2641void map_toggleNotes()
2642{
2643 map_show_notes = !map_show_notes;
2644}
2645/*
2646 * A* algorithm for shortest path finding
2647 *
2648 * Note since that we can't actually get an admissible heurestic for A* this is
2649 * in reality just Djikstras. I've removed the heurestic bit to make sure I
2650 * don't try to implement an admissible heuristic when I'm pretty sure there is
2651 * none.
2652 */
2656typedef struct SysNode_ {
2657 struct SysNode_ *next;
2658 struct SysNode_ *gnext;
2660 struct SysNode_ *parent;
2661 StarSystem* sys;
2662 int g;
2663 double d;
2664 const vec2 *pos;
2665} SysNode;
2666static SysNode *A_gc;
2667/* prototypes */
2668static SysNode* A_newNode( StarSystem* sys );
2669static int A_g( const SysNode* n );
2670static double A_d( const SysNode* n );
2671static int A_less( const SysNode *op1, const SysNode *op2 );
2672static SysNode* A_add( SysNode *first, SysNode *cur );
2673static SysNode* A_rm( SysNode *first, const StarSystem *cur );
2674static SysNode* A_in( SysNode *first, const StarSystem *cur );
2675static SysNode* A_lowest( SysNode *first );
2676static void A_freeList( SysNode *first );
2677static int map_decorator_parse( MapDecorator *temp, const char *file );
2679static SysNode* A_newNode( StarSystem* sys )
2680{
2681 SysNode *n = malloc(sizeof(SysNode));
2682
2683 n->next = NULL;
2684 n->sys = sys;
2685
2686 n->gnext = A_gc;
2687 A_gc = n;
2688
2689 return n;
2690}
2692static int A_g( const SysNode* n )
2693{
2694 return n->g;
2695}
2697static double A_d( const SysNode* n )
2698{
2699 return n->d;
2700}
2702static int A_less( const SysNode *op1, const SysNode *op2 )
2703{
2704 return (A_g(op1) < A_g(op2)) || (A_g(op1) == A_g(op2) && A_d(op1) < A_d(op2));
2705}
2707static SysNode* A_add( SysNode *first, SysNode *cur )
2708{
2709 SysNode *n;
2710
2711 if (first == NULL)
2712 return cur;
2713
2714 n = first;
2715 while (n->next != NULL)
2716 n = n->next;
2717 n->next = cur;
2718
2719 return first;
2720}
2721/* @brief Removes a node from a linked list. */
2722static SysNode* A_rm( SysNode *first, const StarSystem *cur )
2723{
2724 SysNode *n, *p;
2725
2726 if (first->sys == cur) {
2727 n = first->next;
2728 first->next = NULL;
2729 return n;
2730 }
2731
2732 p = first;
2733 n = p->next;
2734 do {
2735 if (n->sys == cur) {
2736 p->next = n->next;
2737 n->next = NULL;
2738 break;
2739 }
2740 p = n;
2741 } while ((n=n->next) != NULL);
2742
2743 return first;
2744}
2746static SysNode* A_in( SysNode *first, const StarSystem *cur )
2747{
2748 SysNode *n;
2749
2750 if (first == NULL)
2751 return NULL;
2752
2753 n = first;
2754 do {
2755 if (n->sys == cur)
2756 return n;
2757 } while ((n=n->next) != NULL);
2758 return NULL;
2759}
2761static SysNode* A_lowest( SysNode *first )
2762{
2763 SysNode *lowest, *n;
2764
2765 if (first == NULL)
2766 return NULL;
2767
2768 n = first;
2769 lowest = n;
2770 do {
2771 if (A_less(n, lowest))
2772 lowest = n;
2773 } while ((n=n->next) != NULL);
2774 return lowest;
2775}
2777static void A_freeList( SysNode *first )
2778{
2779 SysNode *p, *n;
2780
2781 if (first == NULL)
2782 return;
2783
2784 p = NULL;
2785 n = first;
2786 do {
2787 free(p);
2788 p = n;
2789 } while ((n=n->gnext) != NULL);
2790 free(p);
2791}
2792
2794void map_setZoom( unsigned int wid, double zoom )
2795{
2796 CstMapWidget *cst = map_globalCustomData(wid);
2797 cst->zoom = zoom;
2798}
2799
2812StarSystem** map_getJumpPath( const char* sysstart, const vec2 *posstart, const char* sysend,
2813 int ignore_known, int show_hidden, StarSystem** old_data, double *o_distance )
2814{
2815 int j, ojumps;
2816 StarSystem *ssys, *esys, **res;
2817
2818 SysNode *cur, *neighbour;
2819 SysNode *open, *closed;
2820 SysNode *ocost, *ccost;
2821
2822 A_gc = NULL;
2823 res = old_data;
2824 ojumps = array_size( old_data );
2825
2826 /* initial and target systems */
2827 ssys = system_get(sysstart); /* start */
2828 esys = system_get(sysend); /* goal */
2829
2830 /* Set up. */
2831 if (ojumps > 0)
2832 ssys = system_get( array_back( old_data )->name );
2833
2834 /* Check self. */
2835 if (ssys==esys || array_size(ssys->jumps)==0) {
2836 array_free( res );
2837 return NULL;
2838 }
2839
2840 /* system target must be known and reachable */
2841 if (!ignore_known && !sys_isKnown(esys) && !space_sysReachable(esys)) {
2842 /* can't reach - don't make path */
2843 array_free( res );
2844 return NULL;
2845 }
2846
2847 /* initial entry position */
2848 const vec2 *p_pos_entry = (ojumps > 0) ? NULL : posstart;
2849 if (ojumps > 0) {
2850 const char *prev_name = sysstart;
2851 if (ojumps > 1) {
2852 prev_name = old_data[ojumps - 2]->name;
2853 }
2854 const JumpPoint* jp = jump_get(prev_name, ssys);
2855 if (jp != NULL) {
2856 p_pos_entry = &jp->pos;
2857 }
2858 }
2859
2860 /* start the linked lists */
2861 open = closed = NULL;
2862 cur = A_newNode( ssys );
2863 cur->parent = NULL;
2864 cur->g = 0;
2865 cur->d = 0.0;
2866 cur->pos = p_pos_entry;
2867 open = A_add( open, cur ); /* Initial open node is the start system */
2868
2869 j = 0;
2870 while ((cur = A_lowest(open))) {
2871 int cost;
2872 /* End condition. */
2873 if (cur->sys == esys)
2874 break;
2875
2876 /* Break if infinite loop. */
2877 j++;
2878 if (j > MAP_LOOP_PROT)
2879 break;
2880
2881 /* Get best from open and toss to closed */
2882 open = A_rm( open, cur->sys );
2883 closed = A_add( closed, cur );
2884 cost = A_g(cur) + 1; /* Base unit is jump and always increases by 1. */
2885
2886 for (int i=0; i<array_size(cur->sys->jumps); i++) {
2887 JumpPoint *jp = &cur->sys->jumps[i];
2888 StarSystem *sys = jp->target;
2889
2890 /* Make sure it's reachable */
2891 if (!ignore_known) {
2892 if (!jp_isKnown(jp))
2893 continue;
2894 if (!sys_isKnown(sys) && !space_sysReachable(sys))
2895 continue;
2896 }
2897 if (jp_isFlag( jp, JP_EXITONLY ))
2898 continue;
2899
2900 /* Skip hidden jumps if they're not specifically requested */
2901 if (!show_hidden && jp_isFlag( jp, JP_HIDDEN ))
2902 continue;
2903
2904 /* Update cost */
2905 const SysNode n_cost = {
2906 .g = cost,
2907 .d = A_d(cur) + ((cur->pos != NULL) ? vec2_dist(cur->pos, &jp->pos) : 0.0)
2908 };
2909
2910 /* Check to see if it's already in the closed set. */
2911 ccost = A_in(closed, sys);
2912 if ((ccost != NULL) && !A_less(&n_cost, ccost))
2913 continue;
2914 //closed = A_rm( closed, sys );
2915
2916 /* Remove if it exists and current is better. */
2917 ocost = A_in(open, sys);
2918 if (ocost != NULL) {
2919 if (A_less(&n_cost, ocost))
2920 open = A_rm( open, sys ); /* New path is better */
2921 else
2922 continue; /* This node is worse, so ignore it. */
2923 }
2924
2925 /* Create the node. */
2926 const JumpPoint *jp_entry = jump_getTarget(cur->sys, sys);
2927 neighbour = A_newNode( sys );
2928 neighbour->parent = cur;
2929 neighbour->g = n_cost.g;
2930 neighbour->d = n_cost.d;
2931 neighbour->pos = (jp_entry != NULL) ? &jp_entry->pos : NULL;
2932 open = A_add( open, neighbour );
2933 }
2934
2935 /* Safety check in case not linked. */
2936 if (open == NULL)
2937 break;
2938 }
2939
2940 if (o_distance != NULL) {
2941 *o_distance = cur->d;
2942 }
2943
2944 /* Build path backwards if not broken from loop. */
2945 if (cur != NULL && esys == cur->sys) {
2946 int njumps = A_g(cur) + ojumps;
2947 assert( njumps > ojumps );
2948 if (res == NULL)
2949 res = array_create_size( StarSystem*, njumps );
2950 array_resize( &res, njumps );
2951 /* Build path. */
2952 for (int i=0; i<njumps-ojumps; i++) {
2953 res[njumps-i-1] = cur->sys;
2954 cur = cur->parent;
2955 }
2956 }
2957 else {
2958 res = NULL;
2959 array_free( old_data );
2960 }
2961
2962 /* free the linked lists */
2963 A_freeList(A_gc);
2964 return res;
2965}
2966
2974int map_map( const Outfit *map )
2975{
2976 for (int i=0; i<array_size(map->u.map->systems);i++)
2977 sys_setFlag(map->u.map->systems[i], SYSTEM_KNOWN);
2978
2979 for (int i=0; i<array_size(map->u.map->spobs);i++) {
2980 Spob *spb = map->u.map->spobs[i];
2981 spob_setKnown( spb );
2982#if DEBUGGING
2983 const char *sysname = spob_getSystem( spb->name );
2984 if (sysname == NULL)
2985 WARN(_("Map '%s' is trying to set spob '%s' as known when it has no system!"), map->name, spb->name );
2986 else {
2987 int found = 0;
2988 for (int j=0; j<array_size(map->u.map->systems);j++) {
2989 const StarSystem *ss = map->u.map->systems[j];
2990 if (strcmp( ss->name, sysname )==0) {
2991 found = 1;
2992 break;
2993 }
2994 }
2995 if (!found)
2996 WARN(_("Map '%s' is trying to set spob '%s' as known when it is not in the system list! '%s' is in the '%s' system!"),
2997 map->name, spb->name, spb->name, sysname );
2998 }
2999#endif /* DEBUGGING */
3000 }
3001
3002 for (int i=0; i<array_size(map->u.map->jumps);i++)
3003 jp_setFlag(map->u.map->jumps[i], JP_KNOWN);
3004
3005 return 1;
3006}
3007
3015int map_isUseless( const Outfit* map )
3016{
3017 for (int i=0; i<array_size(map->u.map->systems);i++)
3018 if (!sys_isKnown(map->u.map->systems[i]))
3019 return 0;
3020
3021 for (int i=0; i<array_size(map->u.map->spobs);i++) {
3022 const Spob *p = map->u.map->spobs[i];
3023 if (!spob_hasSystem( p ) )
3024 continue;
3025 if (!spob_isKnown(p))
3026 return 0;
3027 }
3028
3029 for (int i=0; i<array_size(map->u.map->jumps);i++)
3030 if (!jp_isKnown(map->u.map->jumps[i]))
3031 return 0;
3032
3033 return 1;
3034}
3035
3039int localmap_map( const Outfit *lmap )
3040{
3041 double detect, mod;
3042
3043 if (cur_system==NULL)
3044 return 0;
3045
3046 mod = pow2( 200. / (cur_system->interference + 200.) );
3047
3048 detect = lmap->u.lmap.jump_detect;
3049 for (int i=0; i<array_size(cur_system->jumps); i++) {
3050 JumpPoint *jp = &cur_system->jumps[i];
3051 if (jp_isFlag(jp, JP_EXITONLY) || jp_isFlag(jp, JP_HIDDEN))
3052 continue;
3053 if (mod*jp->hide <= detect)
3054 jp_setFlag( jp, JP_KNOWN );
3055 }
3056
3057 detect = lmap->u.lmap.spob_detect;
3058 for (int i=0; i<array_size(cur_system->spobs); i++) {
3059 Spob *p = cur_system->spobs[i];
3060 if (!spob_hasSystem( p ) )
3061 continue;
3062 if (mod*p->hide <= detect)
3063 spob_setKnown( p );
3064 }
3065 return 0;
3066}
3067
3072int localmap_isUseless( const Outfit *lmap )
3073{
3074 double detect, mod;
3075
3076 if (cur_system==NULL)
3077 return 1;
3078
3079 mod = pow2( 200. / (cur_system->interference + 200.) );
3080
3081 detect = lmap->u.lmap.jump_detect;
3082 for (int i=0; i<array_size(cur_system->jumps); i++) {
3083 const JumpPoint *jp = &cur_system->jumps[i];
3084 if (jp_isFlag(jp, JP_EXITONLY) || jp_isFlag(jp, JP_HIDDEN))
3085 continue;
3086 if ((mod*jp->hide <= detect) && !jp_isKnown( jp ))
3087 return 0;
3088 }
3089
3090 detect = lmap->u.lmap.spob_detect;
3091 for (int i=0; i<array_size(cur_system->spobs); i++) {
3092 const Spob *p = cur_system->spobs[i];
3093 if ((mod*p->hide <= detect) && !spob_isKnown( p ))
3094 return 0;
3095 }
3096 return 1;
3097}
3098
3111void map_show( int wid, int x, int y, int w, int h, double zoom, double xoff, double yoff )
3112{
3113 CstMapWidget *cst = calloc( 1, sizeof(CstMapWidget) );
3114
3115 /* New widget. */
3116 window_addCust( wid, x, y, w, h,
3117 "cstMap", 1, map_render, map_mouse, NULL, map_focusLose, cst );
3118 window_custSetDynamic( wid, "cstMap", 1 );
3119 window_custAutoFreeData( wid, "cstMap" );
3120
3121 /* Set up stuff. */
3122 map_setup();
3123
3124 /* Centering stuff. */
3125 cst->xoff = xoff;
3126 cst->yoff = yoff;
3127
3128 /* Set position to focus on current system. */
3129 cst->xtarget = cst->xpos = cur_system->pos.x * zoom + cst->xoff;
3130 cst->ytarget = cst->ypos = cur_system->pos.y * zoom + cst->yoff;
3131
3132 /* Set zoom. */
3133 map_setZoom( wid, zoom );
3134
3135 map_reset( cst, MAPMODE_TRAVEL );
3136}
3137
3145int map_center( int wid, const char *sys )
3146{
3147 double d;
3148 CstMapWidget *cst = map_globalCustomData( wid );
3149
3150 /* Get the system. */
3151 StarSystem *ssys = system_get( sys );
3152 if (ssys == NULL)
3153 return -1;
3154
3155 /* Center on the system. */
3156 cst->xtarget = ssys->pos.x * cst->zoom + cst->xoff;
3157 cst->ytarget = ssys->pos.y * cst->zoom + cst->yoff;
3158
3159 /* Compute flyto speed. */
3160 d = MOD( cst->xtarget-cst->xpos, cst->ytarget-cst->ypos );
3161 map_flyto_speed = MIN( 2000., d / 0.2 );
3162
3163 return 0;
3164}
3165
3171int map_load (void)
3172{
3173#if DEBUGGING
3174 Uint32 time = SDL_GetTicks();
3175#endif /* DEBUGGING */
3176 char **decorator_files = ndata_listRecursive( MAP_DECORATOR_DATA_PATH );
3177
3178 decorator_stack = array_create( MapDecorator );
3179 for (int i=0; i<array_size(decorator_files); i++) {
3180 MapDecorator temp;
3181 int ret = map_decorator_parse( &temp, decorator_files[i] );
3182 if (ret == 0)
3183 array_push_back( &decorator_stack, temp );
3184 free( decorator_files[i] );
3185 }
3186 array_free( decorator_files );
3187
3188#if DEBUGGING
3189 if (conf.devmode) {
3190 time = SDL_GetTicks() - time;
3191 DEBUG( n_( "Loaded %d map decorator in %.3f s", "Loaded %d map decorators in %.3f s", array_size(decorator_stack) ), array_size(decorator_stack), time/1000. );
3192 }
3193 else
3194 DEBUG( n_( "Loaded %d map decorator", "Loaded %d map decorators", array_size(decorator_stack) ), array_size(decorator_stack) );
3195#endif /* DEBUGGING */
3196
3197 return 0;
3198}
3199
3200static int map_decorator_parse( MapDecorator *temp, const char *file )
3201{
3202 xmlDocPtr doc;
3203 xmlNodePtr node, parent;
3204
3205 doc = xml_parsePhysFS( file );
3206 if (doc == NULL)
3207 return -1;
3208
3209 parent = doc->xmlChildrenNode; /* map node */
3210 if (strcmp((char*)parent->name,"decorator")) {
3211 ERR(_("Malformed %s file: missing root element 'decorator'"), file );
3212 return -1;
3213 }
3214
3215 /* Clear memory. */
3216 memset( temp, 0, sizeof(MapDecorator) );
3217
3218 temp->detection_radius = 10;
3219
3220 /* Parse body. */
3221 node = parent->xmlChildrenNode;
3222 do {
3223 xml_onlyNodes(node);
3224 xmlr_float(node, "x", temp->x);
3225 xmlr_float(node, "y", temp->y);
3226 xmlr_int(node, "detection_radius", temp->detection_radius);
3227 if (xml_isNode(node,"image")) {
3228 temp->image = xml_parseTexture( node,
3229 MAP_DECORATOR_GFX_PATH"%s", 1, 1, OPENGL_TEX_MIPMAPS );
3230
3231 if (temp->image == NULL)
3232 WARN(_("Could not load map decorator texture '%s'."), xml_get(node));
3233
3234 continue;
3235 }
3236 WARN(_("Map decorator has unknown node '%s'."), node->name);
3237 } while (xml_nextNode(node));
3238
3239 xmlFreeDoc(doc);
3240
3241 return 0;
3242}
Provides macros to work with dynamic arrays.
#define array_free(ptr_array)
Frees memory allocated and sets array to NULL.
Definition array.h:158
#define array_resize(ptr_array, new_size)
Resizes the array to accomodate new_size elements.
Definition array.h:112
#define array_create_size(basic_type, capacity)
Creates a new dynamic array of ‘basic_type’ with an initial capacity.
Definition array.h:102
#define array_erase(ptr_array, first, last)
Erases elements in interval [first, last).
Definition array.h:140
static ALWAYS_INLINE int array_size(const void *array)
Returns number of elements in the array.
Definition array.h:168
#define array_grow(ptr_array)
Increases the number of elements by one and returns the last element.
Definition array.h:119
#define array_back(ptr_array)
Returns the last element in the array.
Definition array.h:216
#define array_push_back(ptr_array, element)
Adds a new element at the end of the array.
Definition array.h:129
#define array_create(basic_type)
Creates a new dynamic array of ‘basic_type’.
Definition array.h:93
void col_blend(glColour *blend, const glColour *fg, const glColour *bg, float alpha)
Blends two colours.
Definition colour.c:192
int commodity_getN(void)
Return the number of commodities globally.
Definition commodity.c:158
StarSystem * systems_stack
Definition space.c:92
char * dialogue_input(const char *title, int min, int max, const char *fmt,...)
Creates a dialogue that allows the player to write a message.
Definition dialogue.c:441
const char * faction_longname(int f)
Gets the faction's long name (formal, human-readable).
Definition faction.c:348
int faction_exists(const char *name)
Checks to see if a faction exists by name.
Definition faction.c:173
int faction_isKnown(int id)
Is the faction known?
Definition faction.c:275
char faction_getColourChar(int f)
Gets the faction character associated to its standing with the player.
Definition faction.c:1052
const glTexture * faction_logo(int f)
Gets the faction's logo (ideally 256x256).
Definition faction.c:453
int areEnemies(int a, int b)
Checks whether two factions are enemies.
Definition faction.c:1227
const char * faction_name(int f)
Gets a factions "real" (internal) name.
Definition faction.c:306
const char * faction_getStandingText(int f)
Gets the player's standing in human readable form.
Definition faction.c:1066
const glColour * faction_colour(int f)
Gets the colour of the faction.
Definition faction.c:469
const char * faction_mapname(int f)
Gets the faction's map name (translated).
Definition faction.c:365
int faction_get(const char *name)
Gets a faction ID by name.
Definition faction.c:184
int areAllies(int a, int b)
Checks whether two factions are allies or not.
Definition faction.c:1253
int gl_printHeightRaw(const glFont *ft_font, const int width, const char *text)
Gets the height of a non-formatted string.
Definition font.c:1027
glFont gl_smallFont
Definition font.c:154
void gl_printRaw(const glFont *ft_font, double x, double y, const glColour *c, double outlineR, const char *text)
Prints text on screen.
Definition font.c:617
int gl_printWidthRaw(const glFont *ft_font, const char *text)
Gets the width that it would take to print some text.
Definition font.c:961
glFont gl_defFont
Definition font.c:153
void gl_print(const glFont *ft_font, const double x, const double y, const glColour *c, const char *fmt,...)
Prints text on screen like printf.
Definition font.c:691
void gui_setNav(void)
Player just changed their nav computer target.
Definition gui.c:1775
int landed
Definition land.c:75
Spob * land_spob
Definition land.c:83
void mat4_translate(mat4 *m, double x, double y, double z)
Translates a homogenous transformation matrix.
Definition mat4.c:99
void mat4_scale(mat4 *m, double x, double y, double z)
Scales a homogeneous transformation matrix.
Definition mat4.c:82
void mission_sysMark(void)
Marks all active systems that need marking.
Definition mission.c:578
double naev_getrealdt(void)
Gets the last delta-tick.
Definition naev.c:1174
Header file with generic functions and naev-specifics.
#define MIN(x, y)
Definition naev.h:40
#define CLAMP(a, b, x)
Definition naev.h:41
#define pow2(x)
Definition naev.h:46
#define MAX(x, y)
Definition naev.h:39
char ** ndata_listRecursive(const char *path)
Lists all the visible files in a directory, at any depth.
Definition ndata.c:231
int rectOverlap(double x, double y, double w, double h, double x2, double y2, double w2, double h2)
Checks whether two rectangles overlap at any point.
Definition nmath.c:90
int scnprintf(char *text, size_t maxlen, const char *fmt,...)
Like snprintf(), but returns the number of characters ACTUALLY "printed" into the buffer....
Definition nstring.c:99
glTexture * xml_parseTexture(xmlNodePtr node, const char *path, int defsx, int defsy, const unsigned int flags)
Parses a texture handling the sx and sy elements.
Definition nxml.c:29
xmlDocPtr xml_parsePhysFS(const char *filename)
Analogous to xmlParseMemory/xmlParseFile.
Definition nxml.c:75
void gl_renderShader(double x, double y, double w, double h, double r, const SimpleShader *shd, const glColour *c, int center)
Renders a simple shader.
void gl_renderRect(double x, double y, double w, double h, const glColour *c)
Renders a rectangle.
void gl_renderScale(const glTexture *texture, double bx, double by, double bw, double bh, const glColour *c)
Blits a texture scaling it.
void gl_renderCircle(double cx, double cy, double r, const glColour *c, int filled)
Draws a circle.
void gl_freeTexture(glTexture *texture)
Frees a texture.
Definition opengl_tex.c:862
void gl_vboActivateAttribOffset(gl_vbo *vbo, GLuint index, GLuint offset, GLint size, GLenum type, GLsizei stride)
Activates a VBO's offset.
Definition opengl_vbo.c:226
int pilot_getJumps(const Pilot *p)
Gets the amount of jumps the pilot has left.
Definition pilot.c:1273
void player_targetHyperspaceSet(int id, int nomsg)
Sets the player's hyperspace target.
Definition player.c:1821
void player_hyperspacePreempt(int preempt)
Enables or disables jump points preempting spobs in autoface and target clearing.
Definition player.c:1893
Player_t player
Definition player.c:74
void player_autonavStartWindow(unsigned int wid, const char *str)
Starts autonav and closes the window.
static const double c[]
Definition rng.c:264
static const double d[]
Definition rng.c:273
StarSystem * system_getIndex(int id)
Get the system by its index.
Definition space.c:989
int spob_hasSystem(const Spob *spb)
Get whether or not a spob has a system (i.e. is on the map).
Definition space.c:1011
const char * spob_getSymbol(const Spob *p)
Gets the spob symbol.
Definition space.c:1900
char spob_getColourChar(const Spob *p)
Gets the spob colour char.
Definition space.c:1881
int space_sysReachable(const StarSystem *sys)
Sees if a system is reachable.
Definition space.c:826
JumpPoint * jump_getTarget(const StarSystem *target, const StarSystem *sys)
Less safe version of jump_get that works with pointers.
Definition space.c:1246
int space_sysReachableFromSys(const StarSystem *target, const StarSystem *sys)
Sees if a system is reachable from another system.
Definition space.c:865
StarSystem * system_get(const char *sysname)
Get the system from its name.
Definition space.c:960
const char * spob_getSystem(const char *spobname)
Get the name of a system from a spobname.
Definition space.c:1025
void spob_setKnown(Spob *p)
Sets a spob's known status, if it's real.
Definition space.c:1115
StarSystem * cur_system
Definition space.c:106
void spob_updateLand(Spob *p)
Updates the land possibilities of a spob.
Definition space.c:1943
int system_hasSpob(const StarSystem *sys)
See if the system has a spob.
Definition space.c:4294
const char * spob_name(const Spob *p)
Gets the translated name of a spob.
Definition space.c:1752
const char * spob_getServiceName(int service)
Gets the (English) name for a service code.
Definition space.c:167
JumpPoint * jump_get(const char *jumpname, const StarSystem *sys)
Gets a jump point based on its target and system.
Definition space.c:1222
Represents a commodity.
Definition commodity.h:43
Map widget data.
Definition map.c:66
double ytarget
Definition map.c:73
double alpha_faction
Definition map.c:76
double xtarget
Definition map.c:72
double alpha_decorators
Definition map.c:75
double xoff
Definition map.c:67
double alpha_commod
Definition map.c:80
double alpha_env
Definition map.c:77
double alpha_names
Definition map.c:79
MapMode mode
Definition map.c:82
double alpha_path
Definition map.c:78
double ypos
Definition map.c:71
double yoff
Definition map.c:68
double xpos
Definition map.c:70
double zoom
Definition map.c:69
double alpha_markers
Definition map.c:81
int drag
Definition map.c:74
Faction presence container to be used for the map information stuff.
Definition map.c:57
double value
Definition map.c:59
const char * name
Definition map.c:58
int known
Definition map.c:60
Images to be shown on the map.
Definition map.h:14
double y
Definition map.h:16
glTexture * image
Definition map.h:15
int detection_radius
Definition map.h:17
double jump_detect
Definition outfit.h:307
double spob_detect
Definition outfit.h:308
A ship outfit, depends radically on the type.
Definition outfit.h:328
union Outfit::@12 u
OutfitLocalMapData lmap
Definition outfit.h:411
OutfitMapData_t * map
Definition outfit.h:410
char * name
Definition outfit.h:329
Solid solid
Definition pilot.h:227
double fuel
Definition pilot.h:260
double fuel_consumption
Definition pilot.h:261
int devmode
Definition conf.h:157
Pilot * p
Definition player.h:101
int map_minimal
Definition player.h:122
vec2 pos
Definition physics.h:49
int faction
Definition space.h:67
Represents a Space Object (SPOB), including and not limited to planets, stations, wormholes,...
Definition space.h:89
int can_land
Definition space.h:108
Commodity ** commodities
Definition space.h:116
unsigned int services
Definition space.h:115
char * feature
Definition space.h:93
char * name
Definition space.h:91
CommodityPrice * commodityPrice
Definition space.h:117
SpobPresence presence
Definition space.h:104
Node structure for A* pathfinding.
Definition map.c:2656
StarSystem * sys
Definition map.c:2661
const vec2 * pos
Definition map.c:2664
struct SysNode_ * parent
Definition map.c:2660
struct SysNode_ * next
Definition map.c:2657
double d
Definition map.c:2663
struct SysNode_ * gnext
Definition map.c:2658
int g
Definition map.c:2662
Represents a font in memory.
Definition font.h:16
int h
Definition font.h:18
Abstraction for rendering sprite sheets.
Definition opengl_tex.h:36
double sw
Definition opengl_tex.h:46
double sh
Definition opengl_tex.h:47
double w
Definition opengl_tex.h:40
double h
Definition opengl_tex.h:41
Definition mat4.h:10
Represents a 2d vector.
Definition vec2.h:32
unsigned int window_create(const char *name, const char *displayname, const int x, const int y, const int w, const int h)
Creates a window.
Definition toolkit.c:691
void window_dimWidget(unsigned int wid, const char *name, int *w, int *h)
Gets the dimensions of a widget.
Definition toolkit.c:416
void window_setDynamic(unsigned int wid, int dynamic)
Sets a window as dynamic, so that it is drawn every frame completely.
Definition toolkit.c:647
void window_setFocus(unsigned int wid, const char *wgtname)
Sets the focused widget in a window.
Definition toolkit.c:2471
void window_dimWindow(unsigned int wid, int *w, int *h)
Gets the dimensions of a window.
Definition toolkit.c:371
void window_setCancel(unsigned int wid, void(*cancel)(unsigned int, const char *))
Sets the default cancel function of the window.
Definition toolkit.c:868
void window_onClose(unsigned int wid, void(*fptr)(unsigned int, const char *))
Sets the default close function of the window.
Definition toolkit.c:826
void window_moveWidget(unsigned int wid, const char *name, int x, int y)
Moves a widget.
Definition toolkit.c:465
void window_destroyWidget(unsigned int wid, const char *wgtname)
Destroys a widget in a window.
Definition toolkit.c:1165
int window_isTop(unsigned int wid)
Checks to see if a window is at the top.
Definition toolkit.c:549
void window_handleKeys(unsigned int wid, int(*keyhandler)(unsigned int, SDL_Keycode, SDL_Keymod, int))
Sets the key handler for the window.
Definition toolkit.c:960
unsigned int window_get(const char *wdwname)
Gets the ID of a window.
Definition toolkit.c:666
void window_setBorder(unsigned int wid, int enable)
Sets or removes the border of a window.
Definition toolkit.c:941
void window_resizeWidget(unsigned int wid, const char *name, int w, int h)
Resizes a widget.
Definition toolkit.c:493
int window_exists(const char *wdwname)
Checks to see if a window exists.
Definition toolkit.c:596
void window_close(unsigned int wid, const char *str)
Helper function to automatically close the window calling it.
Definition toolkit.c:1026
void window_destroy(unsigned int wid)
Kills the window.
Definition toolkit.c:1037