naev 0.10.4
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);
58/* Misc. */
59static void map_findAccumulateResult( map_find_t *found, int n, StarSystem *sys, Spob *spob );
60static void map_findSelect( const StarSystem *sys );
61static int map_sortCompare( const void *p1, const void *p2 );
62static void map_sortFound( map_find_t *found, int n );
63static char map_getSpobColourChar( Spob *p );
64static const char *map_getSpobSymbol( Spob *p );
65/* Fuzzy outfit/ship stuff. */
66static char **map_fuzzyOutfits( Outfit **o, const char *name );
67static char **map_outfitsMatch( const char *name );
68static char **map_fuzzyShips( Ship **o, const char *name );
69static char **map_shipsMatch( const char *name );
70
74static int map_knownInit (void)
75{
76 const StarSystem *sys = system_getAll();
77
78 map_knownClean();
79 map_known_techs = array_create( tech_group_t* );
80 map_known_spobs = array_create( Spob* );
81
82 /* Get techs. */
83 for (int i=0; i<array_size(sys); i++) {
84 if (!sys_isKnown( &sys[i] ))
85 continue;
86
87 for (int j=0; j<array_size(sys[i].spobs); j++) {
88 Spob *spob = sys[i].spobs[j];
89
90 if (spob_isKnown( spob ) && spob->tech != NULL) {
91 array_push_back( &map_known_spobs, spob );
92 array_push_back( &map_known_techs, spob->tech );
93 }
94 }
95 }
96
97 return 0;
98}
99
103static void map_knownClean (void)
104{
105 array_free( map_known_techs );
106 map_known_techs = NULL;
107 array_free( map_known_spobs );
108 map_known_spobs = NULL;
109}
110
114static void map_findCheckUpdate( unsigned int wid_map_find, const char* str )
115{
116 (void) str;
117 map_find_systems ^= window_checkboxState( wid_map_find, "chkSystem" );
118 map_find_spobs ^= window_checkboxState( wid_map_find, "chkSpob" );
119 map_find_outfits ^= window_checkboxState( wid_map_find, "chkOutfit" );
120 map_find_ships ^= window_checkboxState( wid_map_find, "chkShip" );
121 window_checkboxSet( wid_map_find, "chkSystem", map_find_systems );
122 window_checkboxSet( wid_map_find, "chkSpob", map_find_spobs );
123 window_checkboxSet( wid_map_find, "chkOutfit", map_find_outfits );
124 window_checkboxSet( wid_map_find, "chkShip", map_find_ships );
125}
126
133void map_inputFindType( unsigned int parent, const char *type )
134{
135 map_find_systems = 0;
136 map_find_spobs = 0;
137 map_find_outfits = 0;
138 map_find_ships = 0;
139
140 if (strcmp(type,"system")==0)
141 map_find_systems = 1;
142 else if (strcmp(type,"spob")==0)
143 map_find_spobs = 1;
144 else if (strcmp(type,"outfit")==0)
145 map_find_outfits = 1;
146 else if (strcmp(type,"ship")==0)
147 map_find_ships = 1;
148
149 map_inputFind(parent, NULL);
150}
151
155static void map_findOnClose( unsigned int wid, const char* str )
156{
157 (void) wid;
158 (void) str;
159
160 free( map_found_cur );
161 map_found_cur = NULL;
162 map_knownClean();
163}
164
168static void map_findDisplayMark( unsigned int wid_results, const char* str )
169{
170 /* Get system. */
171 int pos = toolkit_getListPos( wid_results, "lstResult" );
172 StarSystem *sys = map_found_cur[ pos ].sys;
173 int wid_map_find = window_getParent( wid_results );
174
175 map_findSelect( sys );
176
177 /* Close parent. */
178 window_close( wid_map_find, str );
179}
180
184static void map_findDisplayResult( unsigned int wid_map_find, map_find_t *found, int n )
185{
186 unsigned int wid_results;
187 char **ll;
188
189 /* Globals. */
190 map_found_cur = found;
191 map_found_ncur = n;
192
193 /* Sort the found by distance. */
194 map_sortFound( found, n );
195
196 /* Create window. */
197 wid_results = window_create( "wdwFindResult", _("Search Results"), -1, -1, 500, 452 );
198 window_setParent( wid_results, wid_map_find );
199 window_setAccept( wid_results, map_findDisplayMark );
200 window_setCancel( wid_results, window_close );
201
202 /* The list. */
203 ll = malloc( sizeof(char*) * n );
204 for (int i=0; i<n; i++)
205 ll[i] = strdup( found[i].display );
206 window_addList( wid_results, 20, -40, 460, 300,
207 "lstResult", ll, n, 0, NULL, map_findDisplayMark );
208
209 /* Buttons. */
210 window_addButton( wid_results, -20, 20, BUTTON_WIDTH, BUTTON_HEIGHT,
211 "btnSelect", _("Select"), map_findDisplayMark );
212 window_addButton( wid_results, -40 - BUTTON_WIDTH, 20, BUTTON_WIDTH, BUTTON_HEIGHT,
213 "btnClose", _("Cancel"), window_close );
214}
215
219static int map_sortCompare( const void *p1, const void *p2 )
220{
221 map_find_t *f1, *f2;
222
223 /* Convert pointer. */
224 f1 = (map_find_t*) p1;
225 f2 = (map_find_t*) p2;
226
227 /* Compare jumps. */
228 if (f1->jumps > f2->jumps)
229 return +1;
230 else if (f1->jumps < f2->jumps)
231 return -1;
232
233 /* Compare distance. */
234 if (f1->distance > f2->distance)
235 return +1;
236 else if (f1->distance < f2->distance)
237 return -1;
238
239 /* If they're the same it doesn't matter, so we'll sort by name. */
240 return strcasecmp( f1->sys->name, f2->sys->name );
241}
242
246static void map_sortFound( map_find_t *found, int n )
247{
248 qsort( found, n, sizeof(map_find_t), map_sortCompare );
249}
250
254static int map_findDistance( StarSystem *sys, Spob *spob, int *jumps, double *distance )
255{
256 StarSystem **slist;
257 double d;
258 int i;
259 vec2 *vs, *ve;
260
261 /* Defaults. */
262 ve = NULL;
263
264 /* Special case it's the current system. */
265 if (sys == cur_system) {
266 *jumps = 0;
267 if (spob != NULL)
268 *distance = vec2_dist( &player.p->solid->pos, &spob->pos );
269 else
270 *distance = 0.;
271
272 return 0;
273 }
274
275 /* Calculate jump path. */
276 slist = map_getJumpPath( cur_system->name, sys->name, 0, 1, NULL );
277 *jumps = array_size( slist );
278 if (slist==NULL)
279 /* Unknown. */
280 return -1;
281
282 /* Distance to first jump point. */
283 vs = &player.p->solid->pos;
284 for (int j=0; j < array_size(cur_system->jumps); j++) {
285 if (cur_system->jumps[j].target == slist[0]) {
286 ve = &cur_system->jumps[j].pos;
287 break;
288 }
289 }
290 if (ve == NULL) {
291 WARN(_("Jump to first system not found!"));
292 d = 0.;
293 }
294 else
295 d = vec2_dist( vs, ve );
296
297 /* Calculate distance. */
298 for (i=0; i<(*jumps-1); i++) {
299 StarSystem *ss = slist[i];
300
301 /* Search jump points. */
302 for (int j=0; j < array_size(ss->jumps); j++) {
303
304 /* Get previous jump. */
305 if (i == 0) {
306 if (ss->jumps[j].target == cur_system)
307 vs = &ss->jumps[j].pos;
308 }
309 else {
310 if (ss->jumps[j].target == slist[i-1])
311 vs = &ss->jumps[j].pos;
312 }
313
314 /* Get next jump. */
315 if (ss->jumps[j].target == slist[i+1]) {
316 ve = &ss->jumps[j].pos;
317 break;
318 }
319 }
320
321 /* Use current position. */
322 if (i==0)
323 vs = &player.p->solid->pos;
324
325#ifdef DEBUGGING
326 if ((vs==NULL) || (ve==NULL)) {
327 WARN( _("Matching jumps not found, something is up...") );
328 continue;
329 }
330#endif /* DEBUGGING */
331
332 /* Calculate. */
333 d += vec2_dist( vs, ve );
334 }
335
336 /* Account final travel to spob for spob targets. */
337 if (spob != NULL) {
338 if (i > 0) {
339 StarSystem *ss = slist[ i ];
340 for (int j=0; j < array_size(ss->jumps); j++) {
341 if (ss->jumps[j].target == slist[i-1]) {
342 vs = &ss->jumps[j].pos;
343 break;
344 }
345 }
346 }
347
348 ve = &spob->pos;
349
350 assert( vs != NULL );
351 assert( ve != NULL );
352
353 d += vec2_dist( vs, ve );
354 }
355
356 /* Cleanup. */
357 array_free(slist);
358
359 *distance = d;
360 return 0;
361}
362
372static void map_findAccumulateResult( map_find_t *found, int n, StarSystem *sys, Spob *spob )
373{
374 int ret;
375 char route_info[STRMAX_SHORT];
376
377 /* Set some values. */
378 found[n].spob = spob;
379 found[n].sys = sys;
380
381 /* Set more values. */
382 ret = map_findDistance( sys, spob, &found[n].jumps, &found[n].distance );
383 if (ret) {
384 found[n].jumps = 10e3;
385 found[n].distance = 1e6;
386 snprintf( route_info, sizeof(route_info), "%s", _("unknown route") );
387 }
388 else
389 snprintf( route_info, sizeof(route_info),
390 n_( "%d jump, %.0fk distance", "%d jumps, %.0fk distance", found[n].jumps ),
391 found[n].jumps, found[n].distance/1000. );
392
393 /* Set fancy name. */
394 if (spob == NULL)
395 snprintf( found[n].display, sizeof(found[n].display),
396 _("%s (%s)"), _(sys->name), route_info );
397 else
398 snprintf( found[n].display, sizeof(found[n].display),
399 _("#%c%s%s (%s, %s)"), map_getSpobColourChar(spob),
400 map_getSpobSymbol(spob),
401 spob_name(spob), _(sys->name), route_info );
402}
403
407static void map_findSelect( const StarSystem *sys )
408{
409 if (!map_isOpen())
410 map_open();
411 map_select( sys, 0 );
412 map_center( 0, sys->name );
413}
414
421static int map_findSearchSystems( unsigned int wid_map_find, const char *name )
422{
423 const char *sysname;
424 char **names;
425 int len, n;
426 map_find_t *found;
427
428 /* Search for names. */
429 sysname = system_existsCase( name );
430 names = system_searchFuzzyCase( name, &len );
431 if (names == NULL)
432 return -1;
433
434 /* Exact match. */
435 if ((sysname != NULL) && (len == 1)) {
436 /* Select and show. */
437 StarSystem *sys = system_get(sysname);
438 if (sys_isKnown(sys)) {
439 map_findSelect( sys );
440 free(names);
441 return 1;
442 }
443 }
444
445 /* Construct found table. */
446 found = NULL;
447 n = 0;
448 for (int i=0; i<len; i++) {
449
450 /* System must be known. */
451 StarSystem *sys = system_get( names[i] );
452 if (!sys_isKnown(sys))
453 continue;
454
455 if (found == NULL) /* Allocate results array on first match. */
456 found = malloc( sizeof(map_find_t) * len );
457
458 map_findAccumulateResult( found, n, sys, NULL );
459 n++;
460 }
461 free(names);
462
463 /* No visible match. */
464 if (n==0)
465 return -1;
466
467 /* Display results. */
468 map_findDisplayResult( wid_map_find, found, n );
469 return 0;
470}
471
478static int map_findSearchSpobs( unsigned int wid_map_find, const char *name )
479{
480 char **names;
481 int len, n;
482 map_find_t *found;
483 const char *spobname;
484
485 /* Match spob first. */
486 spobname = spob_existsCase( name );
487 names = spob_searchFuzzyCase( name, &len );
488 if (names == NULL)
489 return -1;
490
491 /* Exact match. */
492 if ((spobname != NULL) && (len == 1)) {
493 /* Check exact match. */
494 const char *sysname = spob_getSystem( spobname );
495 if (sysname != NULL) {
496 /* Make sure it's known. */
497 Spob *spob = spob_get( spobname );
498 if ((spob != NULL) && spob_isKnown(spob)) {
499
500 /* Select and show. */
501 StarSystem *sys = system_get(sysname);
502 if (sys_isKnown(sys)) {
503 map_findSelect( sys );
504 free(names);
505 return 1;
506 }
507 }
508 }
509 }
510
511 /* Construct found table. */
512 found = NULL;
513 n = 0;
514 for (int i=0; i<len; i++) {
515 const char *sysname;
516 StarSystem *sys;
517
518 /* Spob must be real. */
519 Spob *spob = spob_get( names[i] );
520 if (spob == NULL)
521 continue;
522 if (!spob_isKnown(spob))
523 continue;
524
525 /* System must be known. */
526 sysname = spob_getSystem( names[i] );
527 if (sysname == NULL)
528 continue;
529 sys = system_get( sysname );
530 if (!sys_isKnown(sys))
531 continue;
532
533 if (found == NULL) /* Allocate results array on first match. */
534 found = malloc( sizeof(map_find_t) * len );
535
536 map_findAccumulateResult( found, n, sys, spob );
537 n++;
538 }
539 free(names);
540
541 /* No visible match. */
542 if (n==0)
543 return -1;
544
545 /* Display results. */
546 map_findDisplayResult( wid_map_find, found, n );
547 return 0;
548}
549
553static char map_getSpobColourChar( Spob *p )
554{
555 char colcode;
556
558 colcode = spob_getColourChar(p);
559
560 return colcode;
561}
562
566static const char *map_getSpobSymbol( Spob *p )
567{
569 return spob_getSymbol(p);
570}
571
575static char **map_fuzzyOutfits( Outfit **o, const char *name )
576{
577 char **names = array_create( char* );
578
579 /* Do fuzzy search. */
580 for (int i=0; i<array_size(o); i++) {
581 if (strcasestr( _(o[i]->name), name ) != NULL)
582 array_push_back( &names, o[i]->name );
583 else if ((o[i]->typename != NULL) && strcasestr( o[i]->typename, name ) != NULL)
584 array_push_back( &names, o[i]->name );
585 else if ((o[i]->condstr != NULL) && strcasestr( o[i]->condstr, name ) != NULL)
586 array_push_back( &names, o[i]->name );
587 else if (strcasestr( outfit_description(o[i]), name ) != NULL)
588 array_push_back( &names, o[i]->name );
589 else if (strcasestr( outfit_summary(o[i], 0), name ) != NULL)
590 array_push_back( &names, o[i]->name );
591 }
592
593 return names;
594}
595
599static char **map_outfitsMatch( const char *name )
600{
601 Outfit **o;
602 char **names;
603
604 /* Get outfits and names. */
605 o = tech_getOutfitArray( map_known_techs, array_size(map_known_techs) );
606 names = map_fuzzyOutfits( o, name );
607 array_free(o);
608
609 return names;
610}
621static void map_addOutfitDetailFields(unsigned int wid_results, int x, int y, int w, int h)
622{
623 (void) h;
624 (void) y;
625 int iw;
626 char buf[STRMAX];
627 size_t l = 0;
628
629 iw = x;
630
631 window_addRect( wid_results, -1 + iw, -50, 128, 129, "rctImage", &cBlack, 0 );
632 window_addImage( wid_results, iw, -50-128, 0, 0, "imgOutfit", NULL, 1 );
633
634 window_addText( wid_results, iw + 128 + 20, -50,
635 280, 160, 0, "txtDescShort", &gl_smallFont, NULL, NULL );
636 l += scnprintf( &buf[l], sizeof(buf)-l, "#n%s#0\n", _("Owned:") );
637 l += scnprintf( &buf[l], sizeof(buf)-l, "#n%s#0\n", _("Mass:") );
638 l += scnprintf( &buf[l], sizeof(buf)-l, "#n%s#0\n", _("Price:") );
639 l += scnprintf( &buf[l], sizeof(buf)-l, "#n%s#0\n", _("Money:") );
640 l += scnprintf( &buf[l], sizeof(buf)-l, "#n%s#0\n", _("License:") );
641 window_addText( wid_results, iw+20, -50-128-10,
642 90, 160, 0, "txtSDesc", &gl_smallFont, NULL, buf );
643 window_addText( wid_results, iw+20, -50-128-10,
644 w - (20 + iw + 20 + 90), 160, 0, "txtDDesc", &gl_smallFont, NULL, NULL );
645 window_addText( wid_results, iw+20, -50-128-10-160,
646 w-(iw+80), 180, 0, "txtDescription",
647 &gl_smallFont, NULL, NULL );
648}
649
660static void map_showOutfitDetail( unsigned int wid, const char* wgtname, int x, int y, int w, int h )
661{
662 (void) x;
663 (void) y;
664 (void) h;
665 char buf[STRMAX], buf_price[ECON_CRED_STRLEN], buf_money[ECON_CRED_STRLEN], buf_mass[ECON_MASS_STRLEN];
666 const Outfit *outfit = outfit_get( map_foundOutfitNames[toolkit_getListPos(wid, wgtname)] );
667 size_t l = 0;
668 double th;
669 int iw;
670 double mass = outfit->mass;
671
672 /* 452 px is the sum of the 128 px outfit image width, its 4 px border,
673 * a 20 px gap, 280 px for the outfit's name and a final 20 px gap. */
674 iw = w - 452;
675
676 window_modifyImage( wid, "imgOutfit", outfit->gfx_store, 128, 128 );
677 l = outfit_getNameWithClass( outfit, buf, sizeof(buf) );
678 l += scnprintf( &buf[l], sizeof(buf)-l, "%s", pilot_outfitSummary( player.p, outfit, 0 ) );
679 window_modifyText( wid, "txtDescShort", buf );
680 th = gl_printHeightRaw( &gl_smallFont, 280, buf );
681
682 if (outfit_isLauncher(outfit))
683 mass += outfit_amount(outfit) * outfit->u.lau.ammo_mass;
684 else if (outfit_isFighterBay(outfit))
685 mass += outfit_amount(outfit) * outfit->u.bay.ship_mass;
686
687 window_modifyText( wid, "txtDescription", pilot_outfitDescription( player.p, outfit ) );
688 credits2str( buf_price, outfit->price, 2 );
689 credits2str( buf_money, player.p->credits, 2 );
690 tonnes2str( buf_mass, (int)round( mass ) );
691
692 l = 0;
693 l += scnprintf( &buf[l], sizeof(buf)-l, "%d\n", player_outfitOwned(outfit) );
694 l += scnprintf( &buf[l], sizeof(buf)-l, "%s\n", buf_mass );
695 l += scnprintf( &buf[l], sizeof(buf)-l, "%s\n", buf_price );
696 l += scnprintf( &buf[l], sizeof(buf)-l, "%s\n", buf_money );
697 l += scnprintf( &buf[l], sizeof(buf)-l, "%s\n" , (outfit->license != NULL) ? _(outfit->license) : _("None") );
698
699 window_modifyText( wid, "txtDDesc", buf );
700 window_resizeWidget( wid, "txtDescShort", 280, th );
701 window_moveWidget( wid, "txtDescShort", iw + 128 + 20, -50 );
702 th = MAX( 128 + gl_smallFont.h, th );
703 window_moveWidget( wid, "txtSDesc", iw+20, -50-th );
704 window_moveWidget( wid, "txtDDesc", iw+20+90, -50-th );
705 th += gl_printHeightRaw( &gl_smallFont, 280, buf );
706 window_moveWidget( wid, "txtDescription", iw+20, -50-th );
707}
708
715static int map_findSearchOutfits( unsigned int wid_map_find, const char *name )
716{
717 int len, n;
718 map_find_t *found;
719 const char *oname, *sysname;
720 char **list;
721 const Outfit *o;
722
723 assert( "Outfit search is not reentrant!" && map_foundOutfitNames == NULL );
724
725 /* Match spob first. */
726 o = NULL;
727 oname = outfit_existsCase( name );
728 map_foundOutfitNames = map_outfitsMatch( name );
729 len = array_size( map_foundOutfitNames );
730 if ((oname != NULL) && (len == 1))
731 o = outfit_get( oname );
732 /* Do fuzzy match. */
733 else if (len > 0) {
734 int i;
735
736 /* Ask which one player wants. */
737 list = malloc( len*sizeof(char*) );
738 for (i=0; i<len; i++)
739 list[i] = strdup( _(map_foundOutfitNames[i]) );
740 i = dialogue_listPanel( _("Search Results"), list, len, 452, 650,
741 map_addOutfitDetailFields, map_showOutfitDetail,
742 _("Search results for outfits matching '%s':"), name );
743 if (i < 0) {
744 array_free( map_foundOutfitNames );
745 map_foundOutfitNames = NULL;
746 return 0;
747 }
748 o = outfit_get( map_foundOutfitNames[i] );
749 }
750 array_free( map_foundOutfitNames );
751 map_foundOutfitNames = NULL;
752 if (o == NULL)
753 return -1;
754
755 /* Construct found table. */
756 found = NULL;
757 n = 0;
758 len = array_size(map_known_techs);
759 for (int i=0; i<len; i++) {
760 /* Try to find the outfit in the spob. */
761 int j;
762 Spob *spob;
763 StarSystem *sys;
764 Outfit **olist = tech_getOutfit( map_known_techs[i] );
765 for (j=array_size(olist)-1; j>=0; j--)
766 if (olist[j] == o)
767 break;
768 array_free( olist );
769 olist = NULL;
770 if (j < 0)
771 continue;
772 spob = map_known_spobs[i];
773
774 /* Must have an outfitter. */
775 if (!spob_hasService(spob,SPOB_SERVICE_OUTFITS))
776 continue;
777
778 /* System must be known. */
779 sysname = spob_getSystem( spob->name );
780 if (sysname == NULL)
781 continue;
782 sys = system_get( sysname );
783 if (!sys_isKnown(sys))
784 continue;
785
786 if (found == NULL) /* Allocate results array on first match. */
787 found = malloc( sizeof(map_find_t) * len );
788
789 map_findAccumulateResult( found, n, sys, spob );
790 n++;
791 }
792
793 /* No visible match. */
794 if (n==0)
795 return -1;
796
797 /* Display results. */
798 map_findDisplayResult( wid_map_find, found, n );
799 return 0;
800}
801
805static char **map_fuzzyShips( Ship **s, const char *name )
806{
807 char **names = array_create( char* );
808
809 /* Do fuzzy search. */
810 for (int i=0; i<array_size(s); i++) {
811 if (strcasestr( _(s[i]->name), name ) != NULL)
812 array_push_back( &names, s[i]->name );
813 else if ((s[i]->license != NULL) && strcasestr( _(s[i]->license), name ) != NULL)
814 array_push_back( &names, s[i]->name );
815 else if (strcasestr( _(ship_classDisplay( s[i] )), name ) != NULL)
816 array_push_back( &names, s[i]->name );
817 else if (strcasestr( _(s[i]->fabricator), name ) != NULL)
818 array_push_back( &names, s[i]->name );
819 else if (strcasestr( _(s[i]->description), name ) != NULL)
820 array_push_back( &names, s[i]->name );
821 }
822
823 return names;
824}
828static char **map_shipsMatch( const char *name )
829{
830 Ship **s;
831 char **names;
832
833 /* Get ships and names. */
834 s = tech_getShipArray( map_known_techs, array_size( map_known_techs ) );
835 names = map_fuzzyShips( s, name );
836 array_free(s);
837
838 return names;
839}
840
847static int map_findSearchShips( unsigned int wid_map_find, const char *name )
848{
849 char **names;
850 int len, n;
851 map_find_t *found;
852 Spob *spob;
853 StarSystem *sys;
854 const char *sname, *sysname;
855 char **list;
856 const Ship *s;
857 Ship **slist;
858
859 /* Match spob first. */
860 s = NULL;
861 sname = ship_existsCase( name );
862 names = map_shipsMatch( name );
863 len = array_size( names );
864 if ((sname != NULL) && (len == 1))
865 s = ship_get( sname );
866 /* Handle fuzzy matching. */
867 else if (len > 0) {
868 int i;
869 /* Ask which one player wants. */
870 list = malloc( len*sizeof(char*) );
871 for (i=0; i<len; i++)
872 list[i] = strdup( _(names[i]) );
873 i = dialogue_list( _("Search Results"), list, len,
874 _("Search results for ships matching '%s':"), name );
875 if (i < 0) {
876 array_free(names);
877 return 0;
878 }
879 s = ship_get( names[i] );
880 }
881 array_free(names);
882 names = NULL;
883 if (s == NULL)
884 return -1;
885
886 /* Construct found table. */
887 found = NULL;
888 n = 0;
889 len = array_size(map_known_techs);
890 for (int i=0; i<len; i++) {
891 int j;
892
893 /* Try to find the ship in the spob. */
894 slist = tech_getShip( map_known_techs[i] );
895 for (j=array_size(slist)-1; j>=0; j--)
896 if (slist[j] == s)
897 break;
898 array_free(slist);
899 slist = NULL;
900 if (j < 0)
901 continue;
902 spob = map_known_spobs[i];
903
904 /* Must have an shipyard. */
905 if (!spob_hasService(spob,SPOB_SERVICE_SHIPYARD))
906 continue;
907
908 /* System must be known. */
909 sysname = spob_getSystem( spob->name );
910 if (sysname == NULL)
911 continue;
912 sys = system_get( sysname );
913 if (!sys_isKnown(sys))
914 continue;
915
916 if (found == NULL) /* Allocate results array on first match. */
917 found = malloc( sizeof(map_find_t) * len );
918
919 map_findAccumulateResult( found, n, sys, spob );
920 n++;
921 }
922
923 /* No visible match. */
924 if (n==0)
925 return -1;
926
927 /* Display results. */
928 map_findDisplayResult( wid_map_find, found, n );
929 return 0;
930}
931
935static void map_findSearch( unsigned int wid_map_find, const char* str )
936{
937 int ret;
938 const char *name, *searchname;
939
940 /* Get the name. */
941 name = window_getInput( wid_map_find, "inpSearch" );
942 if (name[0] == '\0')
943 return;
944
945 /* Prevent reentrancy, e.g. the toolkit spontaneously deciding a future mouseup event was the
946 * user releasing the clicked "Find" button and should reactivate it, never mind that they were
947 * actually clicking on the dialogue_listPanel we opened to present the results.
948 * FIXME: That behavior doesn't seem right, but I'm not sure if it's an actual bug or not. */
949 window_disableButton( wid_map_find, "btnSearch" );
950
951 /* Clean up if necessary. */
952 free( map_found_cur );
953 map_found_cur = NULL;
954
955 /* Handle different search cases. */
956 if (map_find_systems) {
957 ret = map_findSearchSystems( wid_map_find, name );
958 searchname = _("System");
959 }
960 else if (map_find_spobs) {
961 ret = map_findSearchSpobs( wid_map_find, name );
962 searchname = _("Space Objects");
963 }
964 else if (map_find_outfits) {
965 ret = map_findSearchOutfits( wid_map_find, name );
966 searchname = _("Outfit");
967 }
968 else if (map_find_ships) {
969 ret = map_findSearchShips( wid_map_find, name );
970 searchname = _("Ship");
971 }
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:") );
1011 y -= 30;
1012
1013 /* Create input. */
1014 window_addInput( wid_map_find, 30, y, w - 60, 20,
1015 "inpSearch", 32, 1, &gl_defFont );
1016 y -= 40;
1017
1018 /* Create buttons. */
1019 window_addButton( wid_map_find, -30, 20+BUTTON_HEIGHT+20, BUTTON_WIDTH, BUTTON_HEIGHT,
1020 "btnSearch", _("Find"), map_findSearch );
1021 window_addButton( wid_map_find, -30, 20, BUTTON_WIDTH, BUTTON_HEIGHT,
1022 "btnClose", _("Close"), window_close );
1023
1024 /* Create check boxes. */
1025 x = 40;
1026 window_addCheckbox( wid_map_find, x, y, 160, 20,
1027 "chkSystem", _("Systems"), map_findCheckUpdate, map_find_systems );
1028 y -= 20;
1029 window_addCheckbox( wid_map_find, x, y, 160, 20,
1030 "chkSpob", _("Space Objects"), map_findCheckUpdate, map_find_spobs );
1031 y -= 20;
1032 window_addCheckbox( wid_map_find, x, y, 160, 20,
1033 "chkOutfit", _("Outfits"), map_findCheckUpdate, map_find_outfits );
1034 y -= 20;
1035 window_addCheckbox( wid_map_find, x, y, 160, 20,
1036 "chkShip", _("Ships"), map_findCheckUpdate, map_find_ships );
1037}
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
#define BUTTON_HEIGHT
Definition: board.c:33
#define BUTTON_WIDTH
Definition: board.c:32
void dialogue_alert(const char *fmt,...)
Displays an alert popup with only an ok button and a message.
Definition: dialogue.c:132
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:621
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:576
int gl_printHeightRaw(const glFont *ft_font, const int width, const char *text)
Gets the height of a non-formatted string.
Definition: font.c:1026
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
char * strcasestr(const char *haystack, const char *needle)
Finds a string inside another string case insensitively.
Definition: nstring.c:68
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:178
const char * outfit_description(const Outfit *o)
Gets the description of an outfit.
Definition: outfit.c:955
const char * outfit_summary(const Outfit *o, int withname)
Gets the summary of an outfit.
Definition: outfit.c:969
const Outfit * outfit_get(const char *name)
Gets an outfit by name.
Definition: outfit.c:118
int outfit_isLauncher(const Outfit *o)
Checks if outfit is a weapon launcher.
Definition: outfit.c:498
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:394
int outfit_isFighterBay(const Outfit *o)
Checks if outfit is a fighter bay.
Definition: outfit.c:550
int outfit_amount(const Outfit *o)
Gets the amount an outfit can hold.
Definition: outfit.c:670
const char * outfit_existsCase(const char *name)
Checks to see if an outfit exists matching name (case insensitive).
Definition: outfit.c:149
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:73
int player_outfitOwned(const Outfit *o)
Gets how many of the outfit the player owns.
Definition: player.c:2701
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:162
const Ship * ship_get(const char *name)
Gets a ship based on its name.
Definition: ship.c:73
const char * ship_existsCase(const char *name)
Checks to see if an ship exists matching name (case insensitive).
Definition: ship.c:96
Spob * spob_get(const char *spobname)
Gets a spob based on its name.
Definition: space.c:1006
const char * spob_getSymbol(const Spob *p)
Gets the spob symbol.
Definition: space.c:1853
char spob_getColourChar(const Spob *p)
Gets the spob colour char.
Definition: space.c:1834
const char * system_existsCase(const char *sysname)
Checks to see if a system exists case insensitively.
Definition: space.c:858
StarSystem * system_getAll(void)
Gets an array (array.h) of all star systems.
Definition: space.c:847
char ** spob_searchFuzzyCase(const char *spobname, int *n)
Does a fuzzy case matching. Searches spob_name() but returns internal names.
Definition: space.c:1107
char ** system_searchFuzzyCase(const char *sysname, int *n)
Does a fuzzy case matching. Searches translated names but returns internal names.
Definition: space.c:869
StarSystem * system_get(const char *sysname)
Get the system from its name.
Definition: space.c:914
char * spob_getSystem(const char *spobname)
Get the name of a system from a spobname.
Definition: space.c:980
StarSystem * cur_system
Definition: space.c:105
const char * spob_existsCase(const char *spobname)
Check to see if a spob exists (case insensitive).
Definition: space.c:1096
void spob_updateLand(Spob *p)
Updates the land possibilities of a spob.
Definition: space.c:1896
const char * spob_name(const Spob *p)
Gets the translated name of a spob.
Definition: space.c:1705
double ammo_mass
Definition: outfit.h:204
A ship outfit, depends radically on the type.
Definition: outfit.h:304
credits_t price
Definition: outfit.h:322
OutfitLauncherData lau
Definition: outfit.h:373
glTexture * gfx_store
Definition: outfit.h:328
OutfitFighterBayData bay
Definition: outfit.h:376
char * license
Definition: outfit.h:312
double mass
Definition: outfit.h:315
union Outfit::@22 u
Solid * solid
Definition: pilot.h:220
credits_t credits
Definition: pilot.h:317
Pilot * p
Definition: player.h:101
Represents a space ship.
Definition: ship.h:94
vec2 pos
Definition: physics.h:22
Represents a Space Object (SPOB), including and not limited to planets, stations, wormholes,...
Definition: space.h:88
tech_group_t * tech
Definition: space.h:116
char * name
Definition: space.h:90
vec2 pos
Definition: space.h:93
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:799
Ship ** tech_getShip(const tech_group_t *tech)
Gets all of the ships associated to a tech group.
Definition: tech.c:773
Outfit ** tech_getOutfitArray(tech_group_t **tech, int num)
Gets the outfits from an array of techs.
Definition: tech.c:750
Outfit ** tech_getOutfit(const tech_group_t *tech)
Gets all of the outfits associated to a tech group.
Definition: tech.c:725
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:696
unsigned int window_getParent(unsigned int wid)
Gets the window's parent.
Definition: toolkit.c:820
void window_setAccept(unsigned int wid, void(*accept)(unsigned int, const char *))
Sets the default accept function of the window.
Definition: toolkit.c:879
void window_setCancel(unsigned int wid, void(*cancel)(unsigned int, const char *))
Sets the default cancel function of the window.
Definition: toolkit.c:900
void window_onClose(unsigned int wid, void(*fptr)(unsigned int, const char *))
Sets the default close function of the window.
Definition: toolkit.c:840
void window_moveWidget(unsigned int wid, const char *name, int x, int y)
Moves a widget.
Definition: toolkit.c:467
void window_setParent(unsigned int wid, unsigned int parent)
Sets a window as a window's parent.
Definition: toolkit.c:803
void window_resizeWidget(unsigned int wid, const char *name, int w, int h)
Resizes a widget.
Definition: toolkit.c:495
void window_close(unsigned int wid, const char *str)
Helper function to automatically close the window calling it.
Definition: toolkit.c:1031