naev 0.12.5
land_outfits.c
Go to the documentation of this file.
1/*
2 * See Licensing and Copyright notice in naev.h
3 */
10#include <math.h>
11#include <stdio.h>
12#include <stdlib.h>
13
14#include "naev.h"
16
17#include "land_outfits.h"
18
19#include "array.h"
20#include "cond.h"
21#include "dialogue.h"
22#include "equipment.h"
23#include "hook.h"
24#include "land.h"
25#include "log.h"
26#include "map.h"
27#include "naevpedia.h"
28#include "nlua.h"
29#include "nstring.h"
30#include "outfit.h"
31#include "pilot_outfit.h"
32#include "player.h"
33#include "player_gui.h"
34#include "slots.h"
35#include "space.h"
36#include "toolkit.h"
37#include "utf8.h"
38
39#define OUTFITS_IAR "iarOutfits"
40#define OUTFITS_TAB "tabOutfits"
41#define OUTFITS_FILTER "inpFilterOutfits"
42#define OUTFITS_NTABS 7
43
46typedef struct LandOutfitData_ {
47 const Outfit *
51
52static iar_data_t iar_data[OUTFITS_NTABS];
53static Outfit *
54 *iar_outfits[OUTFITS_NTABS];
56static int outfit_Mode = 0;
58 NULL;
59
60/* Modifier for buying and selling quantity. */
61static int outfits_mod = 1;
62
63/*
64 * Helper functions.
65 */
66static void outfits_getSize( unsigned int wid, int *w, int *h, int *iw, int *ih,
67 int *bw, int *bh );
68static void outfits_buy( unsigned int wid, const char *str );
69static void outfits_sell( unsigned int wid, const char *str );
70static int outfits_getMod( void );
71static void outfits_rmouse( unsigned int wid, const char *widget_name );
72static void outfits_naevpedia( unsigned int wid, const char *str );
73static const char *outfit_getPrice( const Outfit *outfit, credits_t *price,
74 int *canbuy, int *cansell,
75 char **player_has );
76static void outfit_Popdown( unsigned int wid, const char *str );
77static void outfits_genList( unsigned int wid );
78static void outfits_changeTab( unsigned int wid, const char *wgt, int old,
79 int tab );
80static void outfits_onClose( unsigned int wid, const char *str );
81static void outfit_modifiers( unsigned int wid );
82static int outfit_events( unsigned int wid, SDL_Event *evt );
83
87static void outfits_getSize( unsigned int wid, int *w, int *h, int *iw, int *ih,
88 int *bw, int *bh )
89{
90 int padding;
91
92 /* Get window dimensions. */
93 window_dimWindow( wid, w, h );
94
95 /* Calculate image array dimensions. */
96 if ( iw != NULL )
97 *iw = 680 + ( *w - LAND_WIDTH );
98 if ( ih != NULL )
99 *ih = *h - 60;
100
101 /* Left padding + per-button padding * nbuttons */
102 padding = 40 + 20 * 4;
103
104 /* Calculate button dimensions. */
105 if ( bw != NULL )
106 *bw = ( *w - ( iw != NULL ? *iw : 0 ) - padding ) / 4;
107 if ( bh != NULL )
108 *bh = LAND_BUTTON_HEIGHT;
109}
110
111static void outfit_modifiers( unsigned int wid )
112{
113 int q = outfits_getMod();
114 if ( q != outfits_mod ) {
116 outfits_mod = q;
117 if ( q == 1 ) {
118 window_buttonCaption( wid, "btnBuyOutfit", _( "Buy" ) );
119 window_buttonCaption( wid, "btnSellOutfit", _( "Sell" ) );
120 } else {
121 char buf[STRMAX_SHORT];
122 snprintf( buf, sizeof( buf ), _( "Buy (%dx)" ), q );
123 window_buttonCaption( wid, "btnBuyOutfit", buf );
124 snprintf( buf, sizeof( buf ), _( "Sell (%dx)" ), q );
125 window_buttonCaption( wid, "btnSellOutfit", buf );
126 }
128 }
129}
130
134static int outfit_events( unsigned int wid, SDL_Event *evt )
135{
136 (void)evt; /* For constness warning. */
137 if ( ( evt->type == SDL_KEYDOWN ) || ( evt->type == SDL_KEYUP ) )
138 outfit_modifiers( wid );
139 return 0;
140}
141
145static void outfits_onClose( unsigned int wid, const char *str )
146{
147 (void)str;
148 LandOutfitData *data = window_getData( wid );
149 if ( data != NULL ) {
150 array_free( data->outfits );
151 free( data );
152 }
153}
154
163void outfits_open( unsigned int wid, const Outfit **outfits, int blackmarket )
164{
165 int w, h, iw, ih, bw, bh, off;
166 LandOutfitData *data = NULL;
167
168 /* Clear sold outfits. */
170 outfits_sold = NULL;
171
172 /* initialize the outfit mode. */
173 outfit_Mode = 0;
174 data = malloc( sizeof( LandOutfitData ) );
175 data->outfits = outfits;
176 data->blackmarket = blackmarket;
177 window_setData( wid, data );
179
180 /* Mark as generated. */
181 if ( outfits == NULL )
182 land_tabGenerate( LAND_WINDOW_OUTFITS );
183
184 /* Get dimensions. */
185 outfits_getSize( wid, &w, &h, &iw, &ih, &bw, &bh );
186
187 /* Initialize stored positions. */
188 for ( int i = 0; i < OUTFITS_NTABS; i++ ) {
189 toolkit_initImageArrayData( &iar_data[i] );
191 }
192 memset( iar_outfits, 0, sizeof( Outfit ** ) * OUTFITS_NTABS );
193
194 /* will allow buying from keyboard */
196
197 /* handle multipliers. */
199 window_setOnFocus( wid, outfit_modifiers );
200
201 /* buttons */
202 off = -20;
203 if ( data->outfits == NULL ) {
204 window_addButtonKey( wid, off, 20, bw, bh, "btnCloseOutfits",
205 _( "Take Off" ), land_buttonTakeoff, SDLK_t );
206 } else {
207 window_addButtonKey( wid, off, 20, bw, bh, "btnCloseOutfits",
208 _( "Close" ), window_close, SDLK_t );
209 }
210 off -= 20 + bw;
211 window_addButtonKey( wid, off, 20, bw, bh, "btnSellOutfit", _( "Sell" ),
212 outfits_sell, SDLK_s );
213 off -= 20 + bw;
214 window_addButtonKey( wid, off, 20, bw, bh, "btnBuyOutfit", _( "Buy" ),
215 outfits_buy, SDLK_b );
216 off -= 20 + bw;
217 window_addButtonKey( wid, off, 20, bw, bh, "btnNaevpediaOutfits",
218 _( "Archives" ), outfits_naevpedia, SDLK_a );
219
220 /* fancy 256x256 image */
221 window_addRect( wid, -40 + 4, -40 + 4, 264, 264, "rctImage", &cBlack, 1 );
222 window_addImage( wid, -40, -40, 256, 256, "imgOutfit", NULL, 0 );
223
224 /* the descriptive text */
225 window_addText( wid, 20 + iw + 20, -40, w - ( 20 + iw + 20 ) - 264 - 40, 160,
226 0, "txtOutfitName", &gl_defFont, NULL, NULL );
227 window_addText( wid, 20 + iw + 20, -40 - gl_defFont.h * 2. - 30,
228 w - ( 20 + iw + 20 ) - 264 - 40, 400, 0, "txtDescShort",
229 &gl_defFont, NULL, NULL );
230
231 window_addText( wid, 20 + iw + 20, 0, 90, 160, 0, "txtSDesc", &gl_defFont,
232 &cFontGrey, NULL );
233 window_addText( wid, 20 + iw + 20 + 90, 0, w - ( 20 + iw + 20 + 90 ), 160, 0,
234 "txtDDesc", &gl_defFont, NULL, NULL );
235 window_addText( wid, 20 + iw + 20, 0, w - ( iw + 80 ),
236 h, /* TODO: Size exactly and resize instead of moving? */
237 0, "txtDescription", &gl_defFont, NULL, NULL );
238
239 /* Create the image array. */
240 outfits_genList( wid );
241
242 /* Set default keyboard focus to the list */
243 window_setFocus( wid, OUTFITS_IAR );
244}
245
252void outfits_regenList( unsigned int wid, const char *str )
253{
254 (void)str;
255 int tab;
256 char *focused;
257 LandOutfitData *data;
258
259 /* If local or not. */
260 data = window_getData( wid );
261
262 /* Must exist. */
263 if ( ( data->outfits == NULL ) &&
264 ( land_getWid( LAND_WINDOW_OUTFITS ) == 0 ) )
265 return;
266
267 /* Save focus. */
268 focused = window_getFocus( wid );
269
270 /* Save positions. */
271 tab = window_tabWinGetActive( wid, OUTFITS_TAB );
272 toolkit_saveImageArrayData( wid, OUTFITS_IAR, &iar_data[tab] );
273 window_destroyWidget( wid, OUTFITS_IAR );
274
275 outfits_genList( wid );
276
277 /* Restore positions. */
278 toolkit_loadImageArrayData( wid, OUTFITS_IAR, &iar_data[tab] );
279 outfits_update( wid, NULL );
280
281 /* Restore focus. */
282 window_setFocus( wid, focused );
283 free( focused );
284}
285
289
290static int outfitLand_filter( const Outfit *o )
291{
292 Pilot *p;
293 const PlayerShip_t *ps;
294
295 switch ( outfit_Mode ) {
296 case 0:
297 return 1;
298
299 case 1: /* Fits any ship of the player. */
300 ps = player_getShipStack();
301 for ( int j = 0; j < array_size( ps ); j++ ) {
302 p = ps[j].p;
303 for ( int i = 0; i < array_size( p->outfits ); i++ ) {
304 if ( outfit_fitsSlot( o, &p->outfits[i]->sslot->slot ) )
305 return 1;
306 }
307 }
308 return 0;
309
310 case 2: /* Fits currently selected ship. */
311 p = player.p;
312 if ( p == NULL )
313 return 1;
314 for ( int i = 0; i < array_size( p->outfits ); i++ ) {
315 if ( outfit_fitsSlot( o, &p->outfits[i]->sslot->slot ) )
316 return 1;
317 }
318 return 0;
319
320 case 3:
321 return ( o->slot.size == OUTFIT_SLOT_SIZE_LIGHT );
322 case 4:
323 return ( o->slot.size == OUTFIT_SLOT_SIZE_MEDIUM );
324 case 5:
325 return ( o->slot.size == OUTFIT_SLOT_SIZE_HEAVY );
326 }
327 return 1;
328}
329static int outfitLand_filterWeapon( const Outfit *o )
330{
331 return outfitLand_filter( o ) && outfit_filterWeapon( o );
332}
333static int outfitLand_filterUtility( const Outfit *o )
334{
335 return outfitLand_filter( o ) && outfit_filterUtility( o );
336}
337static int outfitLand_filterStructure( const Outfit *o )
338{
339 return outfitLand_filter( o ) && outfit_filterStructure( o );
340}
341static int outfitLand_filterCore( const Outfit *o )
342{
343 return outfitLand_filter( o ) && outfit_filterCore( o );
344}
345
351static void outfits_genList( unsigned int wid )
352{
353 int ( *tabfilters[] )( const Outfit *o ) = {
354 outfitLand_filter, outfitLand_filterWeapon,
355 outfitLand_filterUtility, outfitLand_filterStructure,
356 outfitLand_filterCore, outfit_filterOther,
358 };
359
360 int active;
361 ImageArrayCell *coutfits;
362 int noutfits;
363 int w, h, iw, ih;
364 const char *filtertext;
365 LandOutfitData *data;
366 int iconsize;
367
368 /* Get dimensions. */
369 outfits_getSize( wid, &w, &h, &iw, &ih, NULL, NULL );
370
371 /* Create tabbed window. */
372 if ( !widget_exists( wid, OUTFITS_TAB ) ) {
373 int fx, fy, fw, fh, barw; /* Input filter. */
374 const char *tabnames[] = {
375 _( "All" ),
376 _( OUTFIT_LABEL_WEAPON ),
377 _( OUTFIT_LABEL_UTILITY ),
378 _( OUTFIT_LABEL_STRUCTURE ),
379 _( OUTFIT_LABEL_CORE ),
380 _( "#rOther" ),
381 _( "Owned" ),
382 };
383
384 window_addTabbedWindow( wid, 20, 20 + ih - 30, iw, 30, OUTFITS_TAB,
385 OUTFITS_NTABS, tabnames, 1 );
386
387 barw = window_tabWinGetBarWidth( wid, OUTFITS_TAB );
388 fw = CLAMP( 0, 150, iw - barw - 30 );
389 fh = 30;
390
391 fx = iw - fw + 15;
392 fy = ih - 25 - 1 + 20;
393
394 /* Only create the filter widgets if it will be a reasonable size. */
395 if ( iw >= 65 ) {
396 /* Add popdown menu stuff. */
397 window_addButton( wid, fx + fw - 30, fy, 30, 30, "btnOutfitFilter",
398 NULL, outfit_Popdown );
399 window_buttonCustomRender( wid, "btnOutfitFilter",
400 window_buttonCustomRenderGear );
401 fw -= 35;
402
403 /* Set text filter. */
404 window_addInput( wid, fx, fy, fw, fh, OUTFITS_FILTER, 32, 1,
405 &gl_defFont );
406 inp_setEmptyText( wid, OUTFITS_FILTER, _( "Filter…" ) );
407 window_setInputCallback( wid, OUTFITS_FILTER, outfits_regenList );
408 }
409 }
410
411 window_tabWinOnChange( wid, OUTFITS_TAB, outfits_changeTab );
412 active = window_tabWinGetActive( wid, OUTFITS_TAB );
413
414 /* Widget must not already exist. */
415 if ( widget_exists( wid, OUTFITS_IAR ) )
416 return;
417
418 filtertext = NULL;
419 if ( widget_exists( wid, OUTFITS_FILTER ) ) {
420 filtertext = window_getInput( wid, OUTFITS_FILTER );
421 if ( strlen( filtertext ) == 0 )
422 filtertext = NULL;
423 }
424
425 /* Set up the outfits to buy/sell */
426 data = window_getData( wid );
427 array_free( iar_outfits[active] );
428
429 if ( active == 6 ) {
430 /* Show player their owned outfits. */
431 const PlayerOutfit_t *po = player_getOutfits();
432 iar_outfits[active] = array_create( Outfit * );
433 for ( int i = 0; i < array_size( po ); i++ )
434 array_push_back( &iar_outfits[active], (Outfit *)po[i].o );
435 /* Also add stuff they sold. */
436 for ( int i = 0; i < array_size( outfits_sold ); i++ ) {
438 int found = 0;
439 for ( int j = 0; j < array_size( po ); j++ ) {
440 if ( po[j].o == os->o ) {
441 found = 1;
442 break;
443 }
444 }
445 if ( !found )
446 array_push_back( &iar_outfits[active], (Outfit *)os->o );
447 }
448 qsort( iar_outfits[active], array_size( iar_outfits[active] ),
449 sizeof( Outfit * ), outfit_compareTech );
450 } else {
451 /* Use custom list; default to landed outfits. */
452 iar_outfits[active] = ( data->outfits != NULL )
453 ? array_copy( Outfit *, data->outfits )
454 : tech_getOutfit( land_spob->tech );
455 }
456 noutfits = outfits_filter( (const Outfit **)iar_outfits[active],
457 array_size( iar_outfits[active] ),
458 tabfilters[active], filtertext );
459 coutfits = outfits_imageArrayCells( (const Outfit **)iar_outfits[active],
460 &noutfits, player.p, 1 );
461
462 iconsize = 128;
463 if ( !conf.big_icons ) {
464 if ( toolkit_simImageArrayVisibleElements( iw, ih - 34, iconsize,
465 iconsize ) < noutfits )
466 iconsize = 96;
467 if ( toolkit_simImageArrayVisibleElements( iw, ih - 34, iconsize,
468 iconsize ) < noutfits )
469 iconsize = 64;
470 }
471 window_addImageArray( wid, 20, 20, iw, ih - 34, OUTFITS_IAR, iconsize,
472 iconsize, coutfits, noutfits, outfits_update,
473 outfits_rmouse, NULL );
474
475 /* write the outfits stuff */
476 outfits_update( wid, NULL );
477}
478
484void outfits_update( unsigned int wid, const char *str )
485{
486 (void)str;
487 int i, active;
488 Outfit *outfit;
489 char buf[STRMAX], lbl[STRMAX], buf_credits[ECON_CRED_STRLEN],
490 buf_mass[ECON_MASS_STRLEN];
491 const char *buf_price, *summary;
492 credits_t price;
493 size_t l = 0, k = 0;
494 int iw, ih, w, h, blackmarket, canbuy, cansell, sw, th;
495 double mass;
496 char *youhave;
497
498 /* Get dimensions. */
499 outfits_getSize( wid, &w, &h, &iw, &ih, NULL, NULL );
500
501 /* See if black market. */
502 const LandOutfitData *data = window_getData( wid );
503 blackmarket = data->blackmarket;
504
505 /* Set up keys. */
506 k += scnprintf( &lbl[k], sizeof( lbl ) - k, "%s", _( "Owned:" ) );
507 k += scnprintf( &lbl[k], sizeof( lbl ) - k, "\n%s", _( "Mass:" ) );
508 k += scnprintf( &lbl[k], sizeof( lbl ) - k, "\n%s", _( "Price:" ) );
509 k += scnprintf( &lbl[k], sizeof( lbl ) - k, "\n%s", _( "You have:" ) );
510
511 /* Get and set parameters. */
512 active = window_tabWinGetActive( wid, OUTFITS_TAB );
513 i = toolkit_getImageArrayPos( wid, OUTFITS_IAR );
514 if ( i < 0 || array_size( iar_outfits[active] ) == 0 ) { /* No outfits */
515 window_modifyImage( wid, "imgOutfit", NULL, 256, 256 );
516 window_disableButton( wid, "btnBuyOutfit" );
517 window_disableButton( wid, "btnSellOutfit" );
518 l += scnprintf( &buf[l], sizeof( buf ) - l, "%s", _( "N/A" ) );
519 l += scnprintf( &buf[l], sizeof( buf ) - l, "\n%s", _( "N/A" ) );
520 l += scnprintf( &buf[l], sizeof( buf ) - l, "\n%s", _( "N/A" ) );
521 /*l +=*/scnprintf( &buf[l], sizeof( buf ) - l, "\n%s", _( "N/A" ) );
522 window_modifyText( wid, "txtSDesc", buf );
523 window_modifyText( wid, "txtDDesc", buf );
524 window_modifyText( wid, "txtOutfitName", _( "None" ) );
525 window_modifyText( wid, "txtDescShort", NULL );
526 window_modifyText( wid, "txtDescription", NULL );
527 /* Reposition. */
528 th = 260;
529 window_moveWidget( wid, "txtSDesc", 20 + iw + 20, -40 - th - 30 - 32 );
530 window_moveWidget( wid, "txtDDesc", 20 + iw + 20 + 90,
531 -40 - th - 30 - 32 );
532 window_moveWidget( wid, "txtDescription", 20 + iw + 20, -240 - 32 );
533 return;
534 }
535
536 i = MIN( i, array_size( iar_outfits[active] ) - 1 );
537 outfit = iar_outfits[active][i];
538
539 /* new image */
540 window_modifyImage( wid, "imgOutfit", outfit->gfx_store, 256, 256 );
541
542 /* new text */
543 if ( outfit->slot.type == OUTFIT_SLOT_INTRINSIC ) {
544 scnprintf( buf, sizeof( buf ), "%s\n\n#o%s#0", _( outfit->desc_raw ),
545 _( "This is an intrinsic outfit that will be directly "
546 "equipped on the current ship and can not be moved." ) );
547 window_modifyText( wid, "txtDescription", buf );
548 } else
549 window_modifyText( wid, "txtDescription", _( outfit->desc_raw ) );
550 buf_price = outfit_getPrice( outfit, &price, &canbuy, &cansell, &youhave );
551 credits2str( buf_credits, player.p->credits, 2 );
552
553 /* gray out sell button */
554 if ( ( outfit_canSell( outfit ) > 0 ) && cansell )
555 window_enableButton( wid, "btnSellOutfit" );
556 else
557 window_disableButtonSoft( wid, "btnSellOutfit" );
558
559 if ( ( outfit_canBuy( outfit, wid ) > 0 ) && canbuy )
560 window_enableButton( wid, "btnBuyOutfit" );
561 else
562 window_disableButtonSoft( wid, "btnBuyOutfit" );
563
564 mass = outfit->mass;
565 if ( outfit_isLauncher( outfit ) )
566 mass += outfit_amount( outfit ) * outfit->u.lau.ammo_mass;
567 else if ( outfit_isFighterBay( outfit ) )
568 mass += outfit_amount( outfit ) * outfit->u.bay.ship_mass;
569 tonnes2str( buf_mass, (int)round( mass ) );
570
571 outfit_getNameWithClass( outfit, buf, sizeof( buf ) );
572 window_modifyText( wid, "txtOutfitName", buf );
573 window_dimWidget( wid, "txtOutfitName", &sw, NULL );
574 th = gl_printHeightRaw( &gl_defFont, sw, buf ) + gl_defFont.h / 2;
575 l = 0;
576 l += scnprintf( &buf[l], sizeof( buf ) - l, "%d",
577 player_outfitOwned( outfit ) );
578 l += scnprintf( &buf[l], sizeof( buf ) - l, "\n%s", buf_mass );
579 l += scnprintf( &buf[l], sizeof( buf ) - l, "\n%s", buf_price );
580 l += scnprintf( &buf[l], sizeof( buf ) - l, "\n%s",
581 ( ( youhave ) != NULL ) ? youhave : buf_credits );
582 if ( outfit->license ) {
583 int meets_reqs = player_hasLicense( outfit->license );
584 k += scnprintf( &lbl[k], sizeof( lbl ) - k, "\n%s", _( "License:" ) );
585 if ( blackmarket )
586 l += scnprintf( &buf[l], sizeof( buf ) - l, "\n%s#0",
587 _( "Not Necessary (Blackmarket)" ) );
588 else
589 l += scnprintf( &buf[l], sizeof( buf ) - l, "\n%s%s#0",
590 meets_reqs ? "" : "#r", _( outfit->license ) );
591 }
592 if ( outfit->cond ) {
593 int meets_reqs = 0;
594 if ( land_spob != NULL )
595 meets_reqs = cond_check( outfit->cond );
596 /*k +=*/scnprintf( &lbl[k], sizeof( lbl ) - k, "\n%s", _( "Requires:" ) );
597 if ( blackmarket )
598 /*l +=*/scnprintf( &buf[l], sizeof( buf ) - l, "\n%s#0",
599 _( "Not Necessary (Blackmarket)" ) );
600 else
601 /*l +=*/scnprintf( &buf[l], sizeof( buf ) - l, "\n%s%s#0",
602 meets_reqs ? "" : "#r", _( outfit->condstr ) );
603 }
604 window_modifyText( wid, "txtSDesc", lbl );
605 window_modifyText( wid, "txtDDesc", buf );
606 summary = pilot_outfitSummary( player.p, outfit, 0 );
607 window_modifyText( wid, "txtDescShort", summary );
608 window_moveWidget( wid, "txtDescShort", 20 + iw + 20, -40 - th );
609 window_dimWidget( wid, "txtDescShort", &sw, NULL );
610 th += gl_printHeightRaw( &gl_defFont, sw, summary );
611 th = MAX( th + gl_defFont.h / 2, 240 );
612 window_moveWidget( wid, "txtSDesc", 20 + iw + 20, -40 - th );
613 window_moveWidget( wid, "txtDDesc", 20 + iw + 20 + 90, -40 - th );
614 window_dimWidget( wid, "txtDDesc", &sw, NULL );
615 th += gl_printHeightRaw( &gl_defFont, sw, buf );
616 th = MAX( th + gl_defFont.h / 2, 256 + 10 );
617 window_moveWidget( wid, "txtDescription", 20 + iw + 20, -40 - th );
618}
619
624{
625 if ( landed && ( land_spob != NULL ) && land_doneLoading() ) {
626 if ( spob_hasService( land_spob, SPOB_SERVICE_OUTFITS ) ) {
627 int ow = land_getWid( LAND_WINDOW_OUTFITS );
628 outfits_regenList( ow, NULL );
629 } else if ( !spob_hasService( land_spob, SPOB_SERVICE_SHIPYARD ) )
630 return;
631
632 int ew = land_getWid( LAND_WINDOW_EQUIPMENT );
634 equipment_regenLists( ew, 1, 0 );
635 }
636}
637
646static void outfits_changeTab( unsigned int wid, const char *wgt, int old,
647 int tab )
648{
649 (void)wgt;
650 iar_data_t old_data;
651
652 toolkit_saveImageArrayData( wid, OUTFITS_IAR, &iar_data[old] );
653
654 /* Store the currently-saved positions for the new tab. */
655 old_data = iar_data[tab];
656
657 /* Resetting the input will cause the outfit list to be regenerated. */
658 if ( widget_exists( wid, OUTFITS_FILTER ) )
659 window_setInput( wid, OUTFITS_FILTER, NULL );
660 else
661 outfits_regenList( wid, NULL );
662
663 /* Set positions for the new tab. This is necessary because the stored
664 * position for the new tab may have exceeded the size of the old tab,
665 * resulting in it being clipped. */
666 toolkit_loadImageArrayData( wid, OUTFITS_IAR, &old_data );
667
668 /* Focus the outfit image array. */
669 window_setFocus( wid, OUTFITS_IAR );
670}
671
681int outfits_filter( const Outfit **outfits, int n,
682 int ( *filter )( const Outfit * ), const char *name )
683{
684 int j = 0;
685 for ( int i = 0; i < n; i++ ) {
686 const Outfit *o = outfits[i];
687
688 /* First run filter. */
689 if ( ( filter != NULL ) && !filter( outfits[i] ) )
690 continue;
691
692 /* Try to match name somewhere. */
693 if ( name != NULL ) {
694 if ( ( SDL_strcasestr( _( o->name ), name ) == NULL ) &&
695 ( SDL_strcasestr( _( outfit_getType( o ) ), name ) == NULL ) )
696 continue;
697 }
698
699 /* Shift matches downward. */
700 outfits[j++] = o;
701 }
702
703 return j;
704}
705
711static void outfits_naevpedia( unsigned int wid, const char *str )
712{
713 (void)wid;
714 (void)str;
715 naevpedia_open( "outfits" );
716}
717
721static const char *outfit_getPrice( const Outfit *outfit, credits_t *price,
722 int *canbuy, int *cansell,
723 char **player_has )
724{
725 static char pricestr[STRMAX_SHORT];
726 static char youhave[STRMAX_SHORT];
727 unsigned int q = outfits_getMod();
728 if ( outfit->lua_price == LUA_NOREF ) {
729 price2str( pricestr, outfit->price * q, player.p->credits, 2 );
730 *price = outfit->price * q;
731 *canbuy = 1;
732 *cansell = 1;
733 if ( player_has != NULL )
734 *player_has = NULL;
735 return pricestr;
736 }
737 const char *str;
738
739 lua_rawgeti( naevL, LUA_REGISTRYINDEX, outfit->lua_price );
740 lua_pushinteger( naevL, q );
741 if ( nlua_pcall( outfit->lua_env, 1, 4 ) ) { /* */
742 WARN( _( "Outfit '%s' failed to run '%s':\n%s" ), outfit->name, "price",
743 lua_tostring( naevL, -1 ) );
744 *price = 0;
745 *canbuy = 0;
746 *cansell = 0;
747 if ( player_has != NULL )
748 *player_has = NULL;
749 lua_pop( naevL, 1 );
750 return pricestr;
751 }
752
753 str = luaL_checkstring( naevL, -4 );
754 strncpy( pricestr, str, sizeof( pricestr ) - 1 );
755 *price = 0;
756 *canbuy = lua_toboolean( naevL, -3 );
757 *cansell = lua_toboolean( naevL, -2 );
758 if ( player_has != NULL ) {
759 str = luaL_optstring( naevL, -1, NULL );
760 if ( str == NULL )
761 *player_has = NULL;
762 else {
763 strncpy( youhave, str, sizeof( youhave ) - 1 );
764 *player_has = youhave;
765 }
766 }
767 lua_pop( naevL, 4 );
768
769 return pricestr;
770}
771
775int outfit_altText( char *buf, int n, const Outfit *o, const Pilot *plt )
776{
777 int p = outfit_getNameWithClass( o, buf, n );
778 p += scnprintf( &buf[p], n - p, "\n" );
779 if ( outfit_isProp( o, OUTFIT_PROP_UNIQUE ) )
780 p += scnprintf( &buf[p], n - p, "#o%s#0\n", _( "Unique" ) );
781 if ( o->limit != NULL )
782 p += scnprintf( &buf[p], n - p, "#r%s#0\n",
783 _( "Only 1 of type per ship" ) );
784 if ( o->slot.spid != 0 )
785 p += scnprintf( &buf[p], n - p, "#o%s#0\n",
786 _( sp_display( o->slot.spid ) ) );
787 p += scnprintf( &buf[p], n - p, "%s", pilot_outfitSummary( plt, o, 0 ) );
788 return 0;
789}
790
794ImageArrayCell *outfits_imageArrayCells( const Outfit **outfits, int *noutfits,
795 const Pilot *p, int store )
796{
797 ImageArrayCell *coutfits =
798 calloc( MAX( 1, *noutfits ), sizeof( ImageArrayCell ) );
799
800 if ( *noutfits == 0 ) {
801 *noutfits = 1;
802 coutfits[0].image = NULL;
803 coutfits[0].caption = strdup( _( "None" ) );
804 } else {
805 /* Threaded loading of graphics for speed. */
806 int needsgfx = 0;
807 for ( int i = 0; i < *noutfits; i++ ) {
808 Outfit *o = (Outfit *)outfits[i];
809 if ( !outfit_gfxStoreLoaded( o ) ) {
810 outfit_setProp( o, OUTFIT_PROP_NEEDSGFX );
811 needsgfx = 1;
812 }
813 }
814 if ( needsgfx )
815 outfit_gfxStoreLoadNeeded();
816 /* Just to be safe, we assume some ships colud potentially be duplicated.
817 */
818
819 /* Set alt text. */
820 for ( int i = 0; i < *noutfits; i++ ) {
821 const glColour *c;
822 glTexture *t;
823 const Outfit *o = outfits[i];
824
825 coutfits[i].image = gl_dupTexture( o->gfx_store );
826 coutfits[i].caption = strdup( outfit_shortname( o ) );
827 if ( !store && outfit_isProp( o, OUTFIT_PROP_UNIQUE ) )
828 coutfits[i].quantity = -1; /* Don't display. */
829 else
830 coutfits[i].quantity = player_outfitOwned( o );
831 coutfits[i].sloticon = sp_icon( o->slot.spid );
832
833 /* Background colour. */
835 if ( c == NULL )
836 c = &cBlack;
837 col_blend( &coutfits[i].bg, c, &cGrey70, 1 );
838
839 /* Short description. */
840 coutfits[i].alt = strdup( pilot_outfitSummary( p, o, 1 ) );
841
842 /* Slot type. */
843 if ( ( strcmp( outfit_slotName( o ), "N/A" ) != 0 ) &&
844 ( strcmp( outfit_slotName( o ), "NULL" ) != 0 ) ) {
845 size_t sz = 0;
846 const char *typename = _( outfit_slotName( o ) );
847 u8_inc( typename, &sz );
848 coutfits[i].slottype = malloc( sz + 1 );
849 memcpy( coutfits[i].slottype, typename, sz );
850 coutfits[i].slottype[sz] = '\0';
851 }
852
853 /* Layers. */
854 coutfits[i].layers = gl_copyTexArray( o->gfx_overlays );
855 if ( o->rarity > 0 ) {
856 t = rarity_texture( o->rarity );
857 coutfits[i].layers = gl_addTexArray( coutfits[i].layers, t );
858 }
859 }
860 }
861 return coutfits;
862}
863
867static void outfit_PopdownSelect( unsigned int wid, const char *str )
868{
869 int m = toolkit_getListPos( wid, str );
870 if ( m == outfit_Mode )
871 return;
872
873 outfit_Mode = m;
874 outfits_regenList( wid, NULL );
875}
876
877static void outfit_PopdownActivate( unsigned int wid, const char *str )
878{
879 outfit_PopdownSelect( wid, str );
880 window_destroyWidget( wid, str );
881}
882
883static void outfit_Popdown( unsigned int wid, const char *str )
884{
885 const char *name = "lstOutfitPopdown";
886 const char *modes[] = {
887 N_( "Show all outfits" ),
888 N_( "Show only outfits equipable on any of your ships" ),
889 N_( "Show only outfits equipable on current ship" ),
890 N_( "Show only light outfits" ),
891 N_( "Show only medium outfits" ),
892 N_( "Show only heavy outfits" ),
893 };
894 char **modelist;
895 const size_t n = sizeof( modes ) / sizeof( const char * );
896 int x, y, w, h;
897
898 if ( widget_exists( wid, name ) ) {
899 window_destroyWidget( wid, name );
900 return;
901 }
902
903 modelist = malloc( sizeof( modes ) );
904 for ( size_t i = 0; i < n; i++ )
905 modelist[i] = strdup( _( modes[i] ) );
906
907 window_dimWidget( wid, str, &w, &h );
908 window_posWidget( wid, str, &x, &y );
909 window_addList( wid, x + w, y - 120 + h, 350, 120, name, modelist, n,
910 outfit_Mode, outfit_PopdownSelect, outfit_PopdownActivate );
911 window_setFocus( wid, name );
912}
913
914static int outfit_isSold( const Outfit *outfit, int wid )
915{
916 LandOutfitData *data = NULL;
917 if ( wid >= 0 )
918 data = window_getData( wid );
919 if ( ( data != NULL ) && ( data->outfits != NULL ) ) {
920 for ( int i = 0; i < array_size( data->outfits ); i++ ) {
921 if ( data->outfits[i] == outfit )
922 return 1;
923 }
924 return 0;
925 } else if ( ( land_spob != NULL ) &&
926 tech_checkOutfit( land_spob->tech, outfit ) )
927 return 1;
928 return 0;
929}
930
936int outfit_canBuy( const Outfit *outfit, int wid )
937{
938 int failure, canbuy, cansell;
939 credits_t price;
940 LandOutfitData *data = NULL;
941 if ( wid >= 0 )
942 data = window_getData( wid );
943 int blackmarket = ( data != NULL ) ? data->blackmarket : 0;
944 const Outfit *omap = outfit_get( LOCAL_MAP_NAME );
945
947 failure = 0;
948 outfit_getPrice( outfit, &price, &canbuy, &cansell, NULL );
949
950 /* Special exception for local map. */
951 if ( outfit != omap ) {
952 int sold = 0;
953 /* See if the player previously sold it. */
954 for ( int i = 0; i < array_size( outfits_sold ); i++ ) {
955 if ( outfits_sold[i].o == outfit ) {
956 sold = outfits_sold[i].q;
957 break;
958 }
959 }
960
961 /* Not sold at planet. */
962 if ( !sold && !outfit_isSold( outfit, wid ) ) {
963 land_errDialogueBuild( _( "Outfit not sold here!" ) );
964 return 0;
965 }
966 }
967
968 /* Unique. */
969 if ( outfit_isProp( outfit, OUTFIT_PROP_UNIQUE ) &&
970 ( player_outfitOwnedTotal( outfit ) > 0 ) ) {
971 land_errDialogueBuild( _( "You can only own one of this outfit." ) );
972 return 0;
973 }
974
975 /* Intrinsic. */
976 if ( outfit->slot.type == OUTFIT_SLOT_INTRINSIC ) {
977 if ( pilot_hasOutfitLimit( player.p, outfit->limit ) ) {
979 _( "You can only equip one of this outfit type." ) );
980 return 0;
981 }
982 }
983
984 /* Map already mapped */
985 if ( ( outfit_isMap( outfit ) && map_isUseless( outfit ) ) ||
986 ( outfit_isLocalMap( outfit ) && localmap_isUseless( outfit ) ) ) {
988 _( "You already know of everything this map contains." ) );
989 return 0;
990 }
991 /* GUI already owned */
992 if ( outfit_isGUI( outfit ) && player_guiCheck( outfit->u.gui.gui ) ) {
993 land_errDialogueBuild( _( "You already own this GUI." ) );
994 return 0;
995 }
996 /* Already has license. */
997 if ( outfit_isLicense( outfit ) &&
998 player_hasLicense( outfit->u.lic.provides ) ) {
999 land_errDialogueBuild( _( "You already have this license." ) );
1000 return 0;
1001 }
1002 /* Not enough $$ */
1003 if ( !player_hasCredits( price ) ) {
1004 char buf[ECON_CRED_STRLEN];
1005 credits2str( buf, price - player.p->credits, 2 );
1006 land_errDialogueBuild( _( "You need %s more." ), buf );
1007 failure = 1;
1008 }
1009 /* Needs license. */
1010 if ( !blackmarket && !player_hasLicense( outfit->license ) ) {
1012 _( "You need the '%s' license to buy this outfit." ),
1013 _( outfit->license ) );
1014 failure = 1;
1015 }
1016 /* Needs requirements. */
1017 if ( !blackmarket && ( outfit->cond != NULL ) &&
1018 !cond_check( outfit->cond ) ) {
1019 land_errDialogueBuild( "%s", _( outfit->condstr ) );
1020 failure = 1;
1021 }
1022 /* Custom condition failed. */
1023 if ( !canbuy ) {
1025 _( "You lack the resources to buy this outfit." ) );
1026 failure = 1;
1027 }
1028
1029 return !failure;
1030}
1031
1037static void outfits_rmouse( unsigned int wid, const char *widget_name )
1038{
1039 outfits_buy( wid, widget_name );
1040}
1041
1047static void outfits_buy( unsigned int wid, const char *str )
1048{
1049 (void)str;
1050 int i, active;
1051 Outfit *outfit;
1052 int q;
1053 PlayerOutfit_t *sold = NULL;
1054 HookParam hparam[3];
1055
1056 active = window_tabWinGetActive( wid, OUTFITS_TAB );
1057 i = toolkit_getImageArrayPos( wid, OUTFITS_IAR );
1058 if ( i < 0 || array_size( iar_outfits[active] ) == 0 )
1059 return;
1060
1061 outfit = iar_outfits[active][i];
1062 q = outfits_getMod();
1063 /* Can only get one unique item. */
1064 if ( outfit_isProp( outfit, OUTFIT_PROP_UNIQUE ) ||
1065 ( outfit->slot.type == OUTFIT_SLOT_INTRINSIC ) ||
1066 outfit_isMap( outfit ) || outfit_isLocalMap( outfit ) ||
1067 outfit_isGUI( outfit ) || outfit_isLicense( outfit ) )
1068 q = MIN( q, 1 );
1069
1070 /* Can buy the outfit? */
1071 if ( !outfit_canBuy( outfit, wid ) ) {
1073 return;
1074 }
1075
1076 /* See if the player previously sold it, and limit it to that amount. */
1077 for ( int j = 0; j < array_size( outfits_sold ); j++ ) {
1078 if ( outfits_sold[j].o == outfit ) {
1079 sold = &outfits_sold[j];
1080 q = MIN( q, outfits_sold[j].q );
1081 break;
1082 }
1083 }
1084
1085 /* Give dialogue when trying to buy intrinsic. */
1086 if ( outfit->slot.type == OUTFIT_SLOT_INTRINSIC )
1087 if ( !dialogue_YesNo(
1088 _( "Buy Intrinsic Outfit?" ),
1089 _( "Are you sure you wish to buy '%s'? It will be automatically "
1090 "equipped on your current ship '%s'." ),
1091 _( outfit->name ), player.p->name ) )
1092 return;
1093
1094 /* Try Lua. */
1095 if ( outfit->lua_buy != LUA_NOREF ) {
1096 lua_rawgeti( naevL, LUA_REGISTRYINDEX, outfit->lua_buy );
1097 lua_pushinteger( naevL, q );
1098 if ( nlua_pcall( outfit->lua_env, 1, 2 ) ) { /* */
1099 WARN( _( "Outfit '%s' failed to run '%s':\n%s" ), outfit->name,
1100 "price", lua_tostring( naevL, -1 ) );
1101 lua_pop( naevL, 1 );
1102 }
1103
1104 int bought = lua_toboolean( naevL, -2 );
1105
1106 if ( !bought ) {
1107 dialogue_alert( "%s", lua_tostring( naevL, -1 ) );
1108 lua_pop( naevL, 2 );
1109 return;
1110 }
1111 q = luaL_checkinteger( naevL, -1 );
1112 player_addOutfit( outfit, q );
1113
1114 lua_pop( naevL, 2 );
1115 } else
1116 player_modCredits( -outfit->price * player_addOutfit( outfit, q ) );
1117
1118 /* Actually buy the outfit. */
1120 hparam[0].type = HOOK_PARAM_OUTFIT;
1121 hparam[0].u.outfit = outfit;
1122 hparam[1].type = HOOK_PARAM_NUMBER;
1123 hparam[1].u.num = q;
1124 hparam[2].type = HOOK_PARAM_SENTINEL;
1125 hooks_runParam( "outfit_buy", hparam );
1126 land_needsTakeoff( 1 );
1127
1128 /* Mark it that it was sold. */
1129 if ( sold != NULL )
1130 sold->q -= q;
1131
1132 /* Regenerate list. */
1133 outfits_regenList( wid, NULL );
1134}
1135
1139int outfit_canSell( const Outfit *outfit )
1140{
1141 int failure = 0;
1142 int canbuy, cansell;
1143 credits_t price;
1144
1145 land_errClear();
1146 outfit_getPrice( outfit, &price, &canbuy, &cansell, NULL );
1147
1148 /* Unique item. */
1149 if ( outfit_isProp( outfit, OUTFIT_PROP_UNIQUE ) ) {
1150 land_errDialogueBuild( _( "You can't sell a unique outfit." ) );
1151 failure = 1;
1152 }
1153 /* Map check. */
1154 if ( outfit_isMap( outfit ) || outfit_isLocalMap( outfit ) ) {
1155 land_errDialogueBuild( _( "You can't sell a map." ) );
1156 failure = 1;
1157 }
1158 /* GUI check. */
1159 if ( outfit_isGUI( outfit ) ) {
1160 land_errDialogueBuild( _( "You can't sell a GUI." ) );
1161 failure = 1;
1162 }
1163 /* License check. */
1164 if ( outfit_isLicense( outfit ) ) {
1165 land_errDialogueBuild( _( "You can't sell a license." ) );
1166 failure = 1;
1167 }
1168 /* has no outfits to sell */
1169 if ( !pilot_hasIntrinsic( player.p, outfit ) &&
1170 ( player_outfitOwned( outfit ) <= 0 ) ) {
1171 land_errDialogueBuild( _( "You can't sell something you don't have!" ) );
1172 failure = 1;
1173 }
1174 /* Custom condition failed. */
1175 if ( !cansell ) {
1176 land_errDialogueBuild( _( "You are unable to sell this outfit!" ) );
1177 failure = 1;
1178 }
1179
1180 return !failure;
1181}
1182
1187static void outfits_sell( unsigned int wid, const char *str )
1188{
1189 (void)str;
1190 int i, active;
1191 Outfit *outfit;
1192 int q;
1193 HookParam hparam[3];
1194
1195 active = window_tabWinGetActive( wid, OUTFITS_TAB );
1196 i = toolkit_getImageArrayPos( wid, OUTFITS_IAR );
1197 if ( i < 0 || array_size( iar_outfits[active] ) == 0 )
1198 return;
1199
1200 outfit = iar_outfits[active][i];
1201
1202 q = outfits_getMod();
1203
1204 /* Check various failure conditions. */
1205 if ( !outfit_canSell( outfit ) ) {
1207 return;
1208 }
1209
1210 /* Try Lua. */
1211 if ( outfit->lua_sell != LUA_NOREF ) {
1212 lua_rawgeti( naevL, LUA_REGISTRYINDEX, outfit->lua_sell );
1213 lua_pushinteger( naevL, q );
1214 if ( nlua_pcall( outfit->lua_env, 1, 2 ) ) { /* */
1215 WARN( _( "Outfit '%s' failed to run '%s':\n%s" ), outfit->name,
1216 "price", lua_tostring( naevL, -1 ) );
1217 lua_pop( naevL, 1 );
1218 }
1219
1220 int bought = lua_toboolean( naevL, -2 );
1221
1222 if ( !bought ) {
1223 dialogue_alert( "%s", lua_tostring( naevL, -1 ) );
1224 lua_pop( naevL, 2 );
1225 return;
1226 }
1227 q = luaL_checkinteger( naevL, -1 );
1228
1229 lua_pop( naevL, 2 );
1230 } else {
1231 q = player_rmOutfit( outfit, q );
1232 player_modCredits( outfit->price * q );
1233 }
1234
1236 hparam[0].type = HOOK_PARAM_OUTFIT;
1237 hparam[0].u.outfit = outfit;
1238 hparam[1].type = HOOK_PARAM_NUMBER;
1239 hparam[1].u.num = q;
1240 hparam[2].type = HOOK_PARAM_SENTINEL;
1241 hooks_runParam( "outfit_sell", hparam );
1242 land_needsTakeoff( 1 );
1243
1244 /* Update sold outfits list. */
1245 if ( !outfit_isSold( outfit, wid ) ) {
1246 int found = 0;
1247 if ( outfits_sold == NULL )
1249 for ( int j = 0; j < array_size( outfits_sold ); j++ ) {
1250 PlayerOutfit_t *poi = &outfits_sold[j];
1251 if ( poi->o == outfit ) {
1252 poi->q += q;
1253 found = 1;
1254 break;
1255 }
1256 }
1257 if ( !found ) {
1258 PlayerOutfit_t po = {
1259 .o = outfit,
1260 .q = q,
1261 };
1263 }
1264 }
1265
1266 /* Regenerate list. */
1267 outfits_regenList( wid, NULL );
1268}
1269
1273static int outfits_getMod( void )
1274{
1275 SDL_Keymod mods = SDL_GetModState();
1276 int q = 1;
1277 if ( mods & ( KMOD_LCTRL | KMOD_RCTRL ) )
1278 q *= 5;
1279 if ( mods & ( KMOD_LSHIFT | KMOD_RSHIFT ) )
1280 q *= 10;
1281 return q;
1282}
1283
1288{
1289 /* Free stored positions. */
1290 for ( int i = 0; i < OUTFITS_NTABS; i++ )
1291 array_free( iar_outfits[i] );
1292 memset( iar_outfits, 0, sizeof( Outfit ** ) * OUTFITS_NTABS );
1293}
Provides macros to work with dynamic arrays.
#define array_free(ptr_array)
Frees memory allocated and sets array to NULL.
Definition array.h:170
#define array_copy(basic_type, ptr_array)
Returns a shallow copy of the input array.
Definition array.h:230
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
void col_blend(glColour *blend, const glColour *fg, const glColour *bg, float alpha)
Blends two colours.
Definition colour.c:206
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 price2str(char *str, credits_t price, credits_t credits, int decimals)
Given a price and on-hand credits, outputs a colourized string.
Definition commodity.c:111
int cond_check(const char *cond)
Checks to see if a condition is true.
Definition cond.c:100
void dialogue_alert(const char *fmt,...)
Displays an alert popup with only an ok button and a message.
Definition dialogue.c:130
int dialogue_YesNo(const char *caption, const char *fmt,...)
Runs a dialogue with both yes and no options.
Definition dialogue.c:352
static iar_data_t iar_data[OUTFIT_TABS]
Definition equipment.c:74
void equipment_regenLists(unsigned int wid, int outfits, int ships)
Regenerates the equipment window lists.
Definition equipment.c:1429
void equipment_addAmmo(void)
Adds all the ammo it can to the player.
Definition equipment.c:1578
static Outfit ** iar_outfits[OUTFIT_TABS]
Definition equipment.c:75
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_defFont
Definition font.c:158
int hooks_runParam(const char *stack, const HookParam *param)
Runs all the hooks of stack.
Definition hook.c:1029
unsigned int land_getWid(int window)
Gets the WID of a window by type.
Definition land.c:1162
int landed
Definition land.c:78
int land_doneLoading(void)
Check to see if finished loading.
Definition land.c:207
void land_errDialogueBuild(const char *fmt,...)
Generates error dialogues used by several landing tabs.
Definition land.c:226
Spob * land_spob
Definition land.c:87
void land_errClear(void)
Clear error dialogues.
Definition land.c:217
void land_buttonTakeoff(unsigned int wid, const char *unused)
Wrapper for takeoff mission button.
Definition land.c:1124
int land_errDisplay(void)
Displays an error if applicable.
Definition land.c:248
static void outfits_sell(unsigned int wid, const char *str)
Attempts to sell the selected outfit the player has.
static int outfits_getMod(void)
Gets the current modifier status.
int outfit_altText(char *buf, int n, const Outfit *o, const Pilot *plt)
Computes the alt text for an outfit.
static void outfits_onClose(unsigned int wid, const char *str)
For when the widget closes.
static void outfits_genList(unsigned int wid)
Generates the outfit list.
static int outfitLand_filter(const Outfit *o)
void outfits_regenList(unsigned int wid, const char *str)
Regenerates the outfit list.
static void outfits_getSize(unsigned int wid, int *w, int *h, int *iw, int *ih, int *bw, int *bh)
Gets the size of the outfits window.
static void outfits_naevpedia(unsigned int wid, const char *str)
Starts the map find with outfit search selected.
int outfit_canBuy(const Outfit *outfit, int wid)
Checks to see if the player can buy the outfit.
void outfits_cleanup(void)
Cleans up outfit globals.
ImageArrayCell * outfits_imageArrayCells(const Outfit **outfits, int *noutfits, const Pilot *p, int store)
Generates image array cells corresponding to outfits.
static int outfit_events(unsigned int wid, SDL_Event *evt)
void outfits_open(unsigned int wid, const Outfit **outfits, int blackmarket)
Opens the outfit exchange center window.
void outfits_updateEquipmentOutfits(void)
Updates the outfitter and equipment outfit image arrays.
static void outfits_buy(unsigned int wid, const char *str)
Attempts to buy the outfit that is selected.
void outfits_update(unsigned int wid, const char *str)
Updates the outfits in the outfit window.
static int outfit_Mode
static PlayerOutfit_t * outfits_sold
int outfits_filter(const Outfit **outfits, int n, int(*filter)(const Outfit *), const char *name)
Applies a filter function and string to a list of outfits.
static void outfit_PopdownSelect(unsigned int wid, const char *str)
int outfit_canSell(const Outfit *outfit)
Checks to see if the player can sell the selected outfit.
static void outfits_rmouse(unsigned int wid, const char *widget_name)
Player right-clicks on an outfit.
static const char * outfit_getPrice(const Outfit *outfit, credits_t *price, int *canbuy, int *cansell, char **player_has)
Returns the price of an outfit (subject to quantity modifier)
static void outfits_changeTab(unsigned int wid, const char *wgt, int old, int tab)
Ensures the tab's selected item is reflected in the ship slot list.
Header file with generic functions and naev-specifics.
#define MIN(x, y)
Definition naev.h:39
#define CLAMP(a, b, x)
Definition naev.h:41
#define MAX(x, y)
Definition naev.h:37
lua_State * naevL
Definition nlua.c:54
int scnprintf(char *text, size_t maxlen, const char *fmt,...)
Like snprintf(), but returns the number of characters ACTUALLY "printed" into the buffer....
Definition nstring.c:102
glTexture * gl_dupTexture(const glTexture *texture)
Duplicates a texture.
Definition opengl_tex.c:891
glTexture ** gl_addTexArray(glTexture **tex, glTexture *t)
Adds an element to a texture array.
glTexture ** gl_copyTexArray(glTexture **tex)
Copy a texture array.
const char * outfit_shortname(const Outfit *o)
Gets the short name (translated) of an outfit.
Definition outfit.c:1168
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
int outfit_isLocalMap(const Outfit *o)
Checks if outfit is a local space map.
Definition outfit.c:719
int outfit_compareTech(const void *outfit1, const void *outfit2)
Function meant for use with C89, C99 algorithm qsort().
Definition outfit.c:302
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_fitsSlot(const Outfit *o, const OutfitSlot *s)
Checks to see if an outfit fits a slot.
Definition outfit.c:1180
int outfit_isFighterBay(const Outfit *o)
Checks if outfit is a fighter bay.
Definition outfit.c:701
int outfit_isMap(const Outfit *o)
Checks if outfit is a space map.
Definition outfit.c:710
int outfit_isLicense(const Outfit *o)
Checks if outfit is a license.
Definition outfit.c:728
int outfit_amount(const Outfit *o)
Gets the amount an outfit can hold.
Definition outfit.c:850
const char * outfit_getType(const Outfit *o)
Gets the outfit's specific type.
Definition outfit.c:1060
int outfit_isGUI(const Outfit *o)
Checks if outfit is a GUI.
Definition outfit.c:737
const char * outfit_slotName(const Outfit *o)
Gets the name of the slot type of an outfit.
Definition outfit.c:405
glTexture * rarity_texture(int rarity)
Definition outfit.c:3299
const glColour * outfit_slotSizeColour(const OutfitSlot *os)
Gets the slot size colour for an outfit slot.
Definition outfit.c:469
int pilot_hasOutfitLimit(const Pilot *p, const char *limit)
Checks to see if a pilot has an outfit with a specific outfit type.
int pilot_hasIntrinsic(const Pilot *pilot, const Outfit *outfit)
Gets how many copies of an intrinsic a pilot has.
const char * pilot_outfitSummary(const Pilot *p, const Outfit *o, int withname)
Gets the summary of an outfit for a give pilot.
int player_rmOutfit(const Outfit *o, int quantity)
Remove an outfit from the player's outfit stack.
Definition player.c:3053
int player_hasLicense(const char *license)
Checks to see if player has license.
Definition player.c:3207
int player_addOutfit(const Outfit *o, int quantity)
Adds an outfit to the player outfit stack.
Definition player.c:2988
const PlayerShip_t * player_getShipStack(void)
Gets the array (array.h) of the player's ships.
Definition player.c:2804
int player_outfitOwnedTotal(const Outfit *o)
Definition player.c:2912
credits_t player_modCredits(credits_t amount)
Modifies the amount of credits the player has.
Definition player.c:1047
Player_t player
Definition player.c:77
int player_hasCredits(credits_t amount)
Checks to see if the player has enough credits.
Definition player.c:1036
int player_outfitOwned(const Outfit *o)
Gets how many of the outfit the player owns.
Definition player.c:2882
const PlayerOutfit_t * player_getOutfits(void)
Gets an array (array.h) of the player's outfits.
Definition player.c:2940
int player_guiCheck(const char *name)
Check if player has a GUI.
Definition player_gui.c:88
static const double c[]
Definition rng.c:256
const glTexture * sp_icon(unsigned int spid)
Gets the icon associated with the slot.
Definition slots.c:225
const char * sp_display(unsigned int spid)
Gets the display name of a slot property (in English).
Definition slots.c:165
The actual hook parameter.
Definition hook.h:40
HookParamType type
Definition hook.h:41
const Outfit * outfit
Definition hook.h:48
union HookParam::@065274143236224234262250043114351136253171035204 u
double num
Definition hook.h:43
Data for handling the widget.
const Outfit ** outfits
char * gui
Definition outfit.h:358
char * provides
Definition outfit.h:365
OutfitSlotSize size
Definition outfit.h:143
unsigned int spid
Definition outfit.h:140
OutfitSlotType type
Definition outfit.h:142
A ship outfit, depends radically on the type.
Definition outfit.h:372
credits_t price
Definition outfit.h:391
char * limit
Definition outfit.h:386
char * cond
Definition outfit.h:382
union Outfit::@264277167364127137334024361374356236341374052147 u
OutfitLauncherData lau
Definition outfit.h:456
char * desc_raw
Definition outfit.h:392
int lua_buy
Definition outfit.h:448
glTexture * gfx_store
Definition outfit.h:398
int rarity
Definition outfit.h:376
int lua_price
Definition outfit.h:446
OutfitGUIData gui
Definition outfit.h:462
char * condstr
Definition outfit.h:383
OutfitSlot slot
Definition outfit.h:380
OutfitFighterBayData bay
Definition outfit.h:459
int lua_sell
Definition outfit.h:449
nlua_env lua_env
Definition outfit.h:418
char * license
Definition outfit.h:381
glTexture ** gfx_overlays
Definition outfit.h:399
double mass
Definition outfit.h:384
char * name
Definition outfit.h:373
OutfitLicenseData lic
Definition outfit.h:463
The representation of an in-game pilot.
Definition pilot.h:263
Wrapper for outfits.
Definition player.h:64
const Outfit * o
Definition player.h:65
Player ship.
Definition player.h:72
Pilot * p
Definition player.h:73
Abstraction for rendering sprite sheets.
Definition opengl_tex.h:43
int tech_checkOutfit(const tech_group_t *tech, const Outfit *o)
Checks to see if there is an outfit in the tech group.
Definition tech.c:980
Outfit ** tech_getOutfit(const tech_group_t *tech)
Gets all of the outfits associated to a tech group.
Definition tech.c:839
void window_setOnFocus(unsigned int wid, void(*focus)(unsigned int))
Sets the focus function of the window.
Definition toolkit.c:889
void window_dimWidget(unsigned int wid, const char *name, int *w, int *h)
Gets the dimensions of a widget.
Definition toolkit.c:415
void window_setFocus(unsigned int wid, const char *wgtname)
Sets the focused widget in a window.
Definition toolkit.c:2488
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_dimWindow(unsigned int wid, int *w, int *h)
Gets the dimensions of a window.
Definition toolkit.c:370
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_posWidget(unsigned int wid, const char *name, int *x, int *y)
Gets a widget's position.
Definition toolkit.c:441
void window_destroyWidget(unsigned int wid, const char *wgtname)
Destroys a widget in a window.
Definition toolkit.c:1167
void toolkit_rerender(void)
Marks the toolkit for needing a full rerender.
Definition toolkit.c:1675
void * window_getData(unsigned int wid)
Gets the custom data of a window.
Definition toolkit.c:923
void window_setData(unsigned int wid, void *data)
Sets custom data for a window.
Definition toolkit.c:906
int widget_exists(unsigned int wid, const char *wgtname)
Checks to see if a widget exists.
Definition toolkit.c:1144
void window_close(unsigned int wid, const char *str)
Helper function to automatically close the window calling it.
Definition toolkit.c:1028
char * window_getFocus(unsigned int wid)
Gets the focused widget in a window (does strdup!!).
Definition toolkit.c:2514
void window_handleEvents(unsigned int wid, int(*eventhandler)(unsigned int, SDL_Event *))
Sets the event handler for the window.
Definition toolkit.c:979