naev 0.12.5
land_shipyard.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_shipyard.h"
18
19#include "array.h"
20#include "cond.h"
21#include "dialogue.h"
22#include "hook.h"
23#include "land.h"
24#include "naevpedia.h"
25#include "nstring.h"
26#include "player.h"
27#include "slots.h"
28#include "space.h"
29#include "tk/toolkit_priv.h"
30#include "toolkit.h"
31
32#define SHIP_GFX_SIZE 256
33
37typedef struct CstShipSlotWidget_ {
38 int mouseover;
39 const ShipOutfitSlot *slot;
40 double altx;
41 double alty;
43
47typedef struct CstShipPreview {
48 int mousedown;
49 GLuint fbo;
50 GLuint tex;
51 double dir;
52 double updown;
54
55/*
56 * Vars.
57 */
59 NULL;
61static Ship *shipyard_selected = NULL;
62
63/*
64 * Helper functions.
65 */
66static int shipyard_canAcquire( const Ship *ship, const Spob *spob,
67 credits_t price );
68static void shipyard_buy( unsigned int wid, const char *str );
69static void shipyard_trade( unsigned int wid, const char *str );
70static void shipyard_rmouse( unsigned int wid, const char *widget_name );
71static void shipyard_renderSlots( double bx, double by, double bw, double bh,
72 void *data );
73static void shipyard_renderSlotsRow( double bx, double by, double bw,
74 const char *str, ShipOutfitSlot *s );
75static int shipyard_mouseSlots( unsigned int wid, const SDL_Event *event,
76 double x, double y, double w, double h,
77 double rx, double ry, void *data );
78static void shipyard_renderSlotsOver( double bx, double by, double bw,
79 double bh, void *data );
80static void shipyard_naevpedia( unsigned int wid, const char *str );
81/* Preview. */
82static void preview_free( void *ptr );
83static void preview_render( double x, double y, double w, double h,
84 void *data );
85static int preview_mouse( unsigned int wid, const SDL_Event *event, double x,
86 double y, double w, double h, double rx, double ry,
87 void *data );
88static void preview_focusLose( unsigned int wid, const char *wgtname );
89
93void shipyard_open( unsigned int wid )
94{
95 ImageArrayCell *cships;
96 int nships;
97 int w, h, sw, sh;
98 int iw, ih;
99 int bw, bh, padding, off;
100 int iconsize;
101 CstShipSlotWidget *data;
102
103 /* Mark as generated. */
104 land_tabGenerate( LAND_WINDOW_SHIPYARD );
105
106 /* Init vars. */
108
109 /* Get window dimensions. */
110 window_dimWindow( wid, &w, &h );
111
112 /* Calculate image array dimensions. */
113 iw = 440 + ( w - LAND_WIDTH );
114 ih = h - 60;
115
116 /* Ship image dimensions. */
117 sw = SHIP_GFX_SIZE;
118 sh = SHIP_GFX_SIZE;
119
120 /* Left padding + per-button padding * nbuttons */
121 padding = 40 + 20 * 4;
122
123 /* Calculate button dimensions. */
124 bw = MIN( LAND_BUTTON_WIDTH, ( w - iw - padding ) / 4 );
125 bh = LAND_BUTTON_HEIGHT;
126
127 /* buttons */
128 off = -20;
129 window_addButtonKey( wid, off, 20, bw, bh, "btnCloseShipyard",
130 _( "Take Off" ), land_buttonTakeoff, SDLK_t );
131 off -= 20 + bw;
132 window_addButtonKey( wid, off, 20, bw, bh, "btnTradeShip", _( "Trade-In" ),
133 shipyard_trade, SDLK_r );
134 off -= 20 + bw;
135 window_addButtonKey( wid, off, 20, bw, bh, "btnBuyShip", _( "Buy" ),
136 shipyard_buy, SDLK_b );
137 off -= 20 + bw;
138 window_addButtonKey( wid, off, 20, bw, bh, "btnNaevpediaOutfits",
139 _( "Archives" ), shipyard_naevpedia, SDLK_a );
140
141 /* ship review */
142 window_addRect( wid, -40 + 4, -40 + 4, sw + 8, sh + 8, "rctTarget", &cBlack,
143 1 );
144 CstShipPreview *pre = calloc( 1, sizeof( CstShipPreview ) );
145 gl_fboCreate( &pre->fbo, &pre->tex, sw / gl_screen.scale,
146 sh / gl_screen.scale );
147 window_addCust( wid, -40, -40, sw, sh, "cstPreview", 0, preview_render,
148 preview_mouse, NULL, preview_focusLose, pre );
149 window_custFreeDataFunc( wid, "cstPreview", preview_free );
150 window_custSetClipping( wid, "cstPreview", 0 );
151
152 /* slot types */
153 data = calloc( 1, sizeof( CstShipSlotWidget ) );
154 window_addCust( wid, -20, -sh - 50, sw - 10, 80, "cstSlots", 0.,
155 shipyard_renderSlots, shipyard_mouseSlots, NULL, NULL,
156 data );
157 window_custSetOverlay( wid, "cstSlots", shipyard_renderSlotsOver );
158 window_custSetClipping( wid, "cstSlots", 0 );
159 window_canFocusWidget( wid, "cstSlots", 0 );
160 window_custFreeDataFunc( wid, "cstSlots", free );
161
162 /* stat text */
163 window_addText( wid, -4, -sw - 50 - 70 - 20, sw, -sh - 60 - 70 - 20 + h - bh,
164 0, "txtStats", &gl_smallFont, NULL, NULL );
165
166 /* Placeholder text-boxes, calculated properly in shipyard_update(). */
167 window_addText( wid, iw + 40, -35, 133, 427, 0, "txtSDesc", &gl_defFont,
168 &cFontGrey, NULL );
169 window_addText( wid, iw + 173, -35, w - sw - iw - 208, 427, 0, "txtDDesc",
170 &gl_defFont, NULL, NULL );
171 window_addText( wid, 20 + iw + 20, -462, w - ( iw + 40 ) - ( sw + 40 ),
172 -482 + h - bh, 0, "txtDescription", &gl_defFont, NULL,
173 NULL );
174
175 /* set up the ships to buy/sell */
177 nships = array_size( shipyard_list );
178 cships = calloc( MAX( 1, nships ), sizeof( ImageArrayCell ) );
179 if ( nships <= 0 ) {
180 cships[0].image = NULL;
181 cships[0].caption = strdup( _( "None" ) );
182 nships = 1;
183 } else {
184 /* Threaded loading of graphics for speed. */
185 int needsgfx = 0;
186 for ( int i = 0; i < nships; i++ ) {
187 Ship *s = (Ship *)shipyard_list[i];
188 if ( !ship_gfxLoaded( s ) ) {
189 s->flags |= SHIP_NEEDSGFX;
190 needsgfx = 1;
191 }
192 }
193 if ( needsgfx )
195
196 /* Properly create the array. */
197 for ( int i = 0; i < nships; i++ ) {
198 cships[i].caption = strdup( _( shipyard_list[i]->name ) );
199 cships[i].image = ship_gfxStore( shipyard_list[i], 256, 0., 0., 0. );
200 cships[i].layers = gl_copyTexArray( shipyard_list[i]->gfx_overlays );
201 if ( shipyard_list[i]->rarity > 0 ) {
202 glTexture *t = rarity_texture( shipyard_list[i]->rarity );
203 cships[i].layers = gl_addTexArray( cships[i].layers, t );
204 }
205 }
206 }
207
208 iconsize = 128;
209 if ( !conf.big_icons ) {
210 if ( toolkit_simImageArrayVisibleElements( iw, ih, iconsize, iconsize ) <
211 nships )
212 iconsize = 96;
213 /*
214 if (toolkit_simImageArrayVisibleElements(iw,ih,iconsize,iconsize) <
215 nships) iconsize = 64;
216 */
217 }
218 window_addImageArray( wid, 20, 20, iw, ih, "iarShipyard", iconsize, iconsize,
219 cships, nships, shipyard_update, shipyard_rmouse,
220 NULL );
221
222 /* write the shipyard stuff */
223 shipyard_update( wid, NULL );
224 /* Set default keyboard focuse to the list */
225 window_setFocus( wid, "iarShipyard" );
226}
227
232void shipyard_update( unsigned int wid, const char *str )
233{
234 (void)str;
235 int i, tw, th, y, w, h, sw, iw, bh;
236 Ship *ship;
237 char lbl[STRMAX], buf[STRMAX], buf_price[ECON_CRED_STRLEN],
238 buf_credits[ECON_CRED_STRLEN];
239 size_t k = 0, l = 0;
240 int blackmarket = ( ( land_spob != NULL ) &&
241 spob_hasService( land_spob, SPOB_SERVICE_BLACKMARKET ) );
242
243 i = toolkit_getImageArrayPos( wid, "iarShipyard" );
244
245 /* No ships */
246 if ( i < 0 || array_size( shipyard_list ) == 0 ) {
247 window_disableButton( wid, "btnBuyShip" );
248 window_disableButton( wid, "btnTradeShip" );
249 window_modifyText( wid, "txtStats", NULL );
250 window_modifyText( wid, "txtDescription", NULL );
251 window_modifyText( wid, "txtSDesc", NULL );
252 window_modifyText( wid, "txtDDesc", NULL );
253 return;
254 }
255
256 ship = shipyard_list[i];
257 shipyard_selected = ship;
258
259 /* update image */
260 CstShipPreview *p = window_custGetData( wid, "cstPreview" );
261 p->dir = 0.;
262 p->updown = 0.;
263 ship_renderGfxStore( p->fbo, shipyard_selected, SHIP_GFX_SIZE, p->dir,
264 p->updown, 0. );
265 window_custSetDynamic( wid, "cstPreview",
267
268 /* update text */
269 window_modifyText( wid, "txtStats", ship->desc_stats );
270 price2str( buf_price, ship_buyPrice( ship ), player.p->credits, 2 );
271 credits2str( buf_credits, player.p->credits, 2 );
272
273 k += scnprintf( &lbl[k], sizeof( lbl ) - k, "%s", _( "Model:" ) );
274 l += scnprintf( &buf[l], sizeof( buf ) - l, "%s", _( ship->name ) );
275 k += scnprintf( &lbl[k], sizeof( lbl ) - k, "\n%s", _( "Class:" ) );
276 l += scnprintf( &buf[l], sizeof( buf ) - l, "\n%s",
277 _( ship_classDisplay( ship ) ) );
278 k += scnprintf( &lbl[k], sizeof( lbl ) - k, "\n%s", _( "Fabricator:" ) );
279 l += scnprintf( &buf[l], sizeof( buf ) - l, "\n%s", _( ship->fabricator ) );
280 k += scnprintf( &lbl[k], sizeof( lbl ) - k, "\n%s", _( "Crew:" ) );
281 l += scnprintf( &buf[l], sizeof( buf ) - l, "\n%d", ship->crew );
282 if ( player.fleet_capacity > 0 ) {
283 k += scnprintf( &lbl[k], sizeof( lbl ) - k, "\n%s",
284 _( "Fleet Capacity:" ) );
285 l += scnprintf( &buf[l], sizeof( buf ) - l, "\n%d", ship->points );
286 }
287 /* Weapons & Manoeuvrability */
288 k +=
289 scnprintf( &lbl[k], sizeof( lbl ) - k, "\n\n%s", _( "Base Properties" ) );
290 l += scnprintf( &buf[l], sizeof( buf ) - l, "\n\n%s", "" );
291 if ( ship->cpu > 0 ) {
292 k += scnprintf( &lbl[k], sizeof( lbl ) - k, "\n%s", _( "CPU:" ) );
293 l += scnprintf( &buf[l], sizeof( buf ) - l, "\n%.0f %s", ship->cpu,
294 UNIT_CPU );
295 }
296 if ( ship->mass ) {
297 char buf_mass[ECON_MASS_STRLEN];
298 tonnes2str( buf_mass, ship->mass );
299 k += scnprintf( &lbl[k], sizeof( lbl ) - k, "\n%s", _( "Mass:" ) );
300 l += scnprintf( &buf[l], sizeof( buf ) - l, "\n%s", buf_mass );
301 }
302 if ( ship->accel ) {
303 k += scnprintf( &lbl[k], sizeof( lbl ) - k, "\n%s", _( "Accel:" ) );
304 l += scnprintf( &buf[l], sizeof( buf ) - l, "\n" );
305 l += scnprintf( &buf[l], sizeof( buf ) - l, _( "%.0f %s" ), ship->accel,
306 UNIT_ACCEL );
307 }
308 if ( ship->speed ) {
309 k += scnprintf( &lbl[k], sizeof( lbl ) - k, "\n%s", _( "Speed:" ) );
310 l += scnprintf( &buf[l], sizeof( buf ) - l, "\n" );
311 l += scnprintf( &buf[l], sizeof( buf ) - l, _( "%.0f %s" ), ship->speed,
312 UNIT_SPEED );
313 }
314 if ( ship->turn ) {
315 k += scnprintf( &lbl[k], sizeof( lbl ) - k, "\n%s", _( "Turn:" ) );
316 l += scnprintf( &buf[l], sizeof( buf ) - l, "\n" );
317 l += scnprintf( &buf[l], sizeof( buf ) - l, _( "%.0f %s" ),
318 ship->turn * 180 / M_PI, UNIT_ROTATION );
319 }
320 if ( ship->dt_default != 1. ) {
321 k +=
322 scnprintf( &lbl[k], sizeof( lbl ) - k, "\n%s", _( "Time Constant:" ) );
323 l += scnprintf( &buf[l], sizeof( buf ) - l, "\n%.0f%%",
324 ship->dt_default * 100. );
325 }
326 /* Misc */
327 if ( ship->dmg_absorb ) {
328 k += scnprintf( &lbl[k], sizeof( lbl ) - k, "\n%s", _( "Absorption:" ) );
329 l += scnprintf( &buf[l], sizeof( buf ) - l, "\n" );
330 l += scnprintf( &buf[l], sizeof( buf ) - l, _( "%.0f%% damage" ),
331 ship->dmg_absorb * 100. );
332 }
333 if ( ship->shield || ship->shield_regen ) {
334 k += scnprintf( &lbl[k], sizeof( lbl ) - k, "\n%s", _( "Shield:" ) );
335 l += scnprintf( &buf[l], sizeof( buf ) - l, "\n" );
336 l +=
337 scnprintf( &buf[l], sizeof( buf ) - l, _( "%.0f %s (%.1f %s)" ),
338 ship->shield, UNIT_ENERGY, ship->shield_regen, UNIT_POWER );
339 }
340 if ( ship->armour || ship->armour_regen ) {
341 k += scnprintf( &lbl[k], sizeof( lbl ) - k, "\n%s", _( "Armour:" ) );
342 l += scnprintf( &buf[l], sizeof( buf ) - l, "\n" );
343 l +=
344 scnprintf( &buf[l], sizeof( buf ) - l, _( "%.0f %s (%.1f %s)" ),
345 ship->armour, UNIT_ENERGY, ship->armour_regen, UNIT_POWER );
346 }
347 if ( ship->energy || ship->energy_regen ) {
348 k += scnprintf( &lbl[k], sizeof( lbl ) - k, "\n%s", _( "Energy:" ) );
349 l += scnprintf( &buf[l], sizeof( buf ) - l, "\n" );
350 l +=
351 scnprintf( &buf[l], sizeof( buf ) - l, _( "%.0f %s (%.1f %s)" ),
352 ship->energy, UNIT_ENERGY, ship->energy_regen, UNIT_POWER );
353 }
354 if ( ship->cap_cargo ) {
355 char buf_cargo[ECON_MASS_STRLEN];
356 tonnes2str( buf_cargo, ship->cap_cargo );
357 k += scnprintf( &lbl[k], sizeof( lbl ) - k, "\n%s", _( "Cargo Space:" ) );
358 l += scnprintf( &buf[l], sizeof( buf ) - l, "\n%s", buf_cargo );
359 }
360 if ( ship->fuel ) {
361 k += scnprintf( &lbl[k], sizeof( lbl ) - k, "\n%s", _( "Fuel:" ) );
362 l += scnprintf( &buf[l], sizeof( buf ) - l, "\n%d %s", ship->fuel,
363 UNIT_UNIT );
364 }
365 if ( ship->fuel_consumption != 100. ) {
366 k += scnprintf( &lbl[k], sizeof( lbl ) - k, "\n%s", _( "Fuel Use:" ) );
367 l += scnprintf( &buf[l], sizeof( buf ) - l, "\n%d %s",
368 ship->fuel_consumption, UNIT_UNIT );
369 }
370
371 k += scnprintf( &lbl[k], sizeof( lbl ) - k, "\n\n%s", _( "Price:" ) );
372 l += scnprintf( &buf[l], sizeof( buf ) - l, "\n\n%s", buf_price );
373 k += scnprintf( &lbl[k], sizeof( lbl ) - k, "\n%s", _( "Money:" ) );
374 l += scnprintf( &buf[l], sizeof( buf ) - l, "\n%s", buf_credits );
375 if ( ship->license ) {
376 int meets_reqs = player_hasLicense( ship->license );
377 ;
378 k += scnprintf( &lbl[k], sizeof( lbl ) - k, "\n%s", _( "License:" ) );
379 if ( blackmarket )
380 l += scnprintf( &buf[l], sizeof( buf ) - l, "\n%s#0",
381 _( "Not Necessary (Blackmarket)" ) );
382 else
383 l += scnprintf( &buf[l], sizeof( buf ) - l, "\n%s%s#0",
384 meets_reqs ? "" : "#r", _( ship->license ) );
385 }
386 if ( ship->cond ) {
387 int meets_reqs = 0;
388 if ( land_spob != NULL )
389 meets_reqs = cond_check( ship->cond );
390 k += scnprintf( &lbl[k], sizeof( lbl ) - k, "\n%s", _( "Requires:" ) );
391 if ( blackmarket )
392 l += scnprintf( &buf[l], sizeof( buf ) - l, "\n%s#0",
393 _( "Not Necessary (Blackmarket)" ) );
394 else
395 l += scnprintf( &buf[l], sizeof( buf ) - l, "\n%s%s#0",
396 meets_reqs ? "" : "#r", _( ship->condstr ) );
397 }
398
399 /* Calculate layout. */
400 window_dimWindow( wid, &w, &h );
401 iw = 440 + ( w - LAND_WIDTH );
402 sw = SHIP_GFX_SIZE;
403 bh = LAND_BUTTON_HEIGHT;
404 tw = gl_printWidthRaw( &gl_defFont, lbl );
405 th = gl_printHeightRaw( &gl_defFont, tw, lbl ) + gl_defFont.h;
406 y = -35;
407 window_modifyText( wid, "txtSDesc", lbl );
408 window_resizeWidget( wid, "txtSDesc", tw + 20, th );
409 window_moveWidget( wid, "txtSDesc", 20 + iw + 20, y );
410 window_modifyText( wid, "txtDDesc", buf );
411 window_resizeWidget( wid, "txtDDesc", w - sw - 40 - ( 20 + iw + 20 + 128 ),
412 th );
413 window_moveWidget( wid, "txtDDesc", 20 + iw + 20 + tw + 20, y );
414 y = MIN( y - th, -40 - SHIP_GFX_SIZE - 20 );
415 if ( ship->desc_extra ) {
416 scnprintf( &buf[0], sizeof( buf ), "%s\n%s", _( ship->description ),
417 _( ship->desc_extra ) );
418 window_modifyText( wid, "txtDescription", buf );
419 } else
420 window_modifyText( wid, "txtDescription", _( ship->description ) );
421 window_resizeWidget( wid, "txtDescription",
422 w - ( 20 + iw + 20 ) - ( sw + 40 ), y - 20 + h - bh );
423 window_moveWidget( wid, "txtDescription", 20 + iw + 20, y );
424
425 if ( !shipyard_canBuy( ship, land_spob ) )
426 window_disableButtonSoft( wid, "btnBuyShip" );
427 else
428 window_enableButton( wid, "btnBuyShip" );
429
430 if ( !shipyard_canTrade( ship, land_spob ) )
431 window_disableButtonSoft( wid, "btnTradeShip" );
432 else
433 window_enableButton( wid, "btnTradeShip" );
434}
435
440{
442 shipyard_list = NULL;
443 shipyard_selected = NULL;
444}
445
446static int shipyard_naevpedia_hook( void *data )
447{
448 (void)data;
449 naevpedia_open( "ships" );
450 return 0;
451}
457static void shipyard_naevpedia( unsigned int wid, const char *str )
458{
459 (void)wid;
460 (void)str;
461 hook_addFunc( shipyard_naevpedia_hook, NULL, "safe" );
462}
463
469static void shipyard_rmouse( unsigned int wid, const char *widget_name )
470{
471 shipyard_buy( wid, widget_name );
472}
473
479static void shipyard_buy( unsigned int wid, const char *str )
480{
481 (void)str;
482 int i;
483 char buf[STRMAX_SHORT];
484 Ship *ship;
485 HookParam hparam[2];
486
487 i = toolkit_getImageArrayPos( wid, "iarShipyard" );
488 if ( i < 0 || array_size( shipyard_list ) == 0 )
489 return;
490
491 ship = shipyard_list[i];
492
493 credits_t targetprice = ship_buyPrice( ship );
494
495 if ( !shipyard_canBuy( ship, land_spob ) ) {
497 return;
498 }
499
500 credits2str( buf, targetprice, 2 );
501 if ( dialogue_YesNo( _( "Are you sure?" ), /* confirm */
502 _( "Do you really want to spend %s on a new ship?" ),
503 buf ) == 0 )
504 return;
505
506 /* Player just got a new ship */
507 snprintf( buf, sizeof( buf ), _( "Bought at %s in the %s system." ),
508 spob_name( land_spob ), _( cur_system->name ) );
509 if ( player_newShip( ship, NULL, 0, buf, 0 ) == NULL ) {
510 /* Player actually aborted naming process. */
511 return;
512 }
513 player_modCredits( -targetprice ); /* ouch, paying is hard */
514
515 /* Update shipyard. */
516 shipyard_update( wid, NULL );
517
518 /* Run hook. */
519 hparam[0].type = HOOK_PARAM_SHIP;
520 hparam[0].u.ship = ship;
521 hparam[1].type = HOOK_PARAM_SENTINEL;
522 hooks_runParam( "ship_buy", hparam );
523 land_needsTakeoff( 1 );
524}
525
526static int shipyard_canAcquire( const Ship *ship, const Spob *spob,
527 credits_t price )
528{
529 int failure = 0;
530 int blackmarket =
531 ( ( spob != NULL ) && spob_hasService( spob, SPOB_SERVICE_BLACKMARKET ) );
533
534 /* Must have the necessary license. */
535 if ( !blackmarket && !player_hasLicense( ship->license ) ) {
536 land_errDialogueBuild( _( "You need the '%s' license to buy this ship." ),
537 _( ship->license ) );
538 failure = 1;
539 }
540
541 /* Must meet conditional requirement. */
542 if ( !blackmarket && ( ship->cond != NULL ) && !cond_check( ship->cond ) ) {
543 land_errDialogueBuild( "%s", _( ship->condstr ) );
544 failure = 1;
545 }
546
547 /* Must have enough credits. */
548 if ( !player_hasCredits( price ) ) {
549 char buf[ECON_CRED_STRLEN];
550 credits2str( buf, price - player.p->credits, 2 );
551 land_errDialogueBuild( _( "You need %s more." ), buf );
552 failure = 1;
553 }
554 return !failure;
555}
556
562int shipyard_canBuy( const Ship *ship, const Spob *spob )
563{
564 credits_t price = ship_buyPrice( ship );
565 return shipyard_canAcquire( ship, spob, price );
566}
567
574int shipyard_canTrade( const Ship *ship, const Spob *spob )
575{
576 credits_t price =
577 ship_buyPrice( ship ) - player_shipPrice( player.p->name, 0 );
579
580 if ( ship_isFlag( player.p->ship, SHIP_UNIQUE ) ) {
581 land_errDialogueBuild( _( "You can not trade in unique ships!" ) );
582 return 0;
583 }
584
585 if ( pilot_cargoUsedMission( player.p ) > 0 ) {
587 _( "You can not trade in your ship when you have mission cargo!" ) );
588 return 0;
589 }
590 return shipyard_canAcquire( ship, spob, price );
591}
592
598static void shipyard_trade( unsigned int wid, const char *str )
599{
600 (void)str;
601 int i;
602 char buf[STRMAX_SHORT], buf2[ECON_CRED_STRLEN], buf3[ECON_CRED_STRLEN],
603 buf4[ECON_CRED_STRLEN];
604 Ship *ship;
605
606 i = toolkit_getImageArrayPos( wid, "iarShipyard" );
607 if ( i < 0 || shipyard_list == NULL )
608 return;
609
610 ship = shipyard_list[i];
611
612 credits_t targetprice = ship_buyPrice( ship );
613 credits_t playerprice = player_shipPrice( player.p->name, 0 );
614
615 if ( !shipyard_canTrade( ship, land_spob ) ) {
617 return;
618 }
619
620 credits2str( buf, targetprice, 2 );
621 credits2str( buf2, playerprice, 2 );
622 credits2str( buf3, targetprice - playerprice, 2 );
623 credits2str( buf4, playerprice - targetprice, 2 );
624
625 /* Display the correct dialogue depending on the new ship's price versus the
626 * player's. */
627 if ( targetprice == playerprice ) {
628 if ( dialogue_YesNo( _( "Are you sure?" ), /* confirm */
629 _( "Your %s is worth %s, exactly as much as the new "
630 "ship, so no credits need be exchanged. Are you "
631 "sure you want to trade your ship in?" ),
632 _( player.p->ship->name ), buf2 ) == 0 )
633 return;
634 } else if ( targetprice < playerprice ) {
635 if ( dialogue_YesNo( _( "Are you sure?" ), /* confirm */
636 _( "Your %s is worth %s, more than the new ship. "
637 "For your ship, you will get the new %s and %s. "
638 "Are you sure you want to trade your ship in?" ),
639 _( player.p->ship->name ), buf2, _( ship->name ),
640 buf4 ) == 0 )
641 return;
642 } else if ( targetprice > playerprice ) {
643 if ( dialogue_YesNo(
644 _( "Are you sure?" ), /* confirm */
645 _( "Your %s is worth %s, so the new ship will cost %s. Are you "
646 "sure you want to trade your ship in?" ),
647 _( player.p->ship->name ), buf2, buf3 ) == 0 )
648 return;
649 }
650
651 /* Store stuff. */
652 const Ship *ssold = player.p->ship;
653 char *sname = strdup( player.p->name );
654
655 /* player just got a new ship */
656 snprintf( buf, sizeof( buf ), _( "Bought at %s in the %s system." ),
657 spob_name( land_spob ), _( cur_system->name ) );
658 if ( player_newShip( ship, NULL, 1, buf, 0 ) == NULL ) {
659 free( sname );
660 return; /* Player aborted the naming process. */
661 }
662
663 HookParam hparam[4];
664 hparam[0].type = HOOK_PARAM_SHIP;
665 hparam[0].u.ship = ssold;
666 hparam[1].type = HOOK_PARAM_STRING;
667 hparam[1].u.str = sname;
668 hparam[2].type = HOOK_PARAM_BOOL;
669 hparam[2].u.b = 1;
670 hparam[3].type = HOOK_PARAM_SENTINEL;
671 hooks_runParam( "ship_sell", hparam );
672 hparam[0].type = HOOK_PARAM_SHIP;
673 hparam[0].u.ship = ship;
674 hparam[1].type = HOOK_PARAM_BOOL;
675 hparam[1].u.b = 1;
676 hparam[2].type = HOOK_PARAM_SENTINEL;
677 hooks_runParam( "ship_buy", hparam );
678
679 free( sname );
680
682 playerprice -
683 targetprice ); /* Modify credits by the difference between ship values. */
684
685 land_refuel();
686
687 /* The newShip call will trigger a loadGUI that will recreate the land
688 * windows. Therefore the land ID will be void. We must reload in in order to
689 * properly update it again.*/
690 wid = land_getWid( LAND_WINDOW_SHIPYARD );
691
692 /* Update shipyard. */
693 shipyard_update( wid, NULL );
694}
695
699static void shipyard_renderSlots( double bx, double by, double bw, double bh,
700 void *data )
701{
702 (void)data;
703 double y, w;
704 Ship *ship;
705
706 /* Make sure a valid ship is selected. */
707 ship = shipyard_selected;
708 if ( ship == NULL )
709 return;
710
711 y = by + bh;
712
713 /* Draw rotated text. */
714 y -= 10 + 5;
715 gl_print( &gl_smallFont, bx, y, &cFontWhite, _( "Slots:" ) );
716
717 w = bw - 10.;
718
719 /* Weapon slots. */
720 y -= 20;
721 shipyard_renderSlotsRow( bx, y, w, _( OUTFIT_LABEL_WEAPON ),
722 ship->outfit_weapon );
723
724 /* Utility slots. */
725 y -= 20;
726 shipyard_renderSlotsRow( bx, y, w, _( OUTFIT_LABEL_UTILITY ),
727 ship->outfit_utility );
728
729 /* Structure slots. */
730 y -= 20;
731 shipyard_renderSlotsRow( bx, y, w, _( OUTFIT_LABEL_STRUCTURE ),
732 ship->outfit_structure );
733}
734
738static void shipyard_renderSlotsRow( double bx, double by, double bw,
739 const char *str, ShipOutfitSlot *s )
740{
741 (void)bw;
742 double x;
743
744 /* Print text. */
745 gl_printMidRaw( &gl_smallFont, 40, bx, by, &cFontWhite, -1, str );
746 x = bx + 30.;
747
748 /* Draw squares. */
749 for ( int i = 0; i < array_size( s ); i++ ) {
750 const glColour *c;
751 const glTexture *icon;
752 const int size = 14;
753
754 /* Ignore locked slots. */
755 if ( s[i].locked && !s[i].visible && ( s[i].data == NULL ) )
756 continue;
757
758 /* Get the colour. */
759 c = outfit_slotSizeColour( &s[i].slot );
760 if ( c == NULL )
761 c = &cBlack;
762
763 x += size + 7.;
764 toolkit_drawRect( x, by, size, size, c, NULL );
765
766 /* Add colour stripe depending on required/exclusiveness. */
767 if ( s[i].required )
768 toolkit_drawTriangle( x, by, x + size, by + size, x, by + size,
769 &cBrightRed );
770 else if ( s[i].exclusive )
771 toolkit_drawTriangle( x, by, x + size, by + size, x, by + size,
772 &cWhite );
773 else if ( s[i].slot.spid != 0 )
774 toolkit_drawTriangle( x, by, x + size, by + size, x, by + size,
775 &cBlack );
776
777 gl_renderRectEmpty( x, by, size, size, &cBlack );
778
779 /* Draw icon if applicable. */
780 icon = sp_icon( s[i].slot.spid );
781 if ( icon != NULL ) {
782 double sw = 12.;
783 double sh = 12.;
784 double sx = x + 6;
785 double sy = by + 6;
786 if ( icon->flags & OPENGL_TEX_SDF )
787 gl_renderSDF( icon, sx, sy, sw, sh, &cWhite, 0., 1. );
788 else
789 gl_renderScaleAspect( icon, sx, sy, sw, sh, NULL );
790 }
791 }
792}
793
794static int shipyard_mouseSlots( unsigned int wid, const SDL_Event *event,
795 double mx, double my, double bw, double bh,
796 double rx, double ry, void *data )
797{
798 (void)wid;
799 (void)bw;
800 (void)rx;
801 (void)ry;
802 int x = floor( ( mx - 30. - 21. ) / 21. );
803 int y = floor( ( bh - my - 15. ) / 20. );
805 ShipOutfitSlot *ps;
806 Ship *ship = shipyard_selected;
807
808 /* Need a selected ship. */
809 if ( ship == NULL )
810 return 0;
811
812 /* Only care about motion. */
813 if ( event->type != SDL_MOUSEMOTION )
814 return 0;
815
816 /* Find what row. */
817 switch ( y ) {
818 case 0:
819 ps = ship->outfit_weapon;
820 break;
821 case 1:
822 ps = ship->outfit_utility;
823 break;
824 case 2:
825 ps = ship->outfit_structure;
826 break;
827
828 default:
829 wgt->mouseover = 0;
830 return 0;
831 }
832 if ( ( x < 0 ) || ( x >= array_size( ps ) ) ) {
833 wgt->mouseover = 0;
834 return 0;
835 }
836
837 /* Mark the slot. */
838 wgt->mouseover = 1;
839 wgt->slot = &ps[x];
840 wgt->alty = 30. + ( 2 - y ) * 20.;
841 wgt->altx = 15. + ( x + 2 ) * 21.;
842 return 1;
843}
844
845static void shipyard_renderSlotsOver( double bx, double by, double bw,
846 double bh, void *data )
847{
848 (void)bw;
849 (void)bh;
850 char alt[STRMAX_SHORT];
851 int pos;
853 const ShipOutfitSlot *slot;
854
855 if ( wgt->mouseover <= 0 )
856 return;
857
858 slot = wgt->slot;
859 pos = 0;
860 if ( slot->slot.spid ) {
861 pos = scnprintf( alt, sizeof( alt ), "#o%s\n",
862 _( sp_display( slot->slot.spid ) ) );
863 } else
864 pos = 0;
865 pos += scnprintf( &alt[pos], sizeof( alt ) - pos, _( "#%c%s #%c%s #0slot" ),
867 _( slotSize( slot->slot.size ) ),
869 _( slotName( slot->slot.type ) ) );
870
871 /* Draw the alt stuff. */
872 toolkit_drawAltText( bx + wgt->altx, by + wgt->alty, alt );
873}
874
875static void preview_free( void *ptr )
876{
877 CstShipPreview *p = ptr;
878 glDeleteFramebuffers( 1, &p->fbo );
879 glDeleteTextures( 1, &p->tex );
880 free( ptr );
881}
882
883static void preview_render( double x, double y, double w, double h, void *data )
884{
885 CstShipPreview *p = data;
886
887 if ( shipyard_selected == NULL )
888 return;
889
891 ship_renderGfxStore( p->fbo, shipyard_selected, SHIP_GFX_SIZE, p->dir,
892 p->updown, 0. );
893
894 gl_renderTextureRaw( p->tex, OPENGL_TEX_VFLIP, x, y, w, h, 0., 0., 1., 1.,
895 NULL, 0. );
896}
897
898static int preview_mouse( unsigned int wid, const SDL_Event *event, double mx,
899 double my, double w, double h, double rx, double ry,
900 void *data )
901{
902 (void)wid;
903 CstShipPreview *p = data;
904
905 if ( shipyard_selected == NULL )
906 return 0;
907
908 switch ( event->type ) {
909 case SDL_MOUSEBUTTONUP:
910 p->mousedown = 0;
911 return 0;
912
913 case SDL_MOUSEBUTTONDOWN:
914 if ( ( mx < 0. ) || ( mx > w ) || ( my < 0. ) || ( my > h ) )
915 return 0;
916 p->mousedown = 1;
917 return 1;
918
919 case SDL_MOUSEMOTION:
920 if ( !p->mousedown )
921 return 0;
922 p->dir += rx / ( SHIP_GFX_SIZE / M_PI * 0.5 );
923 p->updown += ry / ( SHIP_GFX_SIZE / M_PI * 0.5 );
924 /* Rerender if not animated. */
926 ship_renderGfxStore( p->fbo, shipyard_selected, SHIP_GFX_SIZE, p->dir,
927 p->updown, 0. );
928 return 1;
929
930 default:
931 return 0;
932 }
933}
934
935static void preview_focusLose( unsigned int wid, const char *wgtname )
936{
937 (void)wid;
938 (void)wgtname;
939}
Provides macros to work with dynamic arrays.
#define array_free(ptr_array)
Frees memory allocated and sets array to NULL.
Definition array.h:170
static ALWAYS_INLINE int array_size(const void *array)
Returns number of elements in the array.
Definition array.h:179
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
int dialogue_YesNo(const char *caption, const char *fmt,...)
Runs a dialogue with both yes and no options.
Definition dialogue.c:352
int gl_printHeightRaw(const glFont *ft_font, const int width, const char *text)
Gets the height of a non-formatted string.
Definition font.c:1050
glFont gl_smallFont
Definition font.c:159
int gl_printWidthRaw(const glFont *ft_font, const char *text)
Gets the width that it would take to print some text.
Definition font.c:984
glFont gl_defFont
Definition font.c:158
int gl_printMidRaw(const glFont *ft_font, int width, double x, double y, const glColour *c, double outlineR, const char *text)
Displays text centered in position and width.
Definition font.c:821
void gl_print(const glFont *ft_font, const double x, const double y, const glColour *c, const char *fmt,...)
Prints text on screen like printf.
Definition font.c:725
int hooks_runParam(const char *stack, const HookParam *param)
Runs all the hooks of stack.
Definition hook.c:1029
unsigned int hook_addFunc(int(*func)(void *), void *data, const char *stack)
Adds a function hook to be run.
Definition hook.c:634
unsigned int land_getWid(int window)
Gets the WID of a window by type.
Definition land.c:1162
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
void land_refuel(void)
Refuels the player's current ship, if possible.
Definition land.c:995
int land_errDisplay(void)
Displays an error if applicable.
Definition land.c:248
static void shipyard_naevpedia(unsigned int wid, const char *str)
Starts the map find with ship search selected.
static void shipyard_renderSlotsRow(double bx, double by, double bw, const char *str, ShipOutfitSlot *s)
Renders a row of ship slots.
void shipyard_open(unsigned int wid)
Opens the shipyard window.
static void shipyard_rmouse(unsigned int wid, const char *widget_name)
Player right-clicks on a ship.
void shipyard_cleanup(void)
Cleans up shipyard data.
int shipyard_canBuy(const Ship *ship, const Spob *spob)
Makes sure it's valid to buy a ship.
static Ship ** shipyard_list
static void shipyard_renderSlots(double bx, double by, double bw, double bh, void *data)
Custom widget render function for the slot widget.
static void shipyard_buy(unsigned int wid, const char *str)
Player attempts to buy a ship.
void shipyard_update(unsigned int wid, const char *str)
Updates the ships in the shipyard window.
#define SHIP_GFX_SIZE
int shipyard_canTrade(const Ship *ship, const Spob *spob)
Makes sure it's valid to buy a ship, trading the old one in simultaneously.
static void shipyard_trade(unsigned int wid, const char *str)
Player attempts to buy a ship, trading the current ship in.
static Ship * shipyard_selected
Header file with generic functions and naev-specifics.
#define MIN(x, y)
Definition naev.h:39
#define MAX(x, y)
Definition naev.h:37
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
glInfo gl_screen
Definition opengl.c:47
void gl_renderSDF(const glTexture *texture, double x, double y, double w, double h, const glColour *c, double angle, double outline)
SDF Texture blitting backend.
void gl_renderScaleAspect(const glTexture *texture, double bx, double by, double bw, double bh, const glColour *c)
Blits a texture scaling it to fit a rectangle, but conserves aspect ratio.
void gl_renderTextureRaw(GLuint texture, uint8_t flags, double x, double y, double w, double h, double tx, double ty, double tw, double th, const glColour *c, double angle)
Texture blitting backend.
void gl_renderRectEmpty(double x, double y, double w, double h, const glColour *c)
Renders a rectangle.
int gl_fboCreate(GLuint *fbo, GLuint *tex, GLsizei width, GLsizei height)
Creates a framebuffer and its associated texture.
Definition opengl_tex.c:268
glTexture ** gl_addTexArray(glTexture **tex, glTexture *t)
Adds an element to a texture array.
glTexture ** gl_copyTexArray(glTexture **tex)
Copy a texture array.
char outfit_slotTypeColourFont(const OutfitSlot *os)
Gets a font colour character that roughly matches an outfit slot type colour.
Definition outfit.c:505
char outfit_slotSizeColourFont(const OutfitSlot *os)
Gets a font colour character that roughly matches an outfit slot size colour.
Definition outfit.c:487
const char * slotName(const OutfitSlotType type)
Definition outfit.c:413
const char * slotSize(const OutfitSlotSize o)
Gets the slot size as a string.
Definition outfit.c:436
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_cargoUsedMission(const Pilot *p)
Gets how much mission cargo ship has on board.
int player_hasLicense(const char *license)
Checks to see if player has license.
Definition player.c:3207
credits_t player_shipPrice(const char *shipname, int count_unique)
Calculates the price of one of the player's ships.
Definition player.c:733
PlayerShip_t * player_newShip(const Ship *ship, const char *def_name, int trade, const char *acquired, int noname)
Creates a new ship for player.
Definition player.c:470
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
static const double c[]
Definition rng.c:256
const char * ship_classDisplay(const Ship *s)
Gets the ship's display class in human readable form.
Definition ship.c:203
credits_t ship_buyPrice(const Ship *s)
The ship buy price, includes default outfits.
Definition ship.c:303
int ship_gfxLoadNeeded(void)
Tries to load the graphics for all ships that need it.
Definition ship.c:603
int ship_gfxLoaded(const Ship *s)
Checks to see if a ship has loaded graphics.
Definition ship.c:595
int ship_gfxAnimated(const Ship *s)
Returns whether or not the ship has animated graphics.
Definition ship.c:513
glTexture * ship_gfxStore(const Ship *s, int size, double dir, double updown, double glow)
Get the store gfx.
Definition ship.c:383
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
StarSystem * cur_system
Definition space.c:110
const char * spob_name(const Spob *p)
Gets the translated name of a spob.
Definition space.c:1834
The actual hook parameter.
Definition hook.h:40
const char * str
Definition hook.h:44
HookParamType type
Definition hook.h:41
union HookParam::@325330313164266255110350307176363262300250041145 u
const Ship * ship
Definition hook.h:47
int b
Definition hook.h:45
OutfitSlotSize size
Definition outfit.h:143
unsigned int spid
Definition outfit.h:140
OutfitSlotType type
Definition outfit.h:142
Ship outfit slot.
Definition ship.h:71
OutfitSlot slot
Definition ship.h:72
Represents a space ship.
Definition ship.h:97
double shield_regen
Definition ship.h:142
double dt_default
Definition ship.h:136
double cap_cargo
Definition ship.h:135
char * desc_extra
Definition ship.h:122
int flags
Definition ship.h:112
char * license
Definition ship.h:116
char * name
Definition ship.h:100
int fuel
Definition ship.h:133
char * fabricator
Definition ship.h:120
char * description
Definition ship.h:121
double energy_regen
Definition ship.h:144
double armour
Definition ship.h:139
int fuel_consumption
Definition ship.h:134
double armour_regen
Definition ship.h:140
int crew
Definition ship.h:130
double dmg_absorb
Definition ship.h:145
char * condstr
Definition ship.h:119
char * cond
Definition ship.h:117
int points
Definition ship.h:110
double cpu
Definition ship.h:132
double speed
Definition ship.h:127
ShipOutfitSlot * outfit_utility
Definition ship.h:174
double turn
Definition ship.h:126
char * desc_stats
Definition ship.h:180
double accel
Definition ship.h:125
ShipOutfitSlot * outfit_weapon
Definition ship.h:175
double energy
Definition ship.h:143
double shield
Definition ship.h:141
double mass
Definition ship.h:131
ShipOutfitSlot * outfit_structure
Definition ship.h:172
Represents a Space Object (SPOB), including and not limited to planets, stations, wormholes,...
Definition space.h:102
Abstraction for rendering sprite sheets.
Definition opengl_tex.h:43
uint8_t flags
Definition opengl_tex.h:64
Ship ** tech_getShip(const tech_group_t *tech)
Gets all of the ships associated to a tech group.
Definition tech.c:887
void window_setFocus(unsigned int wid, const char *wgtname)
Sets the focused widget in a window.
Definition toolkit.c:2488
void window_dimWindow(unsigned int wid, int *w, int *h)
Gets the dimensions of a window.
Definition toolkit.c:370
void toolkit_drawAltText(int bx, int by, const char *alt)
Draws an alt text.
Definition toolkit.c:1460
void window_canFocusWidget(unsigned int wid, const char *name, int canfocus)
Allows or disallows focusing a widget.
Definition toolkit.c:517
void toolkit_drawRect(int x, int y, int w, int h, const glColour *c, const glColour *lc)
Draws a rectangle.
Definition toolkit.c:1370
void window_moveWidget(unsigned int wid, const char *name, int x, int y)
Moves a widget.
Definition toolkit.c:463
void toolkit_drawTriangle(int x1, int y1, int x2, int y2, int x3, int y3, const glColour *c)
Draws a rectangle.
Definition toolkit.c:1420
void window_resizeWidget(unsigned int wid, const char *name, int w, int h)
Resizes a widget.
Definition toolkit.c:490