naev 0.12.5
map_find.c
1/*
2 * See Licensing and Copyright notice in naev.h
3 */
5#include <assert.h>
6
7#include "naev.h"
9
10#include "map_find.h"
11
12#include "array.h"
13#include "dialogue.h"
14#include "log.h"
15#include "map.h"
16#include "nstring.h"
17#include "player.h"
18#include "space.h"
19#include "tech.h"
20#include "toolkit.h"
21
22#define BUTTON_WIDTH 120
23#define BUTTON_HEIGHT 30
24
25/* Stored checkbox values. */
26static int map_find_systems = 1;
27static int map_find_spobs = 0;
28static int map_find_outfits = 0;
29static int map_find_ships = 0;
30
31/* Misc ugly globals. */
32/* Current found stuff. */
33static map_find_t *map_found_cur = NULL;
34static int map_found_ncur = 0;
35static char **map_foundOutfitNames =
36 NULL;
38/* Tech hack. */
39static tech_group_t **map_known_techs =
40 NULL;
41static Spob **map_known_spobs =
42 NULL;
43
44/*
45 * Prototypes.
46 */
47/* Init/cleanup. */
48static int map_knownInit( void );
49static void map_knownClean( void );
50/* Toolkit-related. */
51static void map_addOutfitDetailFields( unsigned int wid_results, int x, int y,
52 int w, int h );
53static void map_findCheckUpdate( unsigned int wid_map_find, const char *str );
54static void map_findOnClose( unsigned int wid_map_find, const char *str );
55static void map_findDisplayMark( unsigned int wid_results, const char *str );
56static void map_findDisplayResult( unsigned int wid_map_find, map_find_t *found,
57 int n );
58static int map_findSearchSystems( unsigned int wid_map_find, const char *name );
59static int map_findSearchSpobs( unsigned int wid_map_find, const char *name );
60static int map_findSearchOutfits( unsigned int wid_map_find, const char *name );
61static int map_findSearchShips( unsigned int wid_map_find, const char *name );
62static void map_findSearch( unsigned int wid_map_find, const char *str );
63static void map_showOutfitDetail( unsigned int wid, const char *wgtname, int x,
64 int y, int w, int h );
65static void map_adjustButtonLabel( unsigned int wid_map_find,
66 const char *name );
67/* Misc. */
68static void map_findAccumulateResult( map_find_t *found, int n, StarSystem *sys,
69 Spob *spob );
70static void map_findSelect( const StarSystem *sys );
71static int map_sortCompare( const void *p1, const void *p2 );
72static void map_sortFound( map_find_t *found, int n );
73static char map_getSpobColourChar( Spob *p );
74static const char *map_getSpobSymbol( Spob *p );
75/* Fuzzy outfit/ship stuff. */
76static char **map_fuzzyOutfits( Outfit **o, const char *name );
77static char **map_outfitsMatch( const char *name );
78static char **map_fuzzyShips( Ship **o, const char *name );
79static char **map_shipsMatch( const char *name );
80
84static int map_knownInit( void )
85{
86 const StarSystem *sys = system_getAll();
87
88 map_knownClean();
89 map_known_techs = array_create( tech_group_t * );
90 map_known_spobs = array_create( Spob * );
91
92 /* Get techs. */
93 for ( int i = 0; i < array_size( sys ); i++ ) {
94 if ( !sys_isKnown( &sys[i] ) )
95 continue;
96
97 for ( int j = 0; j < array_size( sys[i].spobs ); j++ ) {
98 Spob *spob = sys[i].spobs[j];
99
100 if ( spob_isKnown( spob ) && spob->tech != NULL ) {
101 array_push_back( &map_known_spobs, spob );
102 array_push_back( &map_known_techs, spob->tech );
103 }
104 }
105 }
106
107 return 0;
108}
109
113static void map_knownClean( void )
114{
115 array_free( map_known_techs );
116 map_known_techs = NULL;
117 array_free( map_known_spobs );
118 map_known_spobs = NULL;
119}
120
124static void map_findCheckUpdate( unsigned int wid_map_find, const char *str )
125{
126 (void)str;
127 map_find_systems ^= window_checkboxState( wid_map_find, "chkSystem" );
128 map_find_spobs ^= window_checkboxState( wid_map_find, "chkSpob" );
129 map_find_outfits ^= window_checkboxState( wid_map_find, "chkOutfit" );
130 map_find_ships ^= window_checkboxState( wid_map_find, "chkShip" );
131 window_checkboxSet( wid_map_find, "chkSystem", map_find_systems );
132 window_checkboxSet( wid_map_find, "chkSpob", map_find_spobs );
133 window_checkboxSet( wid_map_find, "chkOutfit", map_find_outfits );
134 window_checkboxSet( wid_map_find, "chkShip", map_find_ships );
135}
136
143void map_inputFindType( unsigned int parent, const char *type )
144{
145 map_find_systems = 0;
146 map_find_spobs = 0;
147 map_find_outfits = 0;
148 map_find_ships = 0;
149
150 if ( strcmp( type, "system" ) == 0 )
151 map_find_systems = 1;
152 else if ( strcmp( type, "spob" ) == 0 )
153 map_find_spobs = 1;
154 else if ( strcmp( type, "outfit" ) == 0 )
155 map_find_outfits = 1;
156 else if ( strcmp( type, "ship" ) == 0 )
157 map_find_ships = 1;
158
159 map_inputFind( parent, NULL );
160}
161
165static void map_findOnClose( unsigned int wid, const char *str )
166{
167 (void)wid;
168 (void)str;
169
170 free( map_found_cur );
171 map_found_cur = NULL;
172 map_knownClean();
173}
174
178static void map_findDisplayMark( unsigned int wid_results, const char *str )
179{
180 /* Get system. */
181 int pos = toolkit_getListPos( wid_results, "lstResult" );
182 StarSystem *sys = map_found_cur[pos].sys;
183 int wid_map_find = window_getParent( wid_results );
184
185 /* Close parent. */
186 window_close( wid_map_find, str );
187
188 map_findSelect( sys );
189}
190
194static void map_findDisplayResult( unsigned int wid_map_find, map_find_t *found,
195 int n )
196{
197 unsigned int wid_results;
198 char **ll;
199
200 /* Globals. */
201 map_found_cur = found;
202 map_found_ncur = n;
203
204 /* Sort the found by distance. */
205 map_sortFound( found, n );
206
207 /* Create window. */
208 wid_results =
209 window_create( "wdwFindResult", _( "Search Results" ), -1, -1, 500, 452 );
210 window_setParent( wid_results, wid_map_find );
211 window_setAccept( wid_results, map_findDisplayMark );
212 window_setCancel( wid_results, window_close );
213
214 /* The list. */
215 ll = malloc( sizeof( char * ) * n );
216 for ( int i = 0; i < n; i++ )
217 ll[i] = strdup( found[i].display );
218 window_addList( wid_results, 20, -40, 460, 300, "lstResult", ll, n, 0, NULL,
219 map_findDisplayMark );
220
221 /* Buttons. */
222 window_addButton( wid_results, -20, 20, BUTTON_WIDTH, BUTTON_HEIGHT,
223 "btnSelect", _( "Select" ), map_findDisplayMark );
224 window_addButton( wid_results, -40 - BUTTON_WIDTH, 20, BUTTON_WIDTH,
225 BUTTON_HEIGHT, "btnClose", _( "Cancel" ), window_close );
226}
227
231static int map_sortCompare( const void *p1, const void *p2 )
232{
233 map_find_t *f1, *f2;
234
235 /* Convert pointer. */
236 f1 = (map_find_t *)p1;
237 f2 = (map_find_t *)p2;
238
239 /* Compare jumps. */
240 if ( f1->jumps > f2->jumps )
241 return +1;
242 else if ( f1->jumps < f2->jumps )
243 return -1;
244
245 /* Compare distance. */
246 if ( f1->distance > f2->distance )
247 return +1;
248 else if ( f1->distance < f2->distance )
249 return -1;
250
251 /* If they're the same it doesn't matter, so we'll sort by name. */
252 return strcasecmp( f1->sys->name, f2->sys->name );
253}
254
258static void map_sortFound( map_find_t *found, int n )
259{
260 qsort( found, n, sizeof( map_find_t ), map_sortCompare );
261}
262
266static int map_findDistance( StarSystem *sys, Spob *spob, int *jumps,
267 double *distance )
268{
269 StarSystem **slist;
270 double d;
271 int i;
272
273 /* Special case it's the current system. */
274 if ( sys == cur_system ) {
275 *jumps = 0;
276 if ( spob != NULL )
277 *distance = vec2_dist( &player.p->solid.pos, &spob->pos );
278 else
279 *distance = 0.;
280
281 return 0;
282 }
283
284 /* Calculate jump path. */
285 slist =
286 map_getJumpPath( cur_system, &player.p->solid.pos, sys, 0, 1, NULL, &d );
287 *jumps = array_size( slist );
288 if ( slist == NULL )
289 /* Unknown. */
290 return -1;
291
292 /* Account final travel to spob for spob targets. */
293 i = *jumps - 1;
294 if ( spob != NULL ) {
295 const vec2 *ve = &spob->pos;
296 vec2 *vs = NULL;
297 if ( i > 0 ) {
298 StarSystem *ss = slist[i];
299 for ( int j = 0; j < array_size( ss->jumps ); j++ ) {
300 if ( ss->jumps[j].target == slist[i - 1] ) {
301 vs = &ss->jumps[j].pos;
302 break;
303 }
304 }
305 } else
306 vs = &player.p->solid.pos; /* No jumps, grab from current location. */
307
308 assert( vs != NULL );
309 assert( ve != NULL );
310
311 d += vec2_dist( vs, ve );
312 }
313
314 /* Cleanup. */
315 array_free( slist );
316
317 *distance = d;
318 return 0;
319}
320
330static void map_findAccumulateResult( map_find_t *found, int n, StarSystem *sys,
331 Spob *spob )
332{
333 int ret;
334 char route_info[STRMAX_SHORT];
335
336 /* Set some values. */
337 found[n].spob = spob;
338 found[n].sys = sys;
339
340 /* Set more values. */
341 ret = map_findDistance( sys, spob, &found[n].jumps, &found[n].distance );
342 if ( ret ) {
343 found[n].jumps = 10e3;
344 found[n].distance = 1e6;
345 snprintf( route_info, sizeof( route_info ), "%s", _( "unknown route" ) );
346 } else
347 snprintf( route_info, sizeof( route_info ),
348 n_( "%d jump, %.0fk distance", "%d jumps, %.0fk distance",
349 found[n].jumps ),
350 found[n].jumps, found[n].distance / 1000. );
351
352 /* Set fancy name. */
353 if ( spob == NULL )
354 snprintf( found[n].display, sizeof( found[n].display ), _( "%s (%s)" ),
355 system_name( sys ), route_info );
356 else
357 snprintf( found[n].display, sizeof( found[n].display ),
358 _( "#%c%s%s (%s, %s)" ), map_getSpobColourChar( spob ),
359 map_getSpobSymbol( spob ), spob_name( spob ),
360 system_name( sys ), route_info );
361}
362
366static void map_findSelect( const StarSystem *sys )
367{
368 if ( !map_isOpen() )
369 map_open();
370 map_select( sys, 0 );
371 map_center( 0, sys->name );
372}
373
380static int map_findSearchSystems( unsigned int wid_map_find, const char *name )
381{
382 const char *sysname;
383 char **names;
384 int len, n;
385 map_find_t *found;
386
387 /* Search for names. */
388 sysname = system_existsCase( name );
389 names = system_searchFuzzyCase( name, &len );
390 if ( names == NULL )
391 return -1;
392
393 /* Exact match. */
394 if ( ( sysname != NULL ) && ( len == 1 ) ) {
395 /* Select and show. */
396 StarSystem *sys = system_get( sysname );
397 if ( sys_isKnown( sys ) ) {
398 map_findSelect( sys );
399 free( names );
400 return 1;
401 }
402 }
403
404 /* Construct found table. */
405 found = NULL;
406 n = 0;
407 for ( int i = 0; i < len; i++ ) {
408
409 /* System must be known. */
410 StarSystem *sys = system_get( names[i] );
411 if ( !sys_isKnown( sys ) )
412 continue;
413
414 if ( found == NULL ) /* Allocate results array on first match. */
415 found = malloc( sizeof( map_find_t ) * len );
416
417 map_findAccumulateResult( found, n, sys, NULL );
418 n++;
419 }
420 free( names );
421
422 /* No visible match. */
423 if ( n == 0 )
424 return -1;
425
426 /* Display results. */
427 map_findDisplayResult( wid_map_find, found, n );
428 return 0;
429}
430
437static int map_findSearchSpobs( unsigned int wid_map_find, const char *name )
438{
439 char **names;
440 int len, n;
441 map_find_t *found;
442 const char *spobname;
443
444 /* Match spob first. */
445 spobname = spob_existsCase( name );
446 names = spob_searchFuzzyCase( name, &len );
447 if ( names == NULL )
448 return -1;
449
450 /* Exact match. */
451 if ( ( spobname != NULL ) && ( len == 1 ) ) {
452 /* Check exact match. */
453 const char *sysname = spob_getSystemName( spobname );
454 if ( sysname != NULL ) {
455 /* Make sure it's known. */
456 Spob *spob = spob_get( spobname );
457 if ( ( spob != NULL ) && spob_isKnown( spob ) ) {
458
459 /* Select and show. */
460 StarSystem *sys = system_get( sysname );
461 if ( sys_isKnown( sys ) ) {
462 map_findSelect( sys );
463 free( names );
464 return 1;
465 }
466 }
467 }
468 }
469
470 /* Construct found table. */
471 found = NULL;
472 n = 0;
473 for ( int i = 0; i < len; i++ ) {
474 const char *sysname;
475 StarSystem *sys;
476
477 /* Spob must be real. */
478 Spob *spob = spob_get( names[i] );
479 if ( spob == NULL )
480 continue;
481 if ( !spob_isKnown( spob ) )
482 continue;
483
484 /* System must be known. */
485 sysname = spob_getSystemName( names[i] );
486 if ( sysname == NULL )
487 continue;
488 sys = system_get( sysname );
489 if ( !sys_isKnown( sys ) )
490 continue;
491
492 if ( found == NULL ) /* Allocate results array on first match. */
493 found = malloc( sizeof( map_find_t ) * len );
494
495 map_findAccumulateResult( found, n, sys, spob );
496 n++;
497 }
498 free( names );
499
500 /* No visible match. */
501 if ( n == 0 )
502 return -1;
503
504 /* Display results. */
505 map_findDisplayResult( wid_map_find, found, n );
506 return 0;
507}
508
512static char map_getSpobColourChar( Spob *p )
513{
514 char colcode;
515
516 spob_updateLand( p );
517 colcode = spob_getColourChar( p );
518
519 return colcode;
520}
521
525static const char *map_getSpobSymbol( Spob *p )
526{
527 spob_updateLand( p );
528 return spob_getSymbol( p );
529}
530
535static char **map_fuzzyOutfits( Outfit **o, const char *name )
536{
537 char **names = array_create( char * );
538
539 /* Do fuzzy search. */
540 for ( int i = 0; i < array_size( o ); i++ ) {
541 if ( SDL_strcasestr( _( o[i]->name ), name ) != NULL )
542 array_push_back( &names, o[i]->name );
543 else if ( ( o[i]->typename != NULL ) &&
544 SDL_strcasestr( o[i]->typename, name ) != NULL )
545 array_push_back( &names, o[i]->name );
546 else if ( ( o[i]->condstr != NULL ) &&
547 SDL_strcasestr( o[i]->condstr, name ) != NULL )
548 array_push_back( &names, o[i]->name );
549 else if ( SDL_strcasestr( outfit_description( o[i] ), name ) != NULL )
550 array_push_back( &names, o[i]->name );
551 else if ( SDL_strcasestr( outfit_summary( o[i], 0 ), name ) != NULL )
552 array_push_back( &names, o[i]->name );
553 }
554
555 return names;
556}
557
561static char **map_outfitsMatch( const char *name )
562{
563 Outfit **o;
564 char **names;
565
566 /* Get outfits and names. */
567 o = tech_getOutfitArray( map_known_techs, array_size( map_known_techs ) );
568 names = map_fuzzyOutfits( o, name );
569 qsort( names, array_size( names ), sizeof( char * ), strsort );
570 array_free( o );
571
572 return names;
573}
584static void map_addOutfitDetailFields( unsigned int wid_results, int x, int y,
585 int w, int h )
586{
587 (void)h;
588 (void)y;
589 int iw;
590 char buf[STRMAX];
591 size_t l = 0;
592
593 iw = x;
594
595 window_addRect( wid_results, -1 + iw, -50, 128, 129, "rctImage", &cBlack,
596 0 );
597 window_addImage( wid_results, iw, -50 - 128, 0, 0, "imgOutfit", NULL, 1 );
598
599 window_addText( wid_results, iw + 128 + 20, -50, 280, 160, 0, "txtDescShort",
600 &gl_smallFont, NULL, NULL );
601 l += scnprintf( &buf[l], sizeof( buf ) - l, "#n%s#0\n", _( "Owned:" ) );
602 l += scnprintf( &buf[l], sizeof( buf ) - l, "#n%s#0\n", _( "Mass:" ) );
603 l += scnprintf( &buf[l], sizeof( buf ) - l, "#n%s#0\n", _( "Price:" ) );
604 l += scnprintf( &buf[l], sizeof( buf ) - l, "#n%s#0\n", _( "Money:" ) );
605 l += scnprintf( &buf[l], sizeof( buf ) - l, "#n%s#0\n", _( "License:" ) );
606 window_addText( wid_results, iw + 20, -50 - 128 - 10, 90, 160, 0, "txtSDesc",
607 &gl_smallFont, NULL, buf );
608 window_addText( wid_results, iw + 20, -50 - 128 - 10,
609 w - ( 20 + iw + 20 + 90 ), 160, 0, "txtDDesc", &gl_smallFont,
610 NULL, NULL );
611 window_addText( wid_results, iw + 20, -50 - 128 - 10 - 160, w - ( iw + 80 ),
612 180, 0, "txtDescription", &gl_smallFont, NULL, NULL );
613}
614
625static void map_showOutfitDetail( unsigned int wid, const char *wgtname, int x,
626 int y, int w, int h )
627{
628 (void)x;
629 (void)y;
630 (void)h;
631 char buf[STRMAX], buf_price[ECON_CRED_STRLEN], buf_money[ECON_CRED_STRLEN],
632 buf_mass[ECON_MASS_STRLEN];
633 const Outfit *outfit =
634 outfit_get( map_foundOutfitNames[toolkit_getListPos( wid, wgtname )] );
635 size_t l = 0;
636 double th;
637 int iw;
638 double mass = outfit->mass;
639
640 /* 452 px is the sum of the 128 px outfit image width, its 4 px border,
641 * a 20 px gap, 280 px for the outfit's name and a final 20 px gap. */
642 iw = w - 452;
643
644 outfit_gfxStoreLoad( (Outfit *)outfit );
645 window_modifyImage( wid, "imgOutfit", outfit->gfx_store, 128, 128 );
646 l = outfit_getNameWithClass( outfit, buf, sizeof( buf ) );
647 l += scnprintf( &buf[l], sizeof( buf ) - l, " %s",
648 pilot_outfitSummary( player.p, outfit, 0 ) );
649 window_modifyText( wid, "txtDescShort", buf );
650 th = gl_printHeightRaw( &gl_smallFont, 280, buf );
651
652 if ( outfit_isLauncher( outfit ) )
653 mass += outfit_amount( outfit ) * outfit->u.lau.ammo_mass;
654 else if ( outfit_isFighterBay( outfit ) )
655 mass += outfit_amount( outfit ) * outfit->u.bay.ship_mass;
656
657 window_modifyText( wid, "txtDescription",
658 pilot_outfitDescription( player.p, outfit ) );
659 credits2str( buf_price, outfit->price, 2 );
660 credits2str( buf_money, player.p->credits, 2 );
661 tonnes2str( buf_mass, (int)round( mass ) );
662
663 l = 0;
664 l += scnprintf( &buf[l], sizeof( buf ) - l, "%d\n",
665 player_outfitOwned( outfit ) );
666 l += scnprintf( &buf[l], sizeof( buf ) - l, "%s\n", buf_mass );
667 l += scnprintf( &buf[l], sizeof( buf ) - l, "%s\n", buf_price );
668 l += scnprintf( &buf[l], sizeof( buf ) - l, "%s\n", buf_money );
669 l += scnprintf( &buf[l], sizeof( buf ) - l, "%s\n",
670 ( outfit->license != NULL ) ? _( outfit->license )
671 : _( "None" ) );
672
673 window_modifyText( wid, "txtDDesc", buf );
674 window_resizeWidget( wid, "txtDescShort", 280, th );
675 window_moveWidget( wid, "txtDescShort", iw + 128 + 20, -50 );
676 th = MAX( 128 + gl_smallFont.h, th );
677 window_moveWidget( wid, "txtSDesc", iw + 20, -50 - th );
678 window_moveWidget( wid, "txtDDesc", iw + 20 + 90, -50 - th );
679 th += gl_printHeightRaw( &gl_smallFont, 280, buf );
680 window_moveWidget( wid, "txtDescription", iw + 20, -50 - th );
681}
682
689static void map_adjustButtonLabel( unsigned int wid_map_find, const char *name )
690{
691 if ( window_getInput( wid_map_find, name )[0] != '\0' ) {
692 window_buttonCaption( wid_map_find, "btnSearch", _( "Find" ) );
693 } else {
694 window_buttonCaption( wid_map_find, "btnSearch", _( "Show all" ) );
695 }
696}
697
704static int map_findSearchOutfits( unsigned int wid_map_find, const char *name )
705{
706 int len, n;
707 map_find_t *found;
708 const char *oname, *sysname;
709 char **list;
710 const Outfit *o;
711
712 assert( "Outfit search is not reentrant!" && map_foundOutfitNames == NULL );
713
714 /* Match spob first. */
715 o = NULL;
716 oname = outfit_existsCase( name );
717 map_foundOutfitNames = map_outfitsMatch( name );
718 len = array_size( map_foundOutfitNames );
719 if ( ( oname != NULL ) && ( len == 1 ) )
720 o = outfit_get( oname );
721 /* Do fuzzy match. */
722 else if ( len > 0 ) {
723 int i;
724
725 /* Ask which one player wants. */
726 list = malloc( len * sizeof( char * ) );
727 for ( i = 0; i < len; i++ )
728 list[i] = strdup( _( map_foundOutfitNames[i] ) );
729 if ( ( name == NULL ) || ( name[0] == '\0' ) )
730 i = dialogue_listPanelRaw( _( "Search Results" ), list, len, 452, 650,
731 map_addOutfitDetailFields,
732 map_showOutfitDetail,
733 _( "Showing all known outfits:" ) );
734 else
736 _( "Search Results" ), list, len, 452, 650,
737 map_addOutfitDetailFields, map_showOutfitDetail,
738 _( "Search results for outfits matching '%s':" ), name );
739 if ( i < 0 ) {
740 array_free( map_foundOutfitNames );
741 map_foundOutfitNames = NULL;
742 return 0;
743 }
744 o = outfit_get( map_foundOutfitNames[i] );
745 }
746 array_free( map_foundOutfitNames );
747 map_foundOutfitNames = NULL;
748 if ( o == NULL )
749 return -1;
750
751 /* Construct found table. */
752 found = NULL;
753 n = 0;
754 len = array_size( map_known_techs );
755 for ( int i = 0; i < len; i++ ) {
756 /* Try to find the outfit in the spob. */
757 int j;
758 Spob *spob;
759 StarSystem *sys;
760 Outfit **olist = tech_getOutfit( map_known_techs[i] );
761 for ( j = array_size( olist ) - 1; j >= 0; j-- )
762 if ( olist[j] == o )
763 break;
764 array_free( olist );
765 olist = NULL;
766 if ( j < 0 )
767 continue;
768 spob = map_known_spobs[i];
769
770 /* Must have an outfitter. */
771 if ( !spob_hasService( spob, SPOB_SERVICE_OUTFITS ) )
772 continue;
773
774 /* System must be known. */
775 sysname = spob_getSystemName( spob->name );
776 if ( sysname == NULL )
777 continue;
778 sys = system_get( sysname );
779 if ( !sys_isKnown( sys ) )
780 continue;
781
782 if ( found == NULL ) /* Allocate results array on first match. */
783 found = malloc( sizeof( map_find_t ) * len );
784
785 map_findAccumulateResult( found, n, sys, spob );
786 n++;
787 }
788
789 /* No visible match. */
790 if ( n == 0 )
791 return -1;
792
793 /* Display results. */
794 map_findDisplayResult( wid_map_find, found, n );
795 return 0;
796}
797
802static char **map_fuzzyShips( Ship **s, const char *name )
803{
804 char **names = array_create( char * );
805
806 /* Do fuzzy search. */
807 for ( int i = 0; i < array_size( s ); i++ ) {
808 if ( SDL_strcasestr( _( s[i]->name ), name ) != NULL )
809 array_push_back( &names, s[i]->name );
810 else if ( ( s[i]->license != NULL ) &&
811 SDL_strcasestr( _( s[i]->license ), name ) != NULL )
812 array_push_back( &names, s[i]->name );
813 else if ( SDL_strcasestr( _( ship_classDisplay( s[i] ) ), name ) != NULL )
814 array_push_back( &names, s[i]->name );
815 else if ( SDL_strcasestr( _( s[i]->fabricator ), name ) != NULL )
816 array_push_back( &names, s[i]->name );
817 else if ( SDL_strcasestr( _( s[i]->description ), name ) != NULL )
818 array_push_back( &names, s[i]->name );
819 }
820
821 return names;
822}
826static char **map_shipsMatch( const char *name )
827{
828 Ship **s;
829 char **names;
830
831 /* Get ships and names. */
832 s = tech_getShipArray( map_known_techs, array_size( map_known_techs ) );
833 names = map_fuzzyShips( s, name );
834 qsort( names, array_size( names ), sizeof( char * ), strsort );
835 array_free( s );
836
837 return names;
838}
839
846static int map_findSearchShips( unsigned int wid_map_find, const char *name )
847{
848 char **names;
849 int len, n;
850 map_find_t *found;
851 Spob *spob;
852 StarSystem *sys;
853 const char *sname, *sysname;
854 char **list;
855 const Ship *s;
856 Ship **slist;
857
858 /* Match spob first. */
859 s = NULL;
860 sname = ship_existsCase( name );
861 names = map_shipsMatch( name );
862 len = array_size( names );
863 if ( ( sname != NULL ) && ( len == 1 ) )
864 s = ship_get( sname );
865 /* Handle fuzzy matching. */
866 else if ( len > 0 ) {
867 int i;
868 /* Ask which one player wants. */
869 list = malloc( len * sizeof( char * ) );
870 for ( i = 0; i < len; i++ )
871 list[i] = strdup( _( names[i] ) );
872 if ( ( name == NULL ) || ( name[0] == '\0' ) )
873 i = dialogue_listRaw( _( "Search Results" ), list, len,
874 _( "Showing all known ships:" ) );
875 else
876 i = dialogue_list( _( "Search Results" ), list, len,
877 _( "Search results for ships matching '%s':" ),
878 name );
879 if ( i < 0 ) {
880 array_free( names );
881 return 0;
882 }
883 s = ship_get( names[i] );
884 }
885 array_free( names );
886 names = NULL;
887 if ( s == NULL )
888 return -1;
889
890 /* Construct found table. */
891 found = NULL;
892 n = 0;
893 len = array_size( map_known_techs );
894 for ( int i = 0; i < len; i++ ) {
895 int j;
896
897 /* Try to find the ship in the spob. */
898 slist = tech_getShip( map_known_techs[i] );
899 for ( j = array_size( slist ) - 1; j >= 0; j-- )
900 if ( slist[j] == s )
901 break;
902 array_free( slist );
903 slist = NULL;
904 if ( j < 0 )
905 continue;
906 spob = map_known_spobs[i];
907
908 /* Must have an shipyard. */
909 if ( !spob_hasService( spob, SPOB_SERVICE_SHIPYARD ) )
910 continue;
911
912 /* System must be known. */
913 sysname = spob_getSystemName( spob->name );
914 if ( sysname == NULL )
915 continue;
916 sys = system_get( sysname );
917 if ( !sys_isKnown( sys ) )
918 continue;
919
920 if ( found == NULL ) /* Allocate results array on first match. */
921 found = malloc( sizeof( map_find_t ) * len );
922
923 map_findAccumulateResult( found, n, sys, spob );
924 n++;
925 }
926
927 /* No visible match. */
928 if ( n == 0 )
929 return -1;
930
931 /* Display results. */
932 map_findDisplayResult( wid_map_find, found, n );
933 return 0;
934}
935
939static void map_findSearch( unsigned int wid_map_find, const char *str )
940{
941 int ret;
942 const char *name, *searchname;
943
944 /* Get the name. */
945 name = window_getInput( wid_map_find, "inpSearch" );
946
947 /* Prevent reentrancy, e.g. the toolkit spontaneously deciding a future
948 * mouseup event was the user releasing the clicked "Find" button and should
949 * reactivate it, never mind that they were actually clicking on the
950 * dialogue_listPanel we opened to present the results.
951 * FIXME: That behavior doesn't seem right, but I'm not sure if it's an
952 * actual bug or not. */
953 window_disableButton( wid_map_find, "btnSearch" );
954
955 /* Clean up if necessary. */
956 free( map_found_cur );
957 map_found_cur = NULL;
958
959 /* Handle different search cases. */
960 if ( map_find_systems ) {
961 ret = map_findSearchSystems( wid_map_find, name );
962 searchname = _( "System" );
963 } else if ( map_find_spobs ) {
964 ret = map_findSearchSpobs( wid_map_find, name );
965 searchname = _( "Space Objects" );
966 } else if ( map_find_outfits ) {
967 ret = map_findSearchOutfits( wid_map_find, name );
968 searchname = _( "Outfit" );
969 } else if ( map_find_ships ) {
970 ret = map_findSearchShips( wid_map_find, name );
971 searchname = _( "Ship" );
972 } else
973 ret = 1;
974
975 if ( ret < 0 )
976 dialogue_alert( _( "%s matching '%s' not found!" ), searchname, name );
977
978 /* Safe at last. */
979 window_enableButton( wid_map_find, "btnSearch" );
980
981 if ( ret > 0 )
982 window_close( wid_map_find, str );
983}
984
988void map_inputFind( unsigned int parent, const char *str )
989{
990 (void)str;
991 unsigned int wid_map_find;
992 int x, y, w, h;
993
994 /* initialize known. */
995 map_knownInit();
996
997 /* Create the window. */
998 w = 400;
999 h = 220;
1000 wid_map_find = window_create( "wdwFind", _( "Find…" ), -1, -1, w, h );
1001 window_setAccept( wid_map_find, map_findSearch );
1002 window_setCancel( wid_map_find, window_close );
1003 window_setParent( wid_map_find, parent );
1004 window_onClose( wid_map_find, map_findOnClose );
1005
1006 /* Text. */
1007 y = -40;
1008 window_addText( wid_map_find, 20, y, w - 50, gl_defFont.h + 4, 0,
1009 "txtDescription", &gl_defFont, NULL,
1010 _( "Enter keyword to search for: (Partial match)" ) );
1011 y -= 30;
1012
1013 /* Create input. */
1014 window_addInput( wid_map_find, 30, y, w - 60, 20, "inpSearch", 32, 1,
1015 &gl_defFont );
1016 window_setInputCallback( wid_map_find, "inpSearch", map_adjustButtonLabel );
1017 y -= 40;
1018
1019 /* Create buttons. */
1020 window_addButton( wid_map_find, -30, 20 + BUTTON_HEIGHT + 20, BUTTON_WIDTH,
1021 BUTTON_HEIGHT, "btnSearch", _( "Show all" ),
1022 map_findSearch );
1023 window_addButton( wid_map_find, -30, 20, BUTTON_WIDTH, BUTTON_HEIGHT,
1024 "btnClose", _( "Close" ), window_close );
1025
1026 /* Create check boxes. */
1027 x = 40;
1028 window_addCheckbox( wid_map_find, x, y, 160, 20, "chkSystem", _( "Systems" ),
1029 map_findCheckUpdate, map_find_systems );
1030 y -= 20;
1031 window_addCheckbox( wid_map_find, x, y, 160, 20, "chkSpob",
1032 _( "Space Objects" ), map_findCheckUpdate,
1033 map_find_spobs );
1034 y -= 20;
1035 window_addCheckbox( wid_map_find, x, y, 160, 20, "chkOutfit", _( "Outfits" ),
1036 map_findCheckUpdate, map_find_outfits );
1037 y -= 20;
1038 window_addCheckbox( wid_map_find, x, y, 160, 20, "chkShip", _( "Ships" ),
1039 map_findCheckUpdate, map_find_ships );
1040}
Provides macros to work with dynamic arrays.
#define array_free(ptr_array)
Frees memory allocated and sets array to NULL.
Definition array.h:170
static ALWAYS_INLINE int array_size(const void *array)
Returns number of elements in the array.
Definition array.h:179
#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 credits2str(char *str, credits_t credits, int decimals)
Converts credits to a usable string for displaying.
Definition commodity.c:75
void tonnes2str(char *str, int tonnes)
Converts tonnes to a usable string for displaying.
Definition commodity.c:131
void dialogue_alert(const char *fmt,...)
Displays an alert popup with only an ok button and a message.
Definition dialogue.c:130
int dialogue_listPanelRaw(const char *title, char **items, int nitems, int extrawidth, int minheight, void(*add_widgets)(unsigned int wid, int x, int y, int w, int h), void(*select_call)(unsigned int wid, const char *wgtname, int x, int y, int w, int h), const char *msg)
Creates a list dialogue with OK and Cancel buttons, with a fixed message, as well as a small extra ar...
Definition dialogue.c:681
int dialogue_listRaw(const char *title, char **items, int nitems, const char *msg)
Creates a list dialogue with OK and Cancel button.
Definition dialogue.c:614
int dialogue_listPanel(const char *title, char **items, int nitems, int extrawidth, int minheight, void(*add_widgets)(unsigned int wid, int x, int y, int w, int h), void(*select_call)(unsigned int wid, const char *wgtname, int x, int y, int w, int h), const char *fmt,...)
Creates a list dialogue with OK and Cancel buttons, with a fixed message, as well as a small extra ar...
Definition dialogue.c:639
int dialogue_list(const char *title, char **items, int nitems, const char *fmt,...)
Creates a list dialogue with OK and Cancel button with a fixed message.
Definition dialogue.c:588
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
glFont gl_defFont
Definition font.c:158
Header file with generic functions and naev-specifics.
#define MAX(x, y)
Definition naev.h:37
int strsort(const void *p1, const void *p2)
Sort function for sorting strings with qsort().
Definition nstring.c:83
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
const char * outfit_description(const Outfit *o)
Gets the description of an outfit.
Definition outfit.c:1143
const char * outfit_summary(const Outfit *o, int withname)
Gets the summary of an outfit.
Definition outfit.c:1157
const Outfit * outfit_get(const char *name)
Gets an outfit by name.
Definition outfit.c:223
int outfit_isLauncher(const Outfit *o)
Checks if outfit is a weapon launcher.
Definition outfit.c:649
size_t outfit_getNameWithClass(const Outfit *outfit, char *buf, size_t size)
Gets a brief name/class description suitable for the title section of an outfitter screen.
Definition outfit.c:525
int outfit_isFighterBay(const Outfit *o)
Checks if outfit is a fighter bay.
Definition outfit.c:701
int outfit_amount(const Outfit *o)
Gets the amount an outfit can hold.
Definition outfit.c:850
int outfit_gfxStoreLoad(Outfit *o)
Loads the store graphics for the outfit.
Definition outfit.c:198
const char * outfit_existsCase(const char *name)
Checks to see if an outfit exists matching name (case insensitive).
Definition outfit.c:255
const char * pilot_outfitDescription(const Pilot *p, const Outfit *o)
Gets the description of an outfit for a given pilot.
const char * pilot_outfitSummary(const Pilot *p, const Outfit *o, int withname)
Gets the summary of an outfit for a give pilot.
Player_t player
Definition player.c:77
int player_outfitOwned(const Outfit *o)
Gets how many of the outfit the player owns.
Definition player.c:2882
static const double d[]
Definition rng.c:263
const char * ship_classDisplay(const Ship *s)
Gets the ship's display class in human readable form.
Definition ship.c:203
const Ship * ship_get(const char *name)
Gets a ship based on its name.
Definition ship.c:99
const char * ship_existsCase(const char *name)
Checks to see if an ship exists matching name (case insensitive).
Definition ship.c:123
Spob * spob_get(const char *spobname)
Gets a spob based on its name.
Definition space.c:1107
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
const char * system_existsCase(const char *sysname)
Checks to see if a system exists case insensitively.
Definition space.c:936
StarSystem * system_getAll(void)
Gets an array (array.h) of all star systems.
Definition space.c:925
char ** spob_searchFuzzyCase(const char *spobname, int *n)
Does a fuzzy case matching. Searches spob_name() but returns internal names.
Definition space.c:1211
char ** system_searchFuzzyCase(const char *sysname, int *n)
Does a fuzzy case matching. Searches translated names but returns internal names.
Definition space.c:948
StarSystem * system_get(const char *sysname)
Get the system from its name.
Definition space.c:1007
StarSystem * cur_system
Definition space.c:110
const char * spob_existsCase(const char *spobname)
Check to see if a spob exists (case insensitive).
Definition space.c:1199
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
const char * spob_name(const Spob *p)
Gets the translated name of a spob.
Definition space.c:1834
A ship outfit, depends radically on the type.
Definition outfit.h:372
credits_t price
Definition outfit.h:391
union Outfit::@264277167364127137334024361374356236341374052147 u
OutfitLauncherData lau
Definition outfit.h:456
glTexture * gfx_store
Definition outfit.h:398
OutfitFighterBayData bay
Definition outfit.h:459
char * license
Definition outfit.h:381
double mass
Definition outfit.h:384
Represents a space ship.
Definition ship.h:97
Represents a Space Object (SPOB), including and not limited to planets, stations, wormholes,...
Definition space.h:102
tech_group_t * tech
Definition space.h:137
char * name
Definition space.h:105
vec2 pos
Definition space.h:109
Represents a found target.
Definition map_find.h:12
StarSystem * sys
Definition map_find.h:14
int jumps
Definition map_find.h:16
Spob * spob
Definition map_find.h:13
double distance
Definition map_find.h:17
Represents a 2d vector.
Definition vec2.h:45
Ship ** tech_getShipArray(tech_group_t **tech, int num)
Gets the ships from an array of techs.
Definition tech.c:913
Ship ** tech_getShip(const tech_group_t *tech)
Gets all of the ships associated to a tech group.
Definition tech.c:887
Outfit ** tech_getOutfitArray(tech_group_t **tech, int num)
Gets the outfits from an array of techs.
Definition tech.c:864
Outfit ** tech_getOutfit(const tech_group_t *tech)
Gets all of the outfits associated to a tech group.
Definition tech.c:839
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
unsigned int window_getParent(unsigned int wid)
Gets the window's parent.
Definition toolkit.c:804
void window_setAccept(unsigned int wid, void(*accept)(unsigned int, const char *))
Sets the default accept function of the window.
Definition toolkit.c:846
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_setParent(unsigned int wid, unsigned int parent)
Sets a window as a window's parent.
Definition toolkit.c:787
void window_resizeWidget(unsigned int wid, const char *name, int w, int h)
Resizes a widget.
Definition toolkit.c:490
void window_close(unsigned int wid, const char *str)
Helper function to automatically close the window calling it.
Definition toolkit.c:1028