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