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