naev 0.10.4
equipment.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"
17#include "equipment.h"
18
19#include "array.h"
20#include "conf.h"
21#include "debug.h"
22#include "dialogue.h"
23#include "escort.h"
24#include "gui.h"
25#include "hook.h"
26#include "info.h"
27#include "land.h"
28#include "land_outfits.h"
29#include "log.h"
30#include "map.h"
31#include "mission.h"
32#include "ndata.h"
33#include "nstring.h"
34#include "nlua.h"
35#include "nlua_tk.h"
36#include "ntime.h"
37#include "player.h"
38#include "player_fleet.h"
39#include "pilot_outfit.h"
40#include "shipstats.h"
41#include "slots.h"
42#include "tk/toolkit_priv.h" /* Yes, I'm a bad person, abstractions be damned! */
43#include "toolkit.h"
44
45/*
46 * Image array names.
47 */
48#define EQUIPMENT_SHIPS "iarAvailShips"
49#define EQUIPMENT_OUTFIT_TAB "tabOutfits"
50#define EQUIPMENT_OUTFITS "iarAvailOutfits"
51#define EQUIPMENT_FILTER "inpFilterOutfits"
52#define OUTFIT_TABS 5
53
54/* global/main window */
55#define BUTTON_WIDTH 200
56#define BUTTON_HEIGHT 40
58/*
59 * equipment stuff
60 */
62static double equipment_dir = 0.;
63static unsigned int equipment_lastick = 0;
64static unsigned int equipment_wid = 0;
65static int ship_mode = 0;
66static iar_data_t *iar_data = NULL;
67static Outfit ***iar_outfits = NULL;
68static nlua_env autoequip_env = LUA_NOREF; /* Autoequip env. */
69static int equipment_outfitMode = 0;
71/*
72 * prototypes
73 */
74/* Creation. */
75static void equipment_getDim( unsigned int wid, int *w, int *h,
76 int *sw, int *sh, int *ow, int *oh,
77 int *ew, int *eh,
78 int *cw, int *ch, int *bw, int *bh );
79static void equipment_genShipList( unsigned int wid );
80static void equipment_genOutfitList( unsigned int wid );
81/* Widget. */
82static void equipment_genLists( unsigned int wid );
83static void equipment_toggleFav( unsigned int wid, const char *wgt );
84static void equipment_toggleDeploy( unsigned int wid, const char *wgt );
85static void equipment_renderColumn( double x, double y, double w, double h,
86 PilotOutfitSlot *lst, const char *txt,
87 int selected, Outfit *o, Pilot *p, CstSlotWidget *wgt );
88static void equipment_renderSlots( double bx, double by, double bw, double bh, void *data );
89static void equipment_renderMisc( double bx, double by, double bw, double bh, void *data );
90static void equipment_renderOverlayColumn( double x, double y, double h,
91 PilotOutfitSlot *lst, int mover, CstSlotWidget *wgt );
92static void equipment_renderOverlaySlots( double bx, double by, double bw, double bh,
93 void *data );
94static void equipment_renderShip( double bx, double by, double bw, double bh, void *data );
95static int equipment_mouseInColumn( double y, double h, int n, double my );
96static int equipment_mouseSlots( unsigned int wid, SDL_Event* event,
97 double x, double y, double w, double h, double rx, double ry, void *data );
98/* Misc. */
99static char eq_qCol( double cur, double base, int inv );
100static int equipment_swapSlot( unsigned int wid, Pilot *p, PilotOutfitSlot *slot );
101static void equipment_sellShip( unsigned int wid, const char* str );
102static void equipment_renameShip( unsigned int wid, const char *str );
103static void equipment_shipMode( unsigned int wid, const char *str );
104static void equipment_rightClickShips( unsigned int wid, const char* str );
105static void equipment_transChangeShip( unsigned int wid, const char* str );
106static void equipment_changeShip( unsigned int wid );
107static void equipment_unequipShip( unsigned int wid, const char* str );
108static void equipment_autoequipShip( unsigned int wid, const char* str );
109static void equipment_filterOutfits( unsigned int wid, const char *str );
110static void equipment_rightClickOutfits( unsigned int wid, const char* str );
111static void equipment_outfitPopdown( unsigned int wid, const char* str );
112static void equipment_changeTab( unsigned int wid, const char *wgt, int old, int tab );
113static int equipment_playerAddOutfit( const Outfit *o, int quantity );
114static int equipment_playerRmOutfit( const Outfit *o, int quantity );
115
121void equipment_rightClickOutfits( unsigned int wid, const char* str )
122{
123 (void) str;
124 Outfit *o;
125 int id, active, minimal, n, nfits;
126 PilotOutfitSlot* slots;
127 Pilot *p;
128 OutfitSlotSize size;
129
130 active = window_tabWinGetActive( wid, EQUIPMENT_OUTFIT_TAB );
131 id = toolkit_getImageArrayPos( wid, EQUIPMENT_OUTFITS );
132
133 /* Did the user click on background or placeholder cell? */
134 if (id < 0 || iar_outfits[active] == NULL)
135 return;
136
137 o = iar_outfits[active][id];
138 if (o==NULL)
139 return;
140
141 /* Figure out which slot this stuff fits into */
142 switch (o->slot.type) {
143 case OUTFIT_SLOT_STRUCTURE:
145 break;
146 case OUTFIT_SLOT_UTILITY:
148 break;
149 case OUTFIT_SLOT_WEAPON:
150 slots = eq_wgt.selected->p->outfit_weapon;
151 break;
152 default:
153 return;
154 }
155 n = array_size(slots);
156
157 /* See how many slots it fits into. */
158 nfits = 0;
159 minimal = n;
160 for (int i=0; i<n; i++) {
161 /* Must fit the slot. */
162 if (!outfit_fitsSlot( o, &slots[i].sslot->slot))
163 continue;
164
165 /* Must have valid slot size. */
166 if (o->slot.size == OUTFIT_SLOT_SIZE_NA)
167 continue;
168
169 minimal = i;
170 nfits++;
171 }
172 /* Only fits in a single slot, so we might as well just swap it. */
173 if (nfits==1) {
174 eq_wgt.outfit = o;
175 p = eq_wgt.selected->p;
176 /* We have to call once to remove, once to add. */
177 if (slots[minimal].outfit != NULL)
178 equipment_swapSlot( equipment_wid, p, &slots[minimal] );
179 eq_wgt.outfit = o;
180 equipment_swapSlot( equipment_wid, p, &slots[minimal] );
181
182 hooks_run( "equip" ); /* Equipped. */
183 return;
184 }
185
186 /* See if limit is applied and swap with shared limit slot. */
187 if (o->limit != NULL) {
188 minimal = n;
189 for (int i=0; i<n; i++) {
190 /* Must fit the slot. */
191 if (!outfit_fitsSlot( o, &slots[i].sslot->slot))
192 continue;
193
194 /* Must have valid slot size. */
195 if (o->slot.size == OUTFIT_SLOT_SIZE_NA)
196 continue;
197
198 /* Must have outfit with limit. */
199 if ((slots[i].outfit == NULL) || (slots[i].outfit->limit == NULL))
200 continue;
201
202 /* Must share a limit to be able to swap. */
203 if (strcmp(slots[i].outfit->limit,o->limit)!=0)
204 continue;
205
206 minimal = i;
207 }
208 if (minimal < n) {
209 eq_wgt.outfit = o;
210 p = eq_wgt.selected->p;
211 /* Once to unequip and once to equip. */
212 equipment_swapSlot( equipment_wid, p, &slots[minimal] );
213 eq_wgt.outfit = o;
214 equipment_swapSlot( equipment_wid, p, &slots[minimal] );
215 hooks_run( "equip" ); /* Equipped. */
216 return;
217 }
218 }
219
220 /* Loop through outfit slots of the right type, try to find an empty one */
221 size = OUTFIT_SLOT_SIZE_NA;
222 minimal = n;
223 for (int i=0; i<n; i++) {
224 /* Slot full. */
225 if (slots[i].outfit != NULL)
226 continue;
227
228 /* Must fit the slot. */
229 if (!outfit_fitsSlot( o, &slots[i].sslot->slot))
230 continue;
231
232 /* Must have valid slot size. */
233 if (o->slot.size == OUTFIT_SLOT_SIZE_NA)
234 continue;
235
236 /* Search for the smallest slot avaliable. */
237 if ((size == OUTFIT_SLOT_SIZE_NA) || (slots[i].sslot->slot.size < size)){
238 size = slots[i].sslot->slot.size;
239 minimal = i;
240 }
241 }
242
243 /* Use the chosen one (if any). */
244 if (minimal < n) {
245 eq_wgt.outfit = o;
246 p = eq_wgt.selected->p;
247 equipment_swapSlot( equipment_wid, p, &slots[minimal] );
248 hooks_run( "equip" ); /* Equipped. */
249 }
250}
251
255static void equipment_getDim( unsigned int wid, int *w, int *h,
256 int *sw, int *sh, int *ow, int *oh,
257 int *ew, int *eh,
258 int *cw, int *ch, int *bw, int *bh )
259{
260 int ssw, ssh;
261 /* Get window dimensions. */
262 window_dimWindow( wid, w, h );
263
264 /* Calculate image array dimensions. */
265 ssw = 550 + (*w - LAND_WIDTH);
266 ssh = (*h - 100);
267 if (sw != NULL)
268 *sw = ssw;
269 if (sh != NULL)
270 *sh = (1*ssh)/3;
271 if (ow != NULL)
272 *ow = ssw;
273 if (oh != NULL)
274 *oh = (2*ssh)/3;
275
276 /* Calculate slot widget. */
277 if (ew != NULL)
278 *ew = 180;
279 if (eh != NULL)
280 *eh = *h - 100;
281
282 /* Calculate custom widget. */
283 if (cw != NULL)
284 *cw = 120;
285 if (ch != NULL)
286 *ch = 140 + ((player.fleet_capacity > 0) ? 40 : 0);
287
288 /* Calculate button dimensions. */
289 if (bw != NULL)
290 *bw = (*w - 20 - (sw!=NULL?*sw:0) - 40 - 20 - 60) / 5;
291 if (bh != NULL)
292 *bh = BUTTON_HEIGHT;
293}
294
298void equipment_open( unsigned int wid )
299{
300 int w,h, sw,sh, ow,oh, bw,bh, ew,eh, cw,ch, x,y;
301
302 /* Load the outfit mode. */
304
305 /* Mark as generated. */
306 land_tabGenerate(LAND_WINDOW_EQUIPMENT);
307
308 /* Set global WID. */
309 equipment_wid = wid;
310
311 /* Get dimensions. */
312 equipment_getDim( wid, &w, &h, &sw, &sh, &ow, &oh,
313 &ew, &eh, &cw, &ch, &bw, &bh );
314
315 /* Buttons */
316 x = -20+4;
317 y = 20;
318 window_addButtonKey( wid, x, y,
319 bw, bh, "btnCloseEquipment",
320 _("Take Off"), land_buttonTakeoff, SDLK_t );
321 x -= (15+bw);
322 window_addButtonKey( wid, x, y,
323 bw, bh, "btnSellShip",
324 _("Sell Ship"), equipment_sellShip, SDLK_s );
325 x -= (15+bw);
326 window_addButtonKey( wid, x, y,
327 bw, bh, "btnChangeShip",
328 _("Swap Ship"), equipment_transChangeShip, SDLK_p );
329 x -= (15+bw);
330 window_addButtonKey( wid, x, y,
331 bw, bh, "btnUnequipShip",
332 _("Unequip"), equipment_unequipShip, SDLK_u );
333 x -= (15+bw);
334 window_addButtonKey( wid, x, y,
335 bw, bh, "btnAutoequipShip",
336 _("Autoequip"), equipment_autoequipShip, SDLK_a );
337
338 /* Prepare the outfit array. */
339 if (iar_data == NULL)
340 iar_data = calloc( OUTFIT_TABS, sizeof(iar_data_t) );
341 else
342 memset( iar_data, 0, sizeof(iar_data_t) * OUTFIT_TABS );
343 if (iar_outfits == NULL)
344 iar_outfits = calloc( OUTFIT_TABS, sizeof(Outfit**) );
345 else {
346 for (int i=0; i<OUTFIT_TABS; i++)
347 free( iar_outfits[i] );
348 memset( iar_outfits, 0, sizeof(Outfit**) * OUTFIT_TABS );
349 }
350
351 /* Safe defaults. */
352 equipment_lastick = SDL_GetTicks();
353 equipment_dir = 0.;
354
355 /* Add ammo. */
357
358 /* text */
359 x = 20+sw+20+180+10;
360 y = -40;
361 window_addText( wid, x, y,
362 130, y-20+h-bh, 0, "txtSDesc", &gl_defFont, &cFontGrey, NULL );
363 window_addText( wid, x, y,
364 w-x-128-30, y-20+h-bh, 0, "txtAcquired", &gl_defFont, NULL, NULL );
365 x += 130;
366 window_addText( wid, x, y,
367 w-x-20-128-20, y-20+h-bh, 0, "txtDDesc", &gl_defFont, NULL, NULL );
368
369 /* Generate lists. */
370 window_addText( wid, 30, -20,
371 ow, gl_defFont.h, 0, "txtShipTitle", &gl_defFont, NULL, _("Available Ships") );
372 window_addText( wid, 30, -40-sh-20,
373 ow, gl_defFont.h, 0, "txtOutfitTitle", &gl_defFont, NULL, _("Available Outfits") );
374
375 /* Favourite checkbox, run before genLists. */
376 x = -20-(128-cw)/2;
377 y = -20-150-ch;
378 window_addCheckbox( wid, x, y, cw, 30, "chkFav", _("Favourite"), equipment_toggleFav, 0 );
379 if (player.fleet_capacity > 0) {
380 y -= 23;
381 window_addCheckbox( wid, x, y, cw, 30, "chkDeploy", _("Deployed"), equipment_toggleDeploy, 0 );
382 }
383 x = -16;
384 y -= 23 + 10;
385 window_addButtonKey( wid, x, y, 128+8, bh, "btnRenameShip",
386 _("Rename"), equipment_renameShip, SDLK_r );
387 y -= bh + 10;
388 window_addButtonKey( wid, x, y, 128+8, bh, "btnShipMode",
389 _("Toggle Display"), equipment_shipMode, SDLK_d );
390
391 /* Generate lists. */
392 equipment_genLists( wid );
393
394 /* Slot widget. Designed so that 10 slots barely fit. */
395 equipment_slotWidget( wid, 20+sw+15, -40-5, ew, eh, &eq_wgt );
397 eq_wgt.canmodify = 1;
398
399 /* Separator. */
400 // window_addRect( wid, 20 + sw + 20, -40, 2, h-60, "rctDivider", &cGrey50, 0 );
401
402 /* Custom widget (ship information). */
403 window_addCust( wid, -20-(128-cw)/2, -20-150, cw, ch, "cstMisc", 0,
404 equipment_renderMisc, NULL, NULL, NULL, NULL );
405 window_canFocusWidget( wid, "cstMisc", 0 );
406
407 /* Spinning ship. */
408 window_addRect( wid, -20+4, -40+4, 128+8, 128+8, "rctShip", &cBlack, 1 );
409 window_addCust( wid, -20, -40, 128, 128, "cstShip", 0,
410 equipment_renderShip, NULL, NULL, NULL, NULL );
411 window_canFocusWidget( wid, "cstShip", 0 );
412
413 /* Focus the ships image array. */
414 window_setFocus( wid , EQUIPMENT_SHIPS );
415}
416
427void equipment_slotWidget( unsigned int wid,
428 double x, double y, double w, double h,
429 CstSlotWidget *data )
430{
431 /* Initialize data. */
433
434 /* Create the widget. */
435 window_addCust( wid, x, y, w, h, "cstEquipment", 0,
436 equipment_renderSlots, equipment_mouseSlots, NULL, NULL, data );
437 window_custSetClipping( wid, "cstEquipment", 0 );
438 window_custSetOverlay( wid, "cstEquipment", equipment_renderOverlaySlots );
439 window_canFocusWidget( wid, "cstEquipment", 0 );
440}
444static void equipment_renderColumn( double x, double y, double w, double h,
445 PilotOutfitSlot *lst, const char *txt,
446 int selected, Outfit *o, Pilot *p, CstSlotWidget *wgt )
447{
448 const glColour *c, *dc, *rc;
449 glColour bc;
450
451 /* Shouldn't be happening, but let's be nice and not crash. */
452 if (!array_size(lst))
453 return;
454
455 /* Render text. */
456 if ((o != NULL) && (lst[0].sslot->slot.type == o->slot.type))
457 c = &cFontGreen;
458 else
459 c = &cFontWhite;
461 x-15., y+h+10., c, -1., txt );
462
463 /* Iterate for all the slots. */
464 for (int i=0; i<array_size(lst); i++) {
465 /* Choose default colour. */
466 if (wgt->weapons >= 0) {
467 int level = pilot_weapSetCheck( p, wgt->weapons, &lst[i] );
468 if (level == 0)
469 dc = &cFontRed;
470 else if (level == 1)
471 dc = &cFontYellow;
472 else if (pilot_slotIsToggleable( &lst[i] ))
473 dc = &cFontBlue;
474 else
475 dc = &cFontGrey;
476 }
477 else
478 dc = outfit_slotSizeColour( &lst[i].sslot->slot );
479
480 if (dc == NULL)
481 dc = &cGrey60;
482
483 /* Draw background. */
484 bc = *dc;
485 bc.a = 0.4;
486 if (i==selected)
487 c = &cGreen;
488 else
489 c = &bc;
490 toolkit_drawRect( x, y, w, h, c, NULL );
491
492 if (lst[i].outfit != NULL) {
493 /* Draw bugger. */
494 gl_renderScale( lst[i].outfit->gfx_store,
495 x, y, w, h, NULL );
496 }
497 else if ((o != NULL) &&
498 (lst[i].sslot->slot.type == o->slot.type)) {
499 /* Render a thick frame with a yes/no color, and geometric cue. */
500 int ok = (!lst[i].sslot->locked && pilot_canEquip( p, &lst[i], o ) == NULL);
501 glUseProgram( shaders.status.program );
502 glUniform1f( shaders.status.paramf, ok );
503 gl_renderShader( x, y, w, h, 0., &shaders.status, NULL, 0 );
504 }
505
506 /* Must rechoose colour based on slot properties. */
507 rc = dc;
508 if (wgt->canmodify) {
509 if (lst[i].sslot->locked)
510 rc = NULL;
511 else if (lst[i].sslot->required)
512 rc = &cBrightRed;
513 else if (lst[i].sslot->exclusive)
514 rc = &cWhite;
515 else if (lst[i].sslot->slot.spid != 0)
516 rc = &cBlack;
517 }
518
519 /* Draw outline. */
520 if (rc != NULL)
521 toolkit_drawOutlineThick( x, y, w, h, 1, 3, rc, NULL );
522 // toolkit_drawOutline( x-1, y-1, w+3, h+3, 0, &cBlack, NULL );
523 /* Go to next one. */
524 y -= h+20;
525 }
526}
527
539static void equipment_calculateSlots( const Pilot *p, double bw, double bh,
540 double *w, double *h, int *n, int *m )
541{
542 double tw, th, s;
543 int tm;
544
545 /* Calculate size. */
546 tm = MAX( MAX( array_size(p->outfit_weapon), array_size(p->outfit_utility) ), array_size(p->outfit_structure) );
547 th = bh / (double)tm;
548 tw = bw / 3.;
549 s = MIN( th, tw ) - 20.;
550 th = s;
551 tw = s;
552
553 /* Return. */
554 *w = tw;
555 *h = th;
556 *n = 3;
557 *m = tm;
558}
568static void equipment_renderSlots( double bx, double by, double bw, double bh, void *data )
569{
570 double x, y;
571 double w, h;
572 double tw;
573 int n, m;
574 CstSlotWidget *wgt;
575 Pilot *p;
576 int selected;
577
578 /* Must have selected ship. */
579 wgt = (CstSlotWidget*) data;
580 if (wgt->selected == NULL)
581 return;
582
583 /* Get data. */
584 p = wgt->selected->p;
585 selected = wgt->slot;
586
587 /* Get dimensions. */
588 equipment_calculateSlots( p, bw, bh, &w, &h, &n, &m );
589 tw = bw / (double)n;
590
591 /* Draw weapon outfits. */
592 x = bx + (tw-w)/2;
593 y = by + bh - (h+20) + (h+20-h)/2;
594 equipment_renderColumn( x, y, w, h,
595 p->outfit_weapon, _("Weapon"),
596 selected, wgt->outfit, p, wgt );
597
598 /* Draw systems outfits. */
599 selected -= array_size(p->outfit_weapon);
600 x += tw;
601 y = by + bh - (h+20) + (h+20-h)/2;
602 equipment_renderColumn( x, y, w, h,
603 p->outfit_utility, _("Utility"),
604 selected, wgt->outfit, p, wgt );
605
606 /* Draw structure outfits. */
607 selected -= array_size(p->outfit_utility);
608 x += tw;
609 y = by + bh - (h+20) + (h+20-h)/2;
610 equipment_renderColumn( x, y, w, h,
611 p->outfit_structure, _("Structure"),
612 selected, wgt->outfit, p, wgt );
613}
623static void equipment_renderMisc( double bx, double by, double bw, double bh, void *data )
624{
625 (void) data;
626 Pilot *p;
627 double percent;
628 double x, y;
629 double w, h;
630
631 /* Must have selected ship. */
632 if (eq_wgt.selected == NULL)
633 return;
634
635 p = eq_wgt.selected->p;
636
637 /* Base bar properties. */
638 w = bw;
639 h = 20;
640 x = bx;
641 y = by + bh - 30 - h;
642
643 /* Fleet capacity. */
644 if (player.fleet_capacity > 0) {
645 gl_printMidRaw( &gl_smallFont, w, x, y + h + 7, &cFontWhite, -1., _("Fleet Capacity") );
646
647 percent = CLAMP(0., 1., 1.-(double)player.fleet_used / (double)player.fleet_capacity );
648 toolkit_drawRect( x, y - 2, w * percent, h + 4, &cBlue, NULL );
649 toolkit_drawRect( x + w * percent, y - 2, w * (1.-percent), h + 4, &cBlack, NULL );
651 x, y + h / 2. - gl_smallFont.h / 2.,
652 &cFontWhite, "%d / %d", player.fleet_capacity-player.fleet_used, player.fleet_capacity );
653
654 y -= gl_smallFont.h + 2*h;
655 }
656
657 /* Render CPU. */
658 gl_printMidRaw( &gl_smallFont, w, x, y + h + 7, &cFontWhite, -1, _("CPU Free") );
659
660 percent = (p->cpu_max > 0) ? CLAMP(0., 1., (double)p->cpu / (double)p->cpu_max) : 0.;
661 toolkit_drawRect( x, y - 2, w * percent, h + 4, &cGreen, NULL );
662 toolkit_drawRect( x + w * percent, y - 2, w * (1.-percent), h + 4, &cRed, NULL );
663 gl_printMid( &gl_smallFont, w, x, y + h / 2. - gl_smallFont.h / 2., &cFontWhite, "%d / %d", p->cpu, p->cpu_max );
664
665 y -= h;
666
667 /* Render mass limit. */
668 gl_printMidRaw( &gl_smallFont, w, x, y-3, &cFontWhite, -1., _("Mass Limit Left") );
669 y -= gl_smallFont.h + h;
670
671 percent = (p->stats.engine_limit > 0) ? CLAMP(0., 1.,
672 (p->stats.engine_limit - p->solid->mass) / p->stats.engine_limit) : 0.;
673 toolkit_drawRect( x, y - 2, w * percent, h + 4, &cGreen, NULL );
674 toolkit_drawRect( x + w * percent, y - 2, w * (1.-percent), h + 4, &cOrange, NULL );
676 x, y + h / 2. - gl_smallFont.h / 2.,
677 &cFontWhite, "%.0f / %.0f", p->stats.engine_limit - p->solid->mass, p->stats.engine_limit );
678
679 y -= h;
680 if (p->stats.engine_limit > 0. && p->solid->mass > p->stats.engine_limit) {
682 x, y, &cFontRed, _("!! %.0f%% Slower !!"),
683 (1. - p->speed / p->speed_base) * 100);
684 }
685}
686
697static void equipment_renderOverlayColumn( double x, double y, double h,
698 PilotOutfitSlot *lst, int mover, CstSlotWidget *wgt )
699{
700 const glColour *c;
701 glColour tc;
702 int text_width, yoff;
703 const char *display;
704
705 /* Iterate for all the slots. */
706 for (int i=0; i<array_size(lst); i++) {
707 int subtitle = 0;
708 int top = 0;
709 if (lst[i].outfit != NULL) {
710 /* See if needs a subtitle. */
711 if ((outfit_isLauncher(lst[i].outfit) ||
712 (outfit_isFighterBay(lst[i].outfit))) &&
713 (lst[i].u.ammo.quantity < outfit_amount(lst[i].outfit)))
714 subtitle = 1;
715 }
716 /* Draw bottom. */
717 if ((i==mover) || subtitle) {
718 display = NULL;
719 if ((i==mover) && wgt->canmodify) {
720 if (lst[i].sslot->locked) {
721 display = _("Locked");
722 c = &cFontRed;
723 }
724 else if (lst[i].outfit != NULL) {
725 top = 1;
726 display = pilot_canEquip( wgt->selected->p, &lst[i], NULL );
727 if (display != NULL)
728 c = &cFontRed;
729 else {
730 display = _("Right click to remove");
731 c = &cFontGreen;
732 }
733 }
734 else if ((wgt->outfit != NULL) &&
735 (lst->sslot->slot.type == wgt->outfit->slot.type)) {
736 top = 1;
737 display = pilot_canEquip( wgt->selected->p, &lst[i], wgt->outfit );
738 if (display != NULL)
739 c = &cFontRed;
740 else {
741 display = _("Right click to add");
742 c = &cFontGreen;
743 }
744 }
745 }
746 else if (lst[i].outfit != NULL) {
747 top = 1;
748 }
749
750 if (display != NULL) {
751 text_width = gl_printWidthRaw( &gl_smallFont, display );
752 if (top)
753 yoff = h + 2;
754 else
755 yoff = -gl_smallFont.h - 3;
756 tc.r = 0.;
757 tc.g = 0.;
758 tc.b = 0.;
759 tc.a = 0.9;
760 toolkit_drawRect( x, y -5. + yoff,
761 text_width+60, gl_smallFont.h+10,
762 &tc, NULL );
763 gl_printMaxRaw( &gl_smallFont, text_width,
764 x+5, y + yoff,
765 c, -1., display );
766 }
767 }
768 /* Go to next one. */
769 y -= h+20;
770 }
771}
781static void equipment_renderOverlaySlots( double bx, double by, double bw, double bh,
782 void *data )
783{
784 (void) bw;
785 Pilot *p;
786 int mover;
787 double x, y;
788 double w, h;
789 double tw;
790 int n, m;
791 PilotOutfitSlot *slot;
792 char alt[STRMAX];
793 int pos;
794 const Outfit *o;
795 CstSlotWidget *wgt;
796 size_t slen;
797
798 /* Get data. */
799 wgt = (CstSlotWidget*) data;
800 if (wgt->selected == NULL)
801 return;
802 p = wgt->selected->p;
803
804 /* Get dimensions. */
805 equipment_calculateSlots( p, bw, bh, &w, &h, &n, &m );
806 tw = bw / (double)n;
807
808 /* Get selected. */
809 mover = wgt->mouseover;
810
811 /* Render weapon outfits. */
812 x = bx + (tw-w)/2;
813 y = by + bh - (h+20) + (h+20-h)/2;
815 p->outfit_weapon, mover, wgt );
816 mover -= array_size(p->outfit_weapon);
817 x += tw;
818 y = by + bh - (h+20) + (h+20-h)/2;
820 p->outfit_utility, mover, wgt );
821 mover -= array_size(p->outfit_utility);
822 x += tw;
823 y = by + bh - (h+20) + (h+20-h)/2;
825 p->outfit_structure, mover, wgt );
826
827 /* Mouse must be over something. */
828 if (wgt->mouseover < 0)
829 return;
830
831 /* Get the slot. */
832 if (wgt->mouseover < array_size(p->outfit_weapon))
833 slot = &p->outfit_weapon[wgt->mouseover];
834 else if (wgt->mouseover < array_size(p->outfit_weapon) + array_size(p->outfit_utility))
835 slot = &p->outfit_utility[ wgt->mouseover - array_size(p->outfit_weapon) ];
836 else
837 slot = &p->outfit_structure[ wgt->mouseover -
838 array_size(p->outfit_weapon) - array_size(p->outfit_utility) ];
839
840 /* For comfortability. */
841 o = slot->outfit;
842
843 /* Slot is empty. */
844 if (o == NULL) {
845 if (slot->sslot->slot.spid) {
846 pos = scnprintf( alt, sizeof(alt),
847 "#o%s\n", _( sp_display( slot->sslot->slot.spid ) ) );
848 }
849 else
850 pos = 0;
851 pos += scnprintf( &alt[pos], sizeof(alt)-pos, _( "#%c%s #%c%s #0slot" ),
852 outfit_slotSizeColourFont( &slot->sslot->slot ), _(slotSize( slot->sslot->slot.size )),
853 outfit_slotTypeColourFont( &slot->sslot->slot ), _(slotName( slot->sslot->slot.type )) );
854 if (slot->sslot->exclusive && (pos < (int)sizeof(alt)))
855 pos += scnprintf( &alt[pos], sizeof(alt)-pos,
856 _(" [exclusive]") );
857 if (slot->sslot->locked && (pos < (int)sizeof(alt)))
858 pos += scnprintf( &alt[pos], sizeof(alt)-pos,
859 "#r%s#0", _(" [locked]") );
860 if (slot->sslot->slot.spid)
861 scnprintf( &alt[pos], sizeof(alt)-pos,
862 "\n\n%s", _( sp_description( slot->sslot->slot.spid ) ) );
863 toolkit_drawAltText( bx + wgt->altx, by + wgt->alty, alt );
864 return;
865 }
866
867 /* Get text. */
868 outfit_altText( alt, sizeof(alt), o, (p==player.p) ? p : NULL );
869
870 /* Display temporary bonuses. */
871 if (slot->lua_mem != LUA_NOREF) {
872 slen = strlen(alt);
873 ss_statsDesc( &slot->lua_stats, &alt[slen], sizeof(alt)-slen, 1 );
874 }
875
876 /* Draw the text. */
877 toolkit_drawAltText( bx + wgt->altx, by + wgt->alty, alt );
878}
879
889static void equipment_renderShip( double bx, double by,
890 double bw, double bh, void *data )
891{
892 (void) data;
893 Pilot *p;
894 int sx, sy;
895 unsigned int tick;
896 double dt;
897 double px, py;
898 double pw, ph;
899 vec2 v;
900
901 /* Must have selected ship. */
902 if (eq_wgt.selected == NULL)
903 return;
904
905 p = eq_wgt.selected->p;
906
907 tick = SDL_GetTicks();
908 dt = (double)(tick - equipment_lastick)/1000.;
909 equipment_lastick = tick;
910 equipment_dir += p->turn * dt;
911 if (equipment_dir > 2.*M_PI)
912 equipment_dir = fmod( equipment_dir, 2.*M_PI );
913 gl_getSpriteFromDir( &sx, &sy, p->ship->gfx_space, equipment_dir );
914
915 /* Render ship graphic. */
916 if (p->ship->gfx_space->sw > bw) {
917 pw = 128.;
918 ph = 128.;
919 }
920 else {
921 pw = p->ship->gfx_space->sw;
922 ph = p->ship->gfx_space->sh;
923 }
924
925 px = bx + (bw-pw)/2;
926 py = by + (bh-ph)/2;
927 gl_renderScaleSprite( p->ship->gfx_space, px, py, sx, sy, pw, ph, NULL );
928
929#ifdef DEBUGGING
930 if (debug_isFlag(DEBUG_MARK_EMITTER)) {
931 /* Visualize the trail emitters. */
932 double dircos, dirsin;
933 int i;
934 dircos = cos(equipment_dir);
935 dirsin = sin(equipment_dir);
936 for (i=0; i<array_size(p->ship->trail_emitters); i++) {
937 v.x = p->ship->trail_emitters[i].x_engine * dircos -
938 p->ship->trail_emitters[i].y_engine * dirsin;
939 v.y = p->ship->trail_emitters[i].x_engine * dirsin +
940 p->ship->trail_emitters[i].y_engine * dircos +
941 p->ship->trail_emitters[i].h_engine;
942 v.x *= pw / p->ship->gfx_space->sw;
943 v.y *= ph / p->ship->gfx_space->sh;
944 if (p->ship->trail_emitters[i].trail_spec->nebula)
945 gl_renderCross(px + pw/2. + v.x, py + ph/2. + v.y*M_SQRT1_2, 2., &cFontBlue);
946 else
947 gl_renderCross(px + pw/2. + v.x, py + ph/2. + v.y*M_SQRT1_2, 4., &cInert);
948 }
949 }
950#endif /* DEBUGGING */
951
952 if ((eq_wgt.slot >= 0) && (eq_wgt.slot < array_size(p->outfit_weapon))) {
953 p->tsx = sx;
954 p->tsy = sy;
955 pilot_getMount( p, &p->outfit_weapon[eq_wgt.slot], &v );
956 px += pw/2.;
957 py += ph/2.;
958 v.x *= pw / p->ship->gfx_space->sw;
959 v.y *= ph / p->ship->gfx_space->sh;
960
961 /* Render it. */
962 glUseProgram(shaders.crosshairs.program);
963 glUniform1f(shaders.crosshairs.paramf, 2.);
964 gl_renderShader( px+v.x, py+v.y, 7., 7., 0., &shaders.crosshairs, &cRadar_player, 1 );
965 }
966}
976static int equipment_mouseInColumn( double y, double h, int n, double my )
977{
978 for (int i=0; i<n; i++) {
979 if ((my > y) && (my < y+h+20.))
980 return i;
981 y -= h+20.;
982 }
983
984 return -1.;
985}
1000static int equipment_mouseColumn( unsigned int wid, SDL_Event* event,
1001 double mx, double my, double y, double h, PilotOutfitSlot* os,
1002 Pilot *p, int selected, CstSlotWidget *wgt )
1003{
1004 int ret = equipment_mouseInColumn( y, h, array_size(os), my );
1005 if (ret < 0)
1006 return 0;
1007
1008 if (event->type == SDL_MOUSEBUTTONDOWN) {
1009 /* Normal mouse usage. */
1010 if (wgt->weapons < 0) {
1011 if (event->button.button == SDL_BUTTON_LEFT)
1012 wgt->slot = selected + ret;
1013 else if ((event->button.button == SDL_BUTTON_RIGHT) &&
1014 wgt->canmodify && !os[ret].sslot->locked) {
1015 equipment_swapSlot( wid, p, &os[ret] );
1016 hooks_run( "equip" ); /* Equipped. */
1017 }
1018 }
1019 /* Viewing weapon slots. */
1020 else {
1021 int level;
1022 int exists = pilot_weapSetCheck( p, wgt->weapons, &os[ret] );
1023 /* Get the level of the selection. */
1024 if (event->button.button == SDL_BUTTON_LEFT)
1025 level = 0;
1026 else if (event->button.button == SDL_BUTTON_RIGHT)
1027 level = 1;
1028 else
1029 return 0; /* We ignore this type of click. */
1030 /* See if we should add it or remove it. */
1031 if (exists==level)
1032 pilot_weapSetRm( p, wgt->weapons, &os[ret] );
1033 else {
1034 /* This is a bloody awful place to do this. I hate it. HATE!. */
1035 /* Case active outfit, convert the weapon group to active outfit. */
1036 if ((os->sslot->slot.type == OUTFIT_SLOT_STRUCTURE) ||
1037 (os->sslot->slot.type == OUTFIT_SLOT_UTILITY)) {
1038 pilot_weapSetRmSlot( p, wgt->weapons, OUTFIT_SLOT_WEAPON );
1039 pilot_weapSetAdd( p, wgt->weapons, &os[ret], 0 );
1040 pilot_weapSetType( p, wgt->weapons, WEAPSET_TYPE_ACTIVE );
1041 }
1042 /* Case change weapon groups or active weapon. */
1043 else {
1044 pilot_weapSetRmSlot( p, wgt->weapons, OUTFIT_SLOT_STRUCTURE );
1045 pilot_weapSetRmSlot( p, wgt->weapons, OUTFIT_SLOT_UTILITY );
1046 if (pilot_weapSetTypeCheck( p, wgt->weapons) == WEAPSET_TYPE_CHANGE)
1047 pilot_weapSetType( p, wgt->weapons, WEAPSET_TYPE_CHANGE );
1048 else {
1049 pilot_weapSetType( p, wgt->weapons, WEAPSET_TYPE_WEAPON );
1050 level = 0;
1051 }
1052 pilot_weapSetAdd( p, wgt->weapons, &os[ret], level );
1053 }
1054 }
1055 p->autoweap = 0; /* Disable autoweap. */
1056 info_update(); /* Need to update weapons. */
1057 }
1058 }
1059 else {
1060 wgt->mouseover = selected + ret;
1061 wgt->altx = mx;
1062 wgt->alty = my;
1063 }
1064
1065 return 1;
1066}
1080static int equipment_mouseSlots( unsigned int wid, SDL_Event* event,
1081 double mx, double my, double bw, double bh,
1082 double rx, double ry, void *data )
1083{
1084 (void) bw;
1085 (void) rx;
1086 (void) ry;
1087 Pilot *p;
1088 int selected;
1089 double x, y;
1090 double w, h;
1091 double tw;
1092 CstSlotWidget *wgt;
1093 int n, m;
1094
1095 /* Get data. */
1096 wgt = (CstSlotWidget*) data;
1097 if (wgt->selected == NULL)
1098 return 0;
1099 p = wgt->selected->p;
1100
1101 /* Must be left click for now. */
1102 if ((event->type != SDL_MOUSEBUTTONDOWN) &&
1103 (event->type != SDL_MOUSEMOTION))
1104 return 0;
1105
1106 /* Is covered by something. */
1107 if (widget_isCovered( wid, "cstEquipment", mx, my )) {
1108 wgt->mouseover = -1;
1109 return 0;
1110 }
1111
1112 /* Get dimensions. */
1113 equipment_calculateSlots( p, bw, bh, &w, &h, &n, &m );
1114 tw = bw / (double)n;
1115
1116 /* Render weapon outfits. */
1117 selected = 0;
1118 x = (tw-w)/2;
1119 y = bh - (h+20) + (h+20-h)/2 - 10;
1120 if ((mx > x-10) && (mx < x+w+10)) {
1121 int ret = equipment_mouseColumn( wid, event, mx, my, y, h,
1122 p->outfit_weapon, p, selected, wgt );
1123 if (ret)
1124 return !!(event->type == SDL_MOUSEBUTTONDOWN);
1125 }
1126 selected += array_size(p->outfit_weapon);
1127 x += tw;
1128 if ((mx > x-10) && (mx < x+w+10)) {
1129 int ret = equipment_mouseColumn( wid, event, mx, my, y, h,
1130 p->outfit_utility, p, selected, wgt );
1131 if (ret)
1132 return !!(event->type == SDL_MOUSEBUTTONDOWN);
1133 }
1134 selected += array_size(p->outfit_utility);
1135 x += tw;
1136 if ((mx > x-10) && (mx < x+w+10)) {
1137 int ret = equipment_mouseColumn( wid, event, mx, my, y, h,
1138 p->outfit_structure, p, selected, wgt );
1139 if (ret)
1140 return !!(event->type == SDL_MOUSEBUTTONDOWN);
1141 }
1142
1143 /* Not over anything. */
1144 wgt->mouseover = -1;
1145 return 0;
1146}
1147
1155static int equipment_swapSlot( unsigned int wid, Pilot *p, PilotOutfitSlot *slot )
1156{
1157 /* Remove outfit. */
1158 if (slot->outfit != NULL) {
1159 int ret;
1160 const Outfit *o = slot->outfit;
1161
1162 /* Must be able to remove. */
1163 if (pilot_canEquip( eq_wgt.selected->p, slot, NULL ) != NULL)
1164 return 0;
1165
1166 /* Remove ammo first. */
1167 pilot_rmAmmo( eq_wgt.selected->p, slot, slot->u.ammo.quantity );
1168
1169 /* Remove outfit. */
1170 ret = pilot_rmOutfit( eq_wgt.selected->p, slot );
1171 if (ret == 0)
1173 }
1174 /* Add outfit. */
1175 else {
1176 int ret;
1177 const Outfit *o = eq_wgt.outfit;
1178 /* Must have outfit. */
1179 if (o==NULL)
1180 return 0;
1181
1182 /* Must fit slot. */
1183 if (!outfit_fitsSlot( o, &slot->sslot->slot ))
1184 return 0;
1185
1186 /* Must be able to add. */
1187 if (pilot_canEquip( eq_wgt.selected->p, slot, o ) != NULL)
1188 return 0;
1189
1190 /* Add outfit to ship. */
1191 ret = equipment_playerRmOutfit( o, 1 );
1192 if (ret == 1) {
1193 pilot_addOutfitRaw( eq_wgt.selected->p, o, slot );
1194
1195 /* Recalculate stats. */
1197 }
1198
1200 }
1201
1202 /* Refuel if necessary. */
1203 land_refuel();
1204
1205 /* Recalculate stats. */
1206 pilot_calcStats( p );
1207 pilot_healLanded( p );
1208
1209 /* Redo the outfits thingy. */
1210 equipment_regenLists( wid, 1, 1 );
1211
1212 /* Update outfits. */
1214
1215 /* Update weapon sets if needed. */
1216 if (eq_wgt.selected->p->autoweap) {
1219 }
1221
1222 /* Notify GUI of modification. */
1223 gui_setShip();
1224
1225 return 0;
1226}
1227
1235void equipment_regenLists( unsigned int wid, int outfits, int ships )
1236{
1237 int nship, noutfit;
1238 double offship, offoutfit;
1239 char *selship;
1240 const char *s;
1241 char *focused;
1242
1243 /* Default.s */
1244 nship = 0;
1245 offship = 0.;
1246
1247 /* Must exist. */
1249 return;
1250
1251 /* Save focus. */
1252 focused = window_getFocus( wid );
1253
1254 /* Save positions. */
1255 if (outfits) {
1256 noutfit = toolkit_getImageArrayPos( wid, EQUIPMENT_OUTFITS );
1257 offoutfit = toolkit_getImageArrayOffset( wid, EQUIPMENT_OUTFITS );
1258 window_destroyWidget( wid, EQUIPMENT_OUTFITS );
1259 }
1260 if (ships) {
1261 nship = toolkit_getImageArrayPos( wid, EQUIPMENT_SHIPS );
1262 offship = toolkit_getImageArrayOffset( wid, EQUIPMENT_SHIPS );
1263 s = toolkit_getImageArray( wid, EQUIPMENT_SHIPS );
1264 selship = strdup( s );
1265 window_destroyWidget( wid, EQUIPMENT_SHIPS );
1266 }
1267
1268 /* Regenerate lists. */
1269 equipment_genLists( wid );
1270
1271 /* Restore positions. */
1272 if (outfits) {
1273 toolkit_setImageArrayPos( wid, EQUIPMENT_OUTFITS, noutfit );
1274 toolkit_setImageArrayOffset( wid, EQUIPMENT_OUTFITS, offoutfit );
1275 equipment_updateOutfits( wid, NULL );
1276 }
1277 if (ships) {
1278 toolkit_setImageArrayPos( wid, EQUIPMENT_SHIPS, nship );
1279 toolkit_setImageArrayOffset( wid, EQUIPMENT_SHIPS, offship );
1280 /* Try to maintain same ship selected. */
1281 s = toolkit_getImageArray( wid, EQUIPMENT_SHIPS );
1282 if ((s != NULL) && (strcmp(s,selship)!=0)) {
1283 int ret = toolkit_setImageArray( wid, EQUIPMENT_SHIPS, selship );
1284 if (ret != 0) /* Failed to maintain. */
1285 toolkit_setImageArrayPos( wid, EQUIPMENT_SHIPS, nship );
1286
1287 /* Update ships. */
1288 equipment_updateShips( wid, NULL );
1289 }
1290 free( selship );
1291 }
1292
1293 /* Restore focus. */
1294 window_setFocus( wid, focused );
1295 free(focused);
1296}
1297
1302{
1303 Pilot *p;
1304
1305 /* Get player. */
1306 if (eq_wgt.selected == NULL)
1307 p = player.p;
1308 else
1309 p = eq_wgt.selected->p;
1310
1311 /* Add ammo to all outfits. */
1312 pilot_fillAmmo( p );
1313
1314 /* Notify GUI of modification. */
1315 gui_setShip();
1316}
1317
1327int equipment_shipStats( char *buf, int max_len, const Pilot *s, int dpseps, int name )
1328{
1329 int l;
1330 double eps, dps;
1331
1332 dps = 0.;
1333 eps = 0.;
1334 /* Calculate damage and energy per second. */
1335 if (dpseps)
1336 pilot_dpseps( s, &dps, &eps );
1337
1338 /* Write to buffer. */
1339 if (name)
1340 l = scnprintf( buf, max_len, "%s\n", s->name );
1341 else
1342 l = 0;
1343 if (dps > 0.)
1344 l += scnprintf( &buf[l], (max_len-l),
1345 _("%.2f DPS [%.2f EPS]"), dps, eps );
1346 l += ss_statsDesc( &s->stats, &buf[l], (max_len-l), l );
1347 return l;
1348}
1349
1353static void equipment_toggleFav( unsigned int wid, const char *wgt )
1354{
1355 int state = window_checkboxState( wid, wgt );
1356 const char *shipname = toolkit_getImageArray( wid, EQUIPMENT_SHIPS );
1357 if (strcmp(shipname,player.p->name)==0) { /* no ships */
1358 player.ps.favourite = state;
1359 }
1360 else {
1361 PlayerShip_t *ps = player_getPlayerShip( shipname );
1362 ps->favourite = state;
1363 }
1364
1365 /* Update ship to reflect changes. */
1366 equipment_regenLists( wid, 0, 1 );
1367}
1368
1369static void equipment_toggleDeploy( unsigned int wid, const char *wgt )
1370{
1371 int state = window_checkboxState( wid, wgt );
1372 const char *shipname = toolkit_getImageArray( wid, EQUIPMENT_SHIPS );
1373
1374 /* Can't deploy if no capacity. */
1375 if (player.fleet_capacity <= 0)
1376 return;
1377
1378 /* Only if current ship isn't selected try to deploy. */
1379 if (strcmp(shipname,player.p->name)!=0) {
1380 PlayerShip_t *ps = player_getPlayerShip( shipname );
1381 if (state && ship_isFlag( ps->p->ship, SHIP_NOESCORT )) {
1382 dialogue_msg( _("Invalid Escort"), _("You can not set your ship '%s' as an escort!"), ps->p->name );
1383 return;
1384 }
1385 if (pfleet_toggleDeploy( ps, state ))
1386 return;
1387 pfleet_update();
1388 }
1389 else
1390 window_checkboxSet( wid, wgt, 1 ); /* Player is always deployed. */
1391
1392 /* Update ship to reflect changes. */
1393 equipment_regenLists( wid, 0, 1 );
1394}
1395
1401static void equipment_genLists( unsigned int wid )
1402{
1403 /* Ship list. */
1404 equipment_genShipList( wid );
1405
1406 /* Outfit list. */
1408
1409 /* Update window. */
1410 equipment_updateOutfits(wid, NULL);
1411 equipment_updateShips(wid, NULL);
1412}
1413
1418static void equipment_genShipList( unsigned int wid )
1419{
1420 int l;
1421 ImageArrayCell *cships;
1422 int nships;
1423 int w, h;
1424 int sw, sh;
1425 Pilot *s;
1426 const PlayerShip_t *ps;
1427 char r[PATH_MAX];
1428 glTexture *t;
1429 int iconsize;
1430
1431 /* Get dimensions. */
1432 equipment_getDim( wid, &w, &h, &sw, &sh, NULL, NULL,
1433 NULL, NULL, NULL, NULL, NULL, NULL );
1434
1435 if (widget_exists( wid, EQUIPMENT_SHIPS ))
1436 return;
1437
1438 eq_wgt.selected = NULL;
1439 if (spob_hasService(land_spob, SPOB_SERVICE_SHIPYARD))
1440 nships = player_nships()+1;
1441 else
1442 nships = 1;
1443 cships = calloc( nships, sizeof(ImageArrayCell) );
1444 /* Add player's current ship. */
1445 cships[0].image = gl_dupTexture(player.p->ship->gfx_store);
1446 cships[0].caption = strdup(player.p->name);
1447 cships[0].layers = gl_copyTexArray( player.p->ship->gfx_overlays, &cships[0].nlayers );
1448 t = gl_newImage( OVERLAY_GFX_PATH"active.webp", 0 );
1449 cships[0].layers = gl_addTexArray( cships[0].layers, &cships[0].nlayers, t );
1450 if (player.ps.favourite) {
1451 t = gl_newImage( OVERLAY_GFX_PATH"favourite.webp", 0 );
1452 cships[0].layers = gl_addTexArray( cships[0].layers, &cships[0].nlayers, t );
1453 }
1454 if (player.p->ship->rarity > 0) {
1455 snprintf( r, sizeof(r), OVERLAY_GFX_PATH"rarity_%d.webp", player.p->ship->rarity );
1456 t = gl_newImage( r, 0 );
1457 cships[0].layers = gl_addTexArray( cships[0].layers, &cships[0].nlayers, t );
1458 }
1459 if (spob_hasService(land_spob, SPOB_SERVICE_SHIPYARD)) {
1461 ps = player_getShipStack();
1462 for (int i=1; i<=array_size(ps); i++) {
1463 cships[i].image = gl_dupTexture( ps[i-1].p->ship->gfx_store );
1464 cships[i].caption = strdup( ps[i-1].p->name );
1465 cships[i].layers = gl_copyTexArray( ps[i-1].p->ship->gfx_overlays, &cships[i].nlayers );
1466 if (ps[i-1].favourite) {
1467 t = gl_newImage( OVERLAY_GFX_PATH"favourite.webp", 0 );
1468 cships[i].layers = gl_addTexArray( cships[i].layers, &cships[i].nlayers, t );
1469 }
1470 if (ps[i-1].deployed) {
1471 t = gl_newImage( OVERLAY_GFX_PATH"fleet.webp", 0 );
1472 cships[i].layers = gl_addTexArray( cships[i].layers, &cships[i].nlayers, t );
1473 }
1474 if (ps[i-1].p->ship->rarity > 0) {
1475 snprintf( r, sizeof(r), OVERLAY_GFX_PATH"rarity_%d.webp", ps[i-1].p->ship->rarity );
1476 t = gl_newImage( r, 0 );
1477 cships[i].layers = gl_addTexArray( cships[i].layers, &cships[i].nlayers, t );
1478 }
1479 }
1480 }
1481 /* Ship stats in alt text. */
1482 for (int i=0; i<nships; i++) {
1483 s = player_getShip( cships[i].caption );
1484 cships[i].alt = malloc( STRMAX_SHORT );
1485 l = snprintf( &cships[i].alt[0], STRMAX_SHORT, _("Ship Stats\n") );
1486 l = equipment_shipStats( &cships[i].alt[0], STRMAX_SHORT-l, s, 1, 1 );
1487 if (l == 0) {
1488 free( cships[i].alt );
1489 cships[i].alt = NULL;
1490 }
1491 }
1492
1493 /* Create the image array. */
1494 iconsize = 96;
1495 if (!conf.big_icons) {
1496 if (toolkit_simImageArrayVisibleElements(sw,sh,iconsize,iconsize) < nships)
1497 iconsize = 80;
1498 if (toolkit_simImageArrayVisibleElements(sw,sh,iconsize,iconsize) < nships)
1499 iconsize = 64;
1500 }
1501 window_addImageArray( wid, 20, -40,
1502 sw, sh, EQUIPMENT_SHIPS, iconsize, iconsize,
1504 toolkit_setImageArrayAccept( wid, EQUIPMENT_SHIPS, equipment_transChangeShip );
1505}
1506
1507static int equipment_filter( const Outfit *o ) {
1508 Pilot *p;
1509 const PlayerShip_t *ps;
1510
1511 switch (equipment_outfitMode) {
1512 case 0:
1513 return 1;
1514
1515 case 1: /* Fits any ship of the player. */
1516 ps = player_getShipStack();
1517 for (int j=0; j < array_size(ps); j++) {
1518 p = ps[j].p;
1519 for (int i=0; i < array_size(p->outfits); i++) {
1520 if (outfit_fitsSlot( o, &p->outfits[i]->sslot->slot ))
1521 return 1;
1522 }
1523 }
1524 return 0;
1525
1526 case 2: /* Fits currently selected ship. */
1527 if (eq_wgt.selected==NULL)
1528 return 1;
1529 p = eq_wgt.selected->p;
1530 if (p==NULL)
1531 return 1;
1532 for (int i=0; i < array_size(p->outfits); i++) {
1533 if (outfit_fitsSlot( o, &p->outfits[i]->sslot->slot ))
1534 return 1;
1535 }
1536 return 0;
1537
1538 case 3:
1539 return (o->slot.size==OUTFIT_SLOT_SIZE_LIGHT);
1540 case 4:
1541 return (o->slot.size==OUTFIT_SLOT_SIZE_MEDIUM);
1542 case 5:
1543 return (o->slot.size==OUTFIT_SLOT_SIZE_HEAVY);
1544 }
1545 return 1;
1546}
1547static int equipment_filterWeapon( const Outfit *o ) {
1548 return equipment_filter(o) && outfit_filterWeapon(o);
1549}
1550static int equipment_filterUtility( const Outfit *o ) {
1551 return equipment_filter(o) && outfit_filterUtility(o);
1552}
1553static int equipment_filterStructure( const Outfit *o ) {
1554 return equipment_filter(o) && outfit_filterStructure(o);
1555}
1556static int equipment_filterCore( const Outfit *o ) {
1557 return equipment_filter(o) && outfit_filterCore(o);
1558}
1559
1564static void equipment_genOutfitList( unsigned int wid )
1565{
1566 int x, y, w, h, ow, oh;
1567 int ix, iy, iw, ih, barw; /* Input filter. */
1568 const char *filtertext;
1569 int (*tabfilters[])( const Outfit *o ) = {
1570 equipment_filter,
1571 equipment_filterWeapon,
1572 equipment_filterUtility,
1573 equipment_filterStructure,
1574 equipment_filterCore,
1575 };
1576 const char *tabnames[] = {
1577 _("All"), _(OUTFIT_LABEL_WEAPON), _(OUTFIT_LABEL_UTILITY), _(OUTFIT_LABEL_STRUCTURE), _(OUTFIT_LABEL_CORE)
1578 };
1579 int noutfits, active;
1580 ImageArrayCell *coutfits;
1581 int iconsize;
1582 Pilot *p = (eq_wgt.selected != NULL) ? eq_wgt.selected->p : NULL;
1583
1584 /* Get dimensions. */
1585 equipment_getDim( wid, &w, &h, NULL, NULL, &ow, &oh,
1586 NULL, NULL, NULL, NULL, NULL, NULL );
1587
1588 /* Deselect. */
1589 eq_wgt.outfit = NULL;
1590
1591 /* Calculate position. */
1592 x = 20;
1593 y = 20;
1594
1595 /* Create tabbed window. */
1596 if (!widget_exists( wid, EQUIPMENT_OUTFIT_TAB )) {
1597 window_addTabbedWindow( wid, x, y + oh - 30, ow, 30,
1598 EQUIPMENT_OUTFIT_TAB, OUTFIT_TABS, tabnames, 1 );
1599
1600 barw = window_tabWinGetBarWidth( wid, EQUIPMENT_OUTFIT_TAB );
1601
1602 iw = CLAMP(0, 150, ow - barw - 30);
1603 ih = 30;
1604
1605 ix = ow - iw + 15;
1606 iy = y + oh - 25 - 1;
1607
1608#ifdef DEBUGGING
1609 if (iw <= 60)
1610 WARN(_("Very little space on equipment outfit tabs!"));
1611#endif /* DEBUGGING */
1612
1613 /* Add popdown menu stuff. */
1614 window_addButton( wid, ix+iw-30, iy, 30, 30, "btnOutfitFilter", NULL, equipment_outfitPopdown );
1615 window_buttonCustomRender( wid, "btnOutfitFilter", window_buttonCustomRenderGear );
1616 iw -= 35;
1617
1618 /* Set text filter. */
1619 window_addInput( wid, ix, iy, iw, ih, EQUIPMENT_FILTER, 32, 1, NULL );
1620 inp_setEmptyText( wid, EQUIPMENT_FILTER, _("Filter…") );
1621 window_setInputCallback( wid, EQUIPMENT_FILTER, equipment_filterOutfits );
1622 }
1623
1624 window_tabWinOnChange( wid, EQUIPMENT_OUTFIT_TAB, equipment_changeTab );
1625 active = window_tabWinGetActive( equipment_wid, EQUIPMENT_OUTFIT_TAB );
1626
1627 /* Widget must not already exist. */
1628 if (widget_exists( wid, EQUIPMENT_OUTFITS ))
1629 return;
1630
1631 /* Allocate space. */
1632 noutfits = MAX( 1, player_numOutfits() ); /* This is the most we'll need, probably less due to filtering. */
1633 free( iar_outfits[active] );
1634 iar_outfits[active] = calloc( noutfits, sizeof(Outfit*) );
1635
1636 filtertext = NULL;
1637 if (widget_exists(equipment_wid, EQUIPMENT_FILTER)) {
1638 filtertext = window_getInput( equipment_wid, EQUIPMENT_FILTER );
1639 if (strlen(filtertext) == 0)
1640 filtertext = NULL;
1641 }
1642
1643 /* Get the outfits. */
1644 noutfits = player_getOutfitsFiltered( (const Outfit**)iar_outfits[active], tabfilters[active], filtertext );
1645 coutfits = outfits_imageArrayCells( (const Outfit**)iar_outfits[active], &noutfits, (p==NULL) ? player.p : p );
1646
1647 /* Create the actual image array. */
1648 iw = ow - 6;
1649 ih = oh - 37;
1650 iconsize = 96;
1651 if (!conf.big_icons) {
1652 if (toolkit_simImageArrayVisibleElements(iw,ih,iconsize,iconsize) < noutfits)
1653 iconsize = 80;
1654 if (toolkit_simImageArrayVisibleElements(iw,ih,iconsize,iconsize) < noutfits)
1655 iconsize = 64;
1656 }
1657 window_addImageArray( wid, x + 4, y + 3, iw, ih,
1658 EQUIPMENT_OUTFITS, iconsize, iconsize,
1659 coutfits, noutfits,
1663
1664 toolkit_setImageArrayAccept( wid, EQUIPMENT_OUTFITS, equipment_rightClickOutfits );
1665}
1666
1670static char eq_qCol( double cur, double base, int inv )
1671{
1672 if (cur > 1.2*base)
1673 return (inv) ? 'r' : 'g';
1674 else if (cur < 0.8*base)
1675 return (inv) ? 'g' : 'r';
1676 return '0';
1677}
1678
1682static const char* eq_qSym( double cur, double base, int inv )
1683{
1684 if (cur > 1.2*base)
1685 return (inv) ? "!! " : "";
1686 else if (cur < 0.8*base)
1687 return (inv) ? "" : "!! ";
1688 return "";
1689}
1690
1691#define EQ_COMP( cur, base, inv ) \
1692eq_qCol( cur, base, inv ), eq_qSym( cur, base, inv ), cur
1698void equipment_updateShips( unsigned int wid, const char* str )
1699{
1700 (void) str;
1701 char buf[STRMAX], buf_price[ECON_CRED_STRLEN];
1702 char errorReport[STRMAX_SHORT], tbuf[64];
1703 const char *shipname, *acquired;
1704 char sdet[NUM2STRLEN], seva[NUM2STRLEN], sste[NUM2STRLEN];
1705 char smass[NUM2STRLEN], sfuel[NUM2STRLEN];
1706 Pilot *ship;
1707 PlayerShip_t *ps, *prevship;
1708 char *nt;
1709 int onboard, cargo, jumps, favourite, deployed, x, h, spaceworthy;
1710 int ww, wh, sw, sh, hacquired, hname;
1711 int wgtw, wgth;
1712 size_t l = 0;
1713
1714 equipment_getDim( wid, &ww, &wh, &sw, &sh, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL );
1715
1716 /* Clear defaults. */
1717 eq_wgt.slot = -1;
1718 eq_wgt.mouseover = -1;
1719 equipment_lastick = SDL_GetTicks();
1720
1721 /* Get the ship. */
1722 shipname = toolkit_getImageArray( wid, EQUIPMENT_SHIPS );
1723 if (strcmp(shipname,player.p->name)==0) { /* no ships */
1724 ps = &player.ps;
1725 onboard = 1;
1726 deployed = 1;
1727 }
1728 else {
1729 ps = player_getPlayerShip( shipname );
1730 onboard = 0;
1731 deployed = ps->deployed;
1732 }
1733 ship = ps->p;
1734 favourite = ps->favourite;
1735 prevship = eq_wgt.selected;
1736 eq_wgt.selected = ps;
1737
1738 /* update text */
1739 credits2str( buf_price, player_shipPrice(shipname), 2 ); /* sell price */
1740 cargo = pilot_cargoFree(ship) + pilot_cargoUsed(ship);
1741 nt = ntime_pretty( pilot_hyperspaceDelay( ship ), 2 );
1742
1743 /* Get ship error report. */
1744 spaceworthy = !pilot_reportSpaceworthy( ship, errorReport, sizeof(errorReport));
1745
1746 jumps = floor(ship->fuel_max / ship->fuel_consumption);
1747
1748 /* Get acquired text length. */
1749 x = 20+sw+20+180+10;
1750 acquired = (ps->acquired) ? ps->acquired : _("You do not remember how you acquired this ship.");
1751 window_dimWidget( wid, "txtAcquired", &wgtw, &wgth );
1752 hacquired = gl_printLinesRaw( &gl_defFont, wgtw, acquired );
1753 window_dimWidget( wid, "txtDDesc", &wgtw, &wgth );
1754 hname = gl_printLinesRaw( &gl_defFont, wgtw, ship->name );
1755
1756 /* Stealth stuff. */
1757 num2str( sdet, ship->ew_detection, 0 );
1758 num2str( seva, ship->ew_evasion, 0 );
1759 num2str( sste, ship->ew_stealth, 0 );
1760 num2str( smass, ship->solid->mass, 0 );
1761 num2str( sfuel, ship->fuel_max, 0 );
1762
1763 l += scnprintf( &buf[l], sizeof(buf)-l, "%s", _("Name:") );
1764 for (int i=0; i<hname-1; i++)
1765 l += scnprintf( &buf[l], sizeof(buf)-l, "\n" );
1766 l += scnprintf( &buf[l], sizeof(buf)-l, "\n%s", _("Model:") );
1767 l += scnprintf( &buf[l], sizeof(buf)-l, "\n%s", _("Class:") );
1768 l += scnprintf( &buf[l], sizeof(buf)-l, "\n%s", _("Acquired Date:") );
1769 for (int i=0; i<hacquired+1; i++)
1770 l += scnprintf( &buf[l], sizeof(buf)-l, "\n" );
1771 if (ship_mode==0) {
1772 l += scnprintf( &buf[l], sizeof(buf)-l, "\n%s", _("Value:") );
1773 if (player.fleet_capacity > 0)
1774 l += scnprintf( &buf[l], sizeof(buf)-l, "\n%s", _("Fleet Capacity:") );
1775 l += scnprintf( &buf[l], sizeof(buf)-l, "\n%s", _("Crew:") );
1776 l += scnprintf( &buf[l], sizeof(buf)-l, "\n%s", _("Mass:") );
1777 l += scnprintf( &buf[l], sizeof(buf)-l, "\n%s", _("Jump Time:") );
1778 l += scnprintf( &buf[l], sizeof(buf)-l, "\n%s", _("Thrust:") );
1779 l += scnprintf( &buf[l], sizeof(buf)-l, "\n%s", _("Speed:") );
1780 l += scnprintf( &buf[l], sizeof(buf)-l, "\n%s", _("Turn:") );
1781 l += scnprintf( &buf[l], sizeof(buf)-l, "\n%s", _("Time Constant:") );
1782 l += scnprintf( &buf[l], sizeof(buf)-l, "\n%s", _("Detected at:") );
1783 l += scnprintf( &buf[l], sizeof(buf)-l, "\n%s", _("Evasion:") );
1784 l += scnprintf( &buf[l], sizeof(buf)-l, "\n%s", _("Stealth:") );
1785 l += scnprintf( &buf[l], sizeof(buf)-l, "\n" );
1786 l += scnprintf( &buf[l], sizeof(buf)-l, "\n%s", _("Absorption:") );
1787 l += scnprintf( &buf[l], sizeof(buf)-l, "\n%s", _("Shield:") );
1788 l += scnprintf( &buf[l], sizeof(buf)-l, "\n%s", _("Armour:") );
1789 l += scnprintf( &buf[l], sizeof(buf)-l, "\n%s", _("Energy:") );
1790 l += scnprintf( &buf[l], sizeof(buf)-l, "\n%s", _("Cargo Space:") );
1791 l += scnprintf( &buf[l], sizeof(buf)-l, "\n%s", _("Fuel:") );
1792 l += scnprintf( &buf[l], sizeof(buf)-l, "\n" );
1793 l += scnprintf( &buf[l], sizeof(buf)-l, "\n%s", _("Ship Status:") );
1794 }
1795 else {
1796 l += scnprintf( &buf[l], sizeof(buf)-l, "\n%s", _("Time Flown:") );
1797 l += scnprintf( &buf[l], sizeof(buf)-l, "\n%s", _("Jumped Times:") );
1798 l += scnprintf( &buf[l], sizeof(buf)-l, "\n%s", _("Landed Times:") );
1799 l += scnprintf( &buf[l], sizeof(buf)-l, "\n%s", _("Damage Done:") );
1800 l += scnprintf( &buf[l], sizeof(buf)-l, "\n%s", _("Damage Taken:") );
1801 l += scnprintf( &buf[l], sizeof(buf)-l, "\n%s", _("Ships Destroyed:") );
1802 l += scnprintf( &buf[l], sizeof(buf)-l, "\n\n%s", _("Intrinsic Outfits:") );
1803 }
1804 window_modifyText( wid, "txtSDesc", buf );
1805
1806 /* Fill the buffer. */
1807 /* Generic. */
1808 l = 0;
1809 l += scnprintf( &buf[l], sizeof(buf)-l, "%s", ship->name );
1810 l += scnprintf( &buf[l], sizeof(buf)-l, "\n%s", _(ship->ship->name) );
1811 l += scnprintf( &buf[l], sizeof(buf)-l, "\n%s", _(ship_classDisplay(ship->ship)) );
1812 if (ps->acquired_date==0)
1813 snprintf( tbuf, sizeof(tbuf), _("Unknown") );
1814 else
1815 ntime_prettyBuf( tbuf, sizeof(tbuf), ps->acquired_date, 2 );
1816 l += scnprintf( &buf[l], sizeof(buf)-l, "\n%s", tbuf );
1817
1818 h = gl_printHeightRaw( &gl_defFont, wgtw, buf );
1819 window_moveWidget( wid, "txtAcquired", x, -40-h-6 );
1820 window_modifyText( wid, "txtAcquired", acquired );
1821
1822 for (int i=0; i<hacquired+1; i++)
1823 l += scnprintf( &buf[l], sizeof(buf)-l, "\n%s", "" );
1824 if (ship_mode==0) {
1825 /* Some core stats. */
1826 l += scnprintf( &buf[l], sizeof(buf)-l, "\n%s", buf_price );
1827 if (player.fleet_capacity > 0)
1828 l += scnprintf( &buf[l], sizeof(buf)-l, "\n%d", ship->ship->points );
1829 l += scnprintf( &buf[l], sizeof(buf)-l, "\n#%c%s%.0f#0", EQ_COMP( ship->crew, ship->ship->crew, 0 ) );
1830 l += scnprintf( &buf[l], sizeof(buf)-l, "\n%s#0 %s", smass, n_( "tonne", "tonnes", ship->solid->mass ) );
1831 l += scnprintf( &buf[l], sizeof(buf)-l, "\n%s", "" );
1832 l += scnprintf( &buf[l], sizeof(buf)-l, _("%s average"), nt );
1833 l += scnprintf( &buf[l], sizeof(buf)-l, "\n%s", "" );
1834 l += scnprintf( &buf[l], sizeof(buf)-l, _("#%c%s%.0f#0 kN/tonne"),
1835 EQ_COMP( ship->thrust/ship->solid->mass, ship->ship->thrust/ship->ship->mass, 0 ) );
1836 l += scnprintf( &buf[l], sizeof(buf)-l, _("\n#%c%s%.0f#0 m/s (max #%c%s%.0f#0 m/s)"),
1837 EQ_COMP( ship->speed, ship->ship->speed, 0 ), EQ_COMP( solid_maxspeed( ship->solid, ship->speed, ship->thrust ),
1838 solid_maxspeed( ship->solid, ship->ship->speed, ship->ship->thrust), 0 ) );
1839 l += scnprintf( &buf[l], sizeof(buf)-l, _("\n#%c%s%.0f#0 deg/s"),
1840 EQ_COMP( ship->turn*180./M_PI, ship->ship->turn*180./M_PI, 0 ) );
1841 l += scnprintf( &buf[l], sizeof(buf)-l, "\n%.0f%%", ship->stats.time_mod * ship->ship->dt_default * 100 );
1842 l += scnprintf( &buf[l], sizeof(buf)-l, "\n%s\n", sdet );
1843 l += scnprintf( &buf[l], sizeof(buf)-l, _("%s (%.1f secs for scan)"), seva, pilot_ewScanTime(ship) );
1844 l += scnprintf( &buf[l], sizeof(buf)-l, "\n%s\n", sste );
1845 l += scnprintf( &buf[l], sizeof(buf)-l, "\n%s", "" );
1846 /* Health. */
1847 l += scnprintf( &buf[l], sizeof(buf)-l, "#%c%s%.0f%%\n", EQ_COMP( ship->dmg_absorb * 100, ship->ship->dmg_absorb * 100, 0 ) );
1848 l += scnprintf( &buf[l], sizeof(buf)-l, _("#%c%s%.0f#0 MJ (#%c%s%.1f#0 MW)"),
1849 EQ_COMP( ship->shield_max, ship->ship->shield, 0 ), EQ_COMP( ship->shield_regen, ship->ship->shield_regen, 0 ) );
1850 l += scnprintf( &buf[l], sizeof(buf)-l, "\n%s", "" );
1851 l += scnprintf( &buf[l], sizeof(buf)-l, _("#%c%s%.0f#0 MJ (#%c%s%.1f#0 MW)"),
1852 EQ_COMP( ship->armour_max, ship->ship->armour, 0 ), EQ_COMP( ship->armour_regen, ship->ship->armour_regen, 0 ) );
1853 l += scnprintf( &buf[l], sizeof(buf)-l, "\n%s", "" );
1854 l += scnprintf( &buf[l], sizeof(buf)-l, _("#%c%s%.0f#0 MJ (#%c%s%.1f#0 MW)"),
1855 EQ_COMP( ship->energy_max, ship->ship->energy, 0 ), EQ_COMP( ship->energy_regen, ship->ship->energy_regen, 0 ) );
1856 l += scnprintf( &buf[l], sizeof(buf)-l, "\n%s", "" );
1857 /* Misc. */
1858 l += scnprintf( &buf[l], sizeof(buf)-l, _("%d / #%c%s%d#0 %s"),
1859 pilot_cargoUsed(ship), EQ_COMP( cargo, ship->ship->cap_cargo, 0 ), n_( "tonne", "tonnes", ship->ship->cap_cargo ) );
1860 l += scnprintf( &buf[l], sizeof(buf)-l, "\n%s", "" );
1861 l += scnprintf( &buf[l], sizeof(buf)-l, _("%s %s (%d %s)"),
1862 sfuel, n_( "unit", "units", ship->fuel_max ), jumps, n_( "jump", "jumps", jumps ) );
1863 l += scnprintf( &buf[l], sizeof(buf)-l, "\n%s", "" );
1864 l += scnprintf( &buf[l], sizeof(buf)-l, "\n#%c%s#0", spaceworthy ? '0' : 'r', errorReport );
1865 }
1866 else {
1867 int destroyed = 0;
1868 for (int i=0; i<SHIP_CLASS_TOTAL; i++)
1869 destroyed += ps->ships_destroyed[i];
1870 l += scnprintf( &buf[l], sizeof(buf)-l, "\n%s", "" );
1871 l += scnprintf( &buf[l], sizeof(buf)-l, _("%.1f hours"), ps->time_played/3600. );
1872 l += scnprintf( &buf[l], sizeof(buf)-l, "\n%s", num2strU(ps->jumped_times,0) );
1873 l += scnprintf( &buf[l], sizeof(buf)-l, "\n%s", num2strU(ps->landed_times,0) );
1874 l += scnprintf( &buf[l], sizeof(buf)-l, "\n%s", "" );
1875 l += scnprintf( &buf[l], sizeof(buf)-l, _("%s MJ"), num2strU(ps->dmg_done_shield+ps->dmg_done_armour,0) );
1876 l += scnprintf( &buf[l], sizeof(buf)-l, "\n%s", "" );
1877 l += scnprintf( &buf[l], sizeof(buf)-l, _("%s MJ"), num2strU(ps->dmg_taken_shield+ps->dmg_taken_armour,0) );
1878 l += scnprintf( &buf[l], sizeof(buf)-l, "\n%s", num2strU(destroyed,0) );
1879 l += scnprintf( &buf[l], sizeof(buf)-l, "\n" );
1880 for (int i=0; i<array_size(ps->p->outfit_intrinsic); i++)
1881 l += scnprintf( &buf[l], sizeof(buf)-l, "\n%s", _(ps->p->outfit_intrinsic[i].outfit->name) );
1882 }
1883 window_modifyText( wid, "txtDDesc", buf );
1884
1885 /* Clean up. */
1886 free( nt );
1887
1888 /* Set checkboxes. */
1889 window_checkboxSet( wid, "chkFav", favourite );
1890 if (player.fleet_capacity > 0)
1891 window_checkboxSet( wid, "chkDeploy", deployed );
1892
1893 /* button disabling */
1894 if (onboard) {
1895 window_disableButton( wid, "btnSellShip" );
1896 window_disableButton( wid, "btnChangeShip" );
1897 }
1898 else {
1899 window_enableButton( wid, "btnChangeShip" );
1900 window_enableButton( wid, "btnSellShip" );
1901 }
1902
1903 /* If pilot-dependent outfit filter modes are active, we have to regenerate outfits always. */
1904 if ((equipment_outfitMode==2) && (eq_wgt.selected != prevship))
1905 equipment_regenLists( wid, 1, 0 );
1906}
1907#undef EQ_COMP
1913void equipment_updateOutfits( unsigned int wid, const char* str )
1914{
1915 (void) str;
1916 int i, active;
1917
1918 /* Must have outfit. */
1919 active = window_tabWinGetActive( wid, EQUIPMENT_OUTFIT_TAB );
1920 i = toolkit_getImageArrayPos( wid, EQUIPMENT_OUTFITS );
1921 if (i < 0 || iar_outfits[active] == NULL) {
1922 eq_wgt.outfit = NULL;
1923 return;
1924 }
1925
1926 eq_wgt.outfit = iar_outfits[active][i];
1927}
1928
1934static void equipment_filterOutfits( unsigned int wid, const char *str )
1935{
1936 (void) str;
1937 equipment_regenLists(wid, 1, 0);
1938}
1939
1944static void equipment_outfitPopdownSelect( unsigned int wid, const char *str )
1945{
1946 int m = toolkit_getListPos( wid, str );
1947 if (m == equipment_outfitMode)
1948 return;
1949
1951 equipment_regenLists( wid, 1, 0 );
1953}
1954
1955static void equipment_outfitPopdownActivate( unsigned int wid, const char *str )
1956{
1958 window_destroyWidget( wid, str );
1959}
1960
1961static void equipment_outfitPopdown( unsigned int wid, const char* str )
1962{
1963 const char *name = "lstOutfitPopdown";
1964 const char *modes[] = {
1965 N_("Show all outfits"),
1966 N_("Show only outfits equipable on any of your ships"),
1967 N_("Show only outfits equipable on current ship"),
1968 N_("Show only light outfits"),
1969 N_("Show only medium outfits"),
1970 N_("Show only heavy outfits"),
1971 };
1972 char **modelist;
1973 const size_t n = sizeof(modes) / sizeof(const char*);
1974 int x, y, w, h;
1975
1976 if (widget_exists( wid, name )) {
1977 window_destroyWidget( wid, name );
1978 return;
1979 }
1980
1981 modelist = malloc(sizeof(modes));
1982 for (size_t i=0; i<n; i++)
1983 modelist[i] = strdup( _(modes[i]) );
1984
1985 window_dimWidget( wid, str, &w, &h );
1986 window_posWidget( wid, str, &x, &y );
1987 window_addList( wid, x+w, y-120+h, 350, 120, name, modelist, n, equipment_outfitMode, equipment_outfitPopdownSelect, equipment_outfitPopdownActivate );
1988 window_setFocus( wid, name );
1989}
1990
1999static void equipment_changeTab( unsigned int wid, const char *wgt, int old, int tab )
2000{
2001 (void) wid;
2002 (void) wgt;
2003 int pos;
2004 double offset;
2005
2006 toolkit_saveImageArrayData( wid, EQUIPMENT_OUTFITS, &iar_data[old] );
2007
2008 /* Store the currently-saved positions for the new tab. */
2009 pos = iar_data[tab].pos;
2010 offset = iar_data[tab].offset;
2011
2012 /* Resetting the input will cause the outfit list to be regenerated. */
2013 if (widget_exists(wid, EQUIPMENT_FILTER))
2014 window_setInput(wid, EQUIPMENT_FILTER, NULL);
2015 else
2016 equipment_regenLists(wid, 1, 0);
2017
2018 /* Set positions for the new tab. This is necessary because the stored
2019 * position for the new tab may have exceeded the size of the old tab,
2020 * resulting in it being clipped. */
2021 toolkit_setImageArrayPos( wid, EQUIPMENT_OUTFITS, pos );
2022 toolkit_setImageArrayOffset( wid, EQUIPMENT_OUTFITS, offset );
2023
2024 /* Focus the outfit image array. */
2025 window_setFocus( wid, EQUIPMENT_OUTFITS );
2026}
2027
2031static void equipment_rightClickShips( unsigned int wid, const char *str )
2032{
2033 const char *shipname = toolkit_getImageArray( wid, str );
2034 PlayerShip_t *ps = player_getPlayerShip( shipname );
2035
2036 /* Must have fleet capacity. */
2037 if (player.fleet_capacity <= 0)
2038 return;
2039
2040 /* Deploy the ship if applicable. */
2041 if (ps == NULL)
2042 return;
2043
2044 /* Don't do anything for player ship. */
2045 if (strcmp(shipname,player.p->name)==0)
2046 return;
2047
2048 if (!ps->deployed && ship_isFlag( ps->p->ship, SHIP_NOESCORT )) {
2049 dialogue_msg( _("Invalid Escort"), _("You can not set your ship '%s' as an escort!"), ps->p->name );
2050 return;
2051 }
2052
2053 /* Try to deploy. */
2054 if (pfleet_toggleDeploy( ps, !ps->deployed ))
2055 return;
2056
2057 if (player.fleet_capacity > 0)
2058 window_checkboxSet( wid, "chkDeploy", ps->deployed );
2059
2060 pfleet_update();
2061
2062 equipment_regenLists( wid, 0, 1 );
2063}
2064
2070static void equipment_transChangeShip( unsigned int wid, const char* str )
2071{
2072 (void) str;
2073
2074 equipment_changeShip( wid );
2075
2076 /* update the window to reflect the change */
2077 equipment_updateShips( wid, NULL );
2078}
2083static void equipment_changeShip( unsigned int wid )
2084{
2085 const char *shipname, *filtertext;
2086 PlayerShip_t *ps;
2087 int i;
2088
2089 shipname = toolkit_getImageArray( wid, EQUIPMENT_SHIPS );
2090 ps = player_getPlayerShip( shipname );
2091 if (ps != NULL) {
2092 /* Swap deployed status. */
2093 player.ps.deployed = ps->deployed;
2094 }
2095
2096 if (land_errDialogue( shipname, "swapEquipment" ))
2097 return;
2098
2099 /* Store active tab, filter text, and positions for the outfits. */
2100 i = window_tabWinGetActive( wid, EQUIPMENT_OUTFIT_TAB );
2101 toolkit_saveImageArrayData( wid, EQUIPMENT_OUTFITS, &iar_data[i] );
2102 if (widget_exists(wid, EQUIPMENT_FILTER))
2103 filtertext = window_getInput( equipment_wid, EQUIPMENT_FILTER );
2104 else
2105 filtertext = NULL;
2106
2107 /* Swap ship. */
2108 player_swapShip( shipname, 1 );
2110
2111 /* What happens here is the gui gets recreated when the player swaps ship.
2112 * This causes all the windows to be destroyed and the 'wid' we have here
2113 * becomes invalid. However, since we store it in a global variable we can
2114 * recover it and use it instead. */
2115 wid = equipment_wid;
2116
2117 /* Restore outfits image array properties. */
2118 window_tabWinSetActive( wid, EQUIPMENT_OUTFIT_TAB, i );
2119 toolkit_setImageArrayPos( wid, EQUIPMENT_OUTFITS, iar_data[i].pos );
2120 toolkit_setImageArrayOffset( wid, EQUIPMENT_OUTFITS, iar_data[i].offset );
2121 if (widget_exists(wid, EQUIPMENT_FILTER))
2122 window_setInput(wid, EQUIPMENT_FILTER, filtertext);
2123
2124 /* Regenerate ship widget. */
2125 equipment_regenLists( wid, 0, 1 );
2126
2127 /* Focus new ship. */
2128 toolkit_setImageArrayPos( wid, EQUIPMENT_SHIPS, 0 );
2129 toolkit_setImageArrayOffset( wid, EQUIPMENT_SHIPS, 0. );
2130}
2131
2138static void equipment_unequipShip( unsigned int wid, const char* str )
2139{
2140 (void) str;
2141 Pilot *ship = eq_wgt.selected->p;
2142
2143 /*
2144 * Unequipping is disallowed under two conditions. Firstly, the ship may not
2145 * be unequipped when it has fighters deployed in space. Secondly, it cannot
2146 * unequip if it's carrying more cargo than the ship normally fits, i.e.
2147 * by equipping cargo pods.
2148 */
2149 if (pilot_cargoUsed(ship) > ship->ship->cap_cargo) {
2150 dialogue_alert( _("You can't unequip your ship when you have more cargo than it can hold without modifications!") );
2151 return;
2152 }
2153 if (dialogue_YesNo(_("Unequip Ship"), /* confirm */
2154 _("Are you sure you want to remove all equipment from your ship?"))==0)
2155 return;
2156 if (pilot_hasDeployed( ship )) {
2157 if (!dialogue_YesNo(_("Recall Fighters"), _("This action will recall your deployed fighters. Is that OK?")))
2158 return;
2159 /* Recall fighters. */
2160 escort_clearDeployed( ship );
2161 }
2162
2163 /* Remove all outfits. */
2164 for (int i=0; i<array_size(ship->outfits); i++) {
2165 int ret;
2166 PilotOutfitSlot *s = ship->outfits[i];
2167 const Outfit *o = s->outfit;
2168
2169 /* Skip null outfits. */
2170 if (o==NULL)
2171 continue;
2172
2173 /* Ignore locked slots. */
2174 if (s->sslot->locked)
2175 continue;
2176
2177 /* Remove ammo first. */
2178 pilot_rmAmmo( ship, s, pilot_maxAmmoO(ship, o) );
2179
2180 /* Remove rest. */
2181 ret = pilot_rmOutfitRaw( ship, s );
2182 if (ret==0)
2184 }
2185
2186 /* Recalculate stats. */
2187 pilot_calcStats( ship );
2188 pilot_healLanded( ship );
2189
2190 /* Regenerate list. */
2191 equipment_regenLists( wid, 1, 1 );
2192
2193 /* Regenerate outfits. */
2195
2196 /* Update weapon sets if needed. */
2197 if (ship->autoweap) {
2198 pilot_weaponAuto( ship );
2200 }
2201 pilot_weaponSafe( ship );
2202
2203 /* Notify GUI of modification. */
2204 gui_setShip();
2205}
2206
2210static void equipment_autoequipShip( unsigned int wid, const char* str )
2211{
2212 (void) str;
2213 (void) wid;
2214 Pilot *ship;
2215 int doswap;
2216 const char *curship;
2217 const char *file = AUTOEQUIP_PATH;
2218
2219 ship = eq_wgt.selected->p;
2220
2221 /* Swap ship if necessary. */
2222 doswap = (ship != player.p);
2223 if (doswap) {
2224 curship = player.p->name;
2225 player_swapShip( ship->name, 0 );
2226 }
2227
2228 /* Create the environment */
2229 if (autoequip_env == LUA_NOREF) {
2230 /* Read File. */
2231 size_t bufsize;
2232 char *buf = ndata_read( file, &bufsize );
2233 if (buf == NULL) {
2234 WARN( _("File '%s' not found!"), file );
2235 return;
2236 }
2237 /* New env. */
2238 autoequip_env = nlua_newEnv();
2239 nlua_loadStandard( autoequip_env );
2240 nlua_loadTk( autoequip_env );
2241 if (nlua_dobufenv(autoequip_env, buf, bufsize, file) != 0) {
2242 WARN(_("Failed to run '%s': %s"), file, lua_tostring(naevL,-1));
2243 free(buf);
2244 lua_pop(naevL,1);
2245 goto autoequip_cleanup;
2246 }
2247
2248 free(buf);
2249 }
2250
2251 /* Run func. */
2252 nlua_getenv( naevL, autoequip_env, "autoequip" );
2253 if (!lua_isfunction(naevL,-1)) {
2254 WARN(_("'%s' doesn't have valid required 'autoequip' function!"), file);
2255 lua_pop(naevL,1);
2256 goto autoequip_cleanup;
2257 }
2258 lua_pushpilot(naevL,player.p->id);
2259 if (nlua_pcall( autoequip_env, 1, 0 )) {
2260 WARN(_("'%s' failed to run required 'autoequip' function: %s"), file, lua_tostring(naevL,-1));
2261 lua_pop(naevL,1);
2262 goto autoequip_cleanup;
2263 }
2264
2265 hooks_run( "equip" ); /* Equipped. */
2266
2267 /* Clean up. */
2268autoequip_cleanup:
2269 if (doswap) {
2270 player_swapShip( curship, 0 );
2271 toolkit_setImageArray( equipment_wid, EQUIPMENT_SHIPS, ship->name );
2273 }
2274}
2275
2281static void equipment_sellShip( unsigned int wid, const char* str )
2282{
2283 (void) str;
2284 char buf[ECON_CRED_STRLEN], *name;
2285 credits_t price;
2286 Pilot *p;
2287 const Ship *s;
2288 HookParam hparam[3];
2289 const char *shipname = toolkit_getImageArray( wid, EQUIPMENT_SHIPS );
2290
2291 if (land_errDialogue( shipname, "sell" ))
2292 return;
2293
2294 /* Calculate price. */
2295 price = player_shipPrice(shipname);
2296 credits2str( buf, price, 2 );
2297
2298 /* Check if player really wants to sell. */
2299 if (!dialogue_YesNo( _("Sell Ship"),
2300 _("Are you sure you want to sell your ship %s for %s?"),
2301 shipname, buf))
2302 return;
2303
2304 /* Store ship type. */
2305 p = player_getShip( shipname );
2306 s = p->ship;
2307
2308 /* Sold. */
2309 name = strdup(shipname);
2310 player_modCredits( price );
2311 player_rmShip( shipname );
2312
2313 /* Destroy widget - must be before widget. */
2314 equipment_regenLists( wid, 0, 1 );
2315
2316 /* Display widget. */
2317 dialogue_msg( _("Ship Sold"),
2318 _("You have sold your ship %s for %s."), name, buf );
2319
2320 /* Run hook. */
2321 hparam[0].type = HOOK_PARAM_STRING;
2322 hparam[0].u.str = s->name;
2323 hparam[1].type = HOOK_PARAM_STRING;
2324 hparam[1].u.str = name;
2325 hparam[2].type = HOOK_PARAM_SENTINEL;
2326 hooks_runParam( "ship_sell", hparam );
2327 land_needsTakeoff( 1 );
2328 free(name);
2329}
2330
2337static void equipment_renameShip( unsigned int wid, const char *str )
2338{
2339 (void) str;
2340 const char *shipname = toolkit_getImageArray( wid, EQUIPMENT_SHIPS );
2341 Pilot *ship = player_getShip(shipname);
2342 char *newname = dialogue_input( _("Ship Name"), 1, 60,
2343 _("Please enter a new name for your %s:"), _(ship->ship->name) );
2344
2345 /* Player cancelled the dialogue. */
2346 if (newname == NULL)
2347 return;
2348
2349 /* Must not have same name. */
2350 if (player_hasShip(newname)) {
2351 dialogue_msg( _("Name Collision"),
2352 _("Please do not give the ship the same name as another of your ships."));
2353 free(newname);
2354 return;
2355 }
2356
2357 free (ship->name);
2358 ship->name = newname;
2359
2360 /* Destroy widget - must be before widget. */
2361 equipment_regenLists( wid, 0, 1 );
2362}
2363
2367static void equipment_shipMode( unsigned int wid, const char *str )
2368{
2369 ship_mode = 1-ship_mode;
2370 equipment_updateShips( wid, str );
2371}
2372
2376static int equipment_playerAddOutfit( const Outfit *o, int quantity )
2377{
2378 if (outfit_isProp(o,OUTFIT_PROP_UNIQUE) && (player_outfitOwned(o)>0))
2379 return 1;
2380 return player_addOutfit(o,quantity);
2381}
2382
2386static int equipment_playerRmOutfit( const Outfit *o, int quantity )
2387{
2388 if (outfit_isProp(o,OUTFIT_PROP_UNIQUE))
2389 return 1;
2390 return player_rmOutfit(o,quantity);
2391}
2392
2397{
2398 /* Free stored positions. */
2399 free(iar_data);
2400 iar_data = NULL;
2401 if (iar_outfits != NULL) {
2402 for (int i=0; i<OUTFIT_TABS; i++)
2403 free( iar_outfits[i] );
2404 free(iar_outfits);
2405 iar_outfits = NULL;
2406 }
2407
2409}
2410
2415{
2416 if (wgt==NULL)
2417 wgt = &eq_wgt;
2418 /* Safe defaults. */
2419 memset( wgt, 0, sizeof(CstSlotWidget) );
2420 wgt->slot = -1;
2421 wgt->mouseover = -1;
2422 wgt->weapons = -1;
2423}
Provides macros to work with dynamic arrays.
static ALWAYS_INLINE int array_size(const void *array)
Returns number of elements in the array.
Definition: array.h:168
void dialogue_alert(const char *fmt,...)
Displays an alert popup with only an ok button and a message.
Definition: dialogue.c:132
char * dialogue_input(const char *title, int min, int max, const char *fmt,...)
Creates a dialogue that allows the player to write a message.
Definition: dialogue.c:436
void dialogue_msg(const char *caption, const char *fmt,...)
Opens a dialogue window with an ok button and a message.
Definition: dialogue.c:218
int dialogue_YesNo(const char *caption, const char *fmt,...)
Runs a dialogue with both yes and no options.
Definition: dialogue.c:344
void equipment_slotDeselect(CstSlotWidget *wgt)
Deselects equipment stuff.
Definition: equipment.c:2414
static const char * eq_qSym(double cur, double base, int inv)
Gets the symbol for comparing a current value vs a ship base value.
Definition: equipment.c:1682
static void equipment_rightClickShips(unsigned int wid, const char *str)
Toggles deployed status.
Definition: equipment.c:2031
static double equipment_dir
Definition: equipment.c:62
static void equipment_renderColumn(double x, double y, double w, double h, PilotOutfitSlot *lst, const char *txt, int selected, Outfit *o, Pilot *p, CstSlotWidget *wgt)
Renders an outfit column.
Definition: equipment.c:444
static Outfit *** iar_outfits
Definition: equipment.c:67
static CstSlotWidget eq_wgt
Definition: equipment.c:61
static int ship_mode
Definition: equipment.c:65
static int equipment_playerAddOutfit(const Outfit *o, int quantity)
Wrapper to only add unique outfits.
Definition: equipment.c:2376
static void equipment_shipMode(unsigned int wid, const char *str)
Toggles the ship visualization mode.
Definition: equipment.c:2367
static void equipment_changeTab(unsigned int wid, const char *wgt, int old, int tab)
Ensures the tab's selected item is reflected in the ship slot list.
Definition: equipment.c:1999
static void equipment_sellShip(unsigned int wid, const char *str)
Player tries to sell a ship.
Definition: equipment.c:2281
static int equipment_playerRmOutfit(const Outfit *o, int quantity)
Wrapper to only remove unique outfits.
Definition: equipment.c:2386
static void equipment_getDim(unsigned int wid, int *w, int *h, int *sw, int *sh, int *ow, int *oh, int *ew, int *eh, int *cw, int *ch, int *bw, int *bh)
Gets the window dimensions.
Definition: equipment.c:255
static void equipment_outfitPopdownSelect(unsigned int wid, const char *str)
Definition: equipment.c:1944
void equipment_regenLists(unsigned int wid, int outfits, int ships)
Regenerates the equipment window lists.
Definition: equipment.c:1235
static void equipment_renameShip(unsigned int wid, const char *str)
Renames the selected ship.
Definition: equipment.c:2337
static void equipment_renderOverlayColumn(double x, double y, double h, PilotOutfitSlot *lst, int mover, CstSlotWidget *wgt)
Renders an outfit column.
Definition: equipment.c:697
void equipment_cleanup(void)
Cleans up after the equipment stuff.
Definition: equipment.c:2396
static void equipment_filterOutfits(unsigned int wid, const char *str)
Handles text input in the filter input widget.
Definition: equipment.c:1934
static int equipment_outfitMode
Definition: equipment.c:69
static void equipment_genLists(unsigned int wid)
Generates a new ship/outfit lists if needed.
Definition: equipment.c:1401
static void equipment_rightClickOutfits(unsigned int wid, const char *str)
Handles right-click on unequipped outfit.
Definition: equipment.c:121
void equipment_updateOutfits(unsigned int wid, const char *str)
Updates the player's outfit list.
Definition: equipment.c:1913
static iar_data_t * iar_data
Definition: equipment.c:66
static void equipment_transChangeShip(unsigned int wid, const char *str)
Changes ship.
Definition: equipment.c:2070
#define BUTTON_HEIGHT
Definition: equipment.c:56
static void equipment_genOutfitList(unsigned int wid)
Generates the outfit list.
Definition: equipment.c:1564
static void equipment_toggleFav(unsigned int wid, const char *wgt)
Handles toggling of the favourite checkbox.
Definition: equipment.c:1353
static void equipment_autoequipShip(unsigned int wid, const char *str)
Does the autoequip magic on the player's ship.
Definition: equipment.c:2210
void equipment_slotWidget(unsigned int wid, double x, double y, double w, double h, CstSlotWidget *data)
Creates the slot widget and initializes it.
Definition: equipment.c:427
void equipment_updateShips(unsigned int wid, const char *str)
Updates the player's ship window.
Definition: equipment.c:1698
static void equipment_renderShip(double bx, double by, double bw, double bh, void *data)
Renders the ship in the equipment window.
Definition: equipment.c:889
static void equipment_calculateSlots(const Pilot *p, double bw, double bh, double *w, double *h, int *n, int *m)
Calculates the size the slots need to be for a given window.
Definition: equipment.c:539
static int equipment_mouseSlots(unsigned int wid, SDL_Event *event, double x, double y, double w, double h, double rx, double ry, void *data)
Does mouse input for the custom equipment widget.
Definition: equipment.c:1080
static int equipment_mouseInColumn(double y, double h, int n, double my)
Handles a mouse press in column.
Definition: equipment.c:976
static void equipment_renderMisc(double bx, double by, double bw, double bh, void *data)
Renders the custom equipment widget.
Definition: equipment.c:623
int equipment_shipStats(char *buf, int max_len, const Pilot *s, int dpseps, int name)
Creates and allocates a string containing the ship stats.
Definition: equipment.c:1327
void equipment_addAmmo(void)
Adds all the ammo it can to the player.
Definition: equipment.c:1301
static int equipment_swapSlot(unsigned int wid, Pilot *p, PilotOutfitSlot *slot)
Swaps an equipment slot.
Definition: equipment.c:1155
static char eq_qCol(double cur, double base, int inv)
Gets the colour for comparing a current value vs a ship base value.
Definition: equipment.c:1670
static void equipment_changeShip(unsigned int wid)
Player attempts to change ship.
Definition: equipment.c:2083
static void equipment_unequipShip(unsigned int wid, const char *str)
Unequips the player's ship.
Definition: equipment.c:2138
static int equipment_mouseColumn(unsigned int wid, SDL_Event *event, double mx, double my, double y, double h, PilotOutfitSlot *os, Pilot *p, int selected, CstSlotWidget *wgt)
Handles a mouse press in a column.
Definition: equipment.c:1000
static unsigned int equipment_wid
Definition: equipment.c:64
void equipment_open(unsigned int wid)
Opens the player's equipment window.
Definition: equipment.c:298
static void equipment_renderSlots(double bx, double by, double bw, double bh, void *data)
Renders the equipment slots.
Definition: equipment.c:568
static void equipment_genShipList(unsigned int wid)
Generates the ship list.
Definition: equipment.c:1418
static unsigned int equipment_lastick
Definition: equipment.c:63
static void equipment_renderOverlaySlots(double bx, double by, double bw, double bh, void *data)
Renders the equipment overlay.
Definition: equipment.c:781
int escort_clearDeployed(Pilot *p)
Clears deployed escorts of a pilot.
Definition: escort.c:229
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
int gl_printWidthRaw(const glFont *ft_font, const char *text)
Gets the width that it would take to print some text.
Definition: font.c:960
glFont gl_defFont
Definition: font.c:153
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:787
int gl_printLinesRaw(const glFont *ft_font, const int width, const char *text)
Gets the number of lines of a non-formatted string.
Definition: font.c:1085
int gl_printMaxRaw(const glFont *ft_font, const int max, double x, double y, const glColour *c, double outlineR, const char *text)
Behaves like gl_printRaw but stops displaying text after a certain distance.
Definition: font.c:720
int gl_printMid(const glFont *ft_font, const int width, double x, double y, const glColour *c, const char *fmt,...)
Displays text centered in position and width.
Definition: font.c:834
void gui_setShip(void)
Player just upgraded their ship or modified it.
Definition: gui.c:1765
int hooks_runParam(const char *stack, const HookParam *param)
Runs all the hooks of stack.
Definition: hook.c:967
int hooks_run(const char *stack)
Runs all the hooks of stack.
Definition: hook.c:987
Handles the info menu.
void info_update(void)
Updates the info windows.
Definition: info.c:353
int land_errDialogue(const char *name, const char *type)
Generates error dialogues used by several landing tabs.
Definition: land.c:256
Spob * land_spob
Definition: land.c:82
void land_buttonTakeoff(unsigned int wid, const char *unused)
Wrapper for takeoff mission button.
Definition: land.c:925
void land_refuel(void)
Refuels the player's current ship, if possible.
Definition: land.c:807
int outfit_altText(char *buf, int n, const Outfit *o, const Pilot *plt)
Computes the alt text for an outfit.
Definition: land_outfits.c:655
ImageArrayCell * outfits_imageArrayCells(const Outfit **outfits, int *noutfits, const Pilot *p)
Generates image array cells corresponding to outfits.
Definition: land_outfits.c:687
void outfits_updateEquipmentOutfits(void)
Updates the outfitter and equipment outfit image arrays.
Definition: land_outfits.c:523
Header file with generic functions and naev-specifics.
#define MIN(x, y)
Definition: naev.h:40
#define CLAMP(a, b, x)
Definition: naev.h:41
#define MAX(x, y)
Definition: naev.h:39
#define PATH_MAX
Definition: naev.h:50
void * ndata_read(const char *path, size_t *filesize)
Reads a file from the ndata (will be NUL terminated).
Definition: ndata.c:154
int nlua_loadStandard(nlua_env env)
Loads the standard Naev Lua API.
Definition: nlua.c:760
LuaPilot * lua_pushpilot(lua_State *L, LuaPilot pilot)
Pushes a pilot on the stack.
Definition: nlua_pilot.c:495
int nlua_loadTk(nlua_env env)
Loads the Toolkit Lua library.
Definition: nlua_tk.c:90
int num2str(char dest[NUM2STRLEN], double n, int decimals)
Converts an electronic warfare value to a string.
Definition: nstring.c:199
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 * num2strU(double n, int decimals)
Unsafe version of num2str that uses an internal buffer. Every call overwrites the return value.
Definition: nstring.c:230
char * ntime_pretty(ntime_t t, int d)
Gets the time in a pretty human readable format.
Definition: ntime.c:173
void ntime_prettyBuf(char *str, int max, ntime_t t, int d)
Gets the time in a pretty human readable format filling a preset buffer.
Definition: ntime.c:188
void gl_renderShader(double x, double y, double w, double h, double r, const SimpleShader *shd, const glColour *c, int center)
Renders a simple shader.
void gl_renderScale(const glTexture *texture, double bx, double by, double bw, double bh, const glColour *c)
Blits a texture scaling it.
void gl_renderScaleSprite(const glTexture *sprite, double bx, double by, int sx, int sy, double bw, double bh, const glColour *c)
Blits a scaled sprite, position is in absolute screen coordinates.
void gl_renderCross(double x, double y, double r, const glColour *c)
Renders a cross at a given position.
glTexture * gl_dupTexture(const glTexture *texture)
Duplicates a texture.
Definition: opengl_tex.c:809
glTexture ** gl_copyTexArray(glTexture **tex, int *n)
Copy a texture array.
Definition: opengl_tex.c:892
glTexture ** gl_addTexArray(glTexture **tex, int *n, glTexture *t)
Adds an element to a texture array.
Definition: opengl_tex.c:934
glTexture * gl_newImage(const char *path, const unsigned int flags)
Loads an image as a texture.
Definition: opengl_tex.c:570
void gl_getSpriteFromDir(int *x, int *y, const glTexture *t, const double dir)
Sets x and y to be the appropriate sprite for glTexture using dir.
Definition: opengl_tex.c:857
int outfit_isLauncher(const Outfit *o)
Checks if outfit is a weapon launcher.
Definition: outfit.c:498
char outfit_slotTypeColourFont(const OutfitSlot *os)
Gets a font colour character that roughly matches an outfit slot type colour.
Definition: outfit.c:375
int outfit_fitsSlot(const Outfit *o, const OutfitSlot *s)
Checks to see if an outfit fits a slot.
Definition: outfit.c:981
int outfit_isFighterBay(const Outfit *o)
Checks if outfit is a fighter bay.
Definition: outfit.c:550
char outfit_slotSizeColourFont(const OutfitSlot *os)
Gets a font colour character that roughly matches an outfit slot size colour.
Definition: outfit.c:358
int outfit_amount(const Outfit *o)
Gets the amount an outfit can hold.
Definition: outfit.c:670
const char * slotName(const OutfitSlotType type)
Definition: outfit.c:287
const char * slotSize(const OutfitSlotSize o)
Gets the slot size as a string.
Definition: outfit.c:308
const glColour * outfit_slotSizeColour(const OutfitSlot *os)
Gets the slot size colour for an outfit slot.
Definition: outfit.c:341
ntime_t pilot_hyperspaceDelay(Pilot *p)
Calculates the hyperspace delay for a pilot.
Definition: pilot.c:2855
void pilot_dpseps(const Pilot *p, double *pdps, double *peps)
Calculates the dps and eps of a pilot.
Definition: pilot.c:3816
int pilot_cargoFree(const Pilot *p)
Gets the pilot's free cargo space.
Definition: pilot_cargo.c:51
int pilot_cargoUsed(const Pilot *p)
Gets how much cargo ship has on board.
Definition: pilot_cargo.c:189
double pilot_ewScanTime(const Pilot *p)
Gets the time it takes to scan a pilot.
Definition: pilot_ew.c:44
int pilot_getMount(const Pilot *p, const PilotOutfitSlot *w, vec2 *v)
Gets the mount position of a pilot.
Definition: pilot_outfit.c:148
int pilot_rmOutfit(Pilot *pilot, PilotOutfitSlot *s)
Removes an outfit from the pilot.
Definition: pilot_outfit.c:475
int pilot_hasDeployed(Pilot *p)
Checks to see if the pilot has deployed ships.
Definition: pilot_outfit.c:251
void pilot_healLanded(Pilot *pilot)
Cures the pilot as if he was landed.
int pilot_maxAmmoO(const Pilot *p, const Outfit *o)
Gets the maximum available ammo for a pilot for a specific outfit.
Definition: pilot_outfit.c:767
int pilot_slotIsToggleable(const PilotOutfitSlot *o)
Checks to see if a slot has an active outfit that can be toggleable.
void pilot_calcStats(Pilot *pilot)
Recalculates the pilot's stats based on his outfits.
Definition: pilot_outfit.c:877
void pilot_fillAmmo(Pilot *pilot)
Fills pilot's ammo completely.
Definition: pilot_outfit.c:786
int pilot_rmOutfitRaw(Pilot *pilot, PilotOutfitSlot *s)
Removes an outfit from the pilot without doing any checks.
Definition: pilot_outfit.c:424
int pilot_reportSpaceworthy(const Pilot *p, char *buf, int bufSize)
Pilot safety report - makes sure stats are safe.
Definition: pilot_outfit.c:541
int pilot_rmAmmo(Pilot *pilot, PilotOutfitSlot *s, int quantity)
Removes some ammo from the pilot stock.
Definition: pilot_outfit.c:693
const char * pilot_canEquip(const Pilot *p, const PilotOutfitSlot *s, const Outfit *o)
Checks to see if can equip/remove an outfit from a slot.
Definition: pilot_outfit.c:627
int pilot_addOutfitRaw(Pilot *pilot, const Outfit *outfit, PilotOutfitSlot *s)
Adds an outfit to the pilot, ignoring CPU or other limits.
Definition: pilot_outfit.c:273
int pilot_weapSetTypeCheck(Pilot *p, int id)
Checks the current weapon set type.
Definition: pilot_weapon.c:301
void pilot_weaponSafe(Pilot *p)
Sets the weapon set as safe.
void ws_copy(PilotWeaponSet dest[PILOT_WEAPON_SETS], const PilotWeaponSet src[PILOT_WEAPON_SETS])
Copies a weapon set over.
void pilot_weapSetAdd(Pilot *p, int id, PilotOutfitSlot *o, int level)
Adds an outfit to a weapon set.
Definition: pilot_weapon.c:431
int pilot_weapSetCheck(Pilot *p, int id, PilotOutfitSlot *o)
Checks to see if a slot is in a weapon set.
Definition: pilot_weapon.c:532
void pilot_weapSetRmSlot(Pilot *p, int id, OutfitSlotType type)
Removes slots by type from the weapon set.
Definition: pilot_weapon.c:397
void pilot_weapSetType(Pilot *p, int id, int type)
Changes the weapon sets mode.
Definition: pilot_weapon.c:314
void pilot_weaponAuto(Pilot *p)
Tries to automatically set and create the pilot's weapon set.
void pilot_weapSetRm(Pilot *p, int id, PilotOutfitSlot *o)
Removes a slot from a weapon set.
Definition: pilot_weapon.c:495
int player_nships(void)
Gets the amount of ships player has in storage.
Definition: player.c:2633
int player_rmOutfit(const Outfit *o, int quantity)
Remove an outfit from the player's outfit stack.
Definition: player.c:2859
void player_swapShip(const char *shipname, int move_cargo)
Swaps player's current ship with their ship named shipname.
Definition: player.c:501
int player_addOutfit(const Outfit *o, int quantity)
Adds an outfit to the player outfit stack.
Definition: player.c:2803
credits_t player_shipPrice(const char *shipname)
Calculates the price of one of the player's ships.
Definition: player.c:639
int player_numOutfits(void)
Gets the amount of different outfits in the player outfit stack.
Definition: player.c:2791
const PlayerShip_t * player_getShipStack(void)
Gets the array (array.h) of the player's ships.
Definition: player.c:2623
void player_rmShip(const char *shipname)
Removes one of the player's ships.
Definition: player.c:669
PlayerShip_t * player_getPlayerShip(const char *shipname)
Gets a specific ship.
Definition: player.c:2682
int player_getOutfitsFiltered(const Outfit **outfits, int(*filter)(const Outfit *o), const char *name)
Prepares two arrays for displaying in an image array.
Definition: player.c:2770
credits_t player_modCredits(credits_t amount)
Modifies the amount of credits the player has.
Definition: player.c:947
int player_hasShip(const char *shipname)
Sees if player has a ship of a name.
Definition: player.c:2644
Player_t player
Definition: player.c:73
void player_shipsSort(void)
Sorts the players ships.
Definition: player.c:2589
int player_outfitOwned(const Outfit *o)
Gets how many of the outfit the player owns.
Definition: player.c:2701
Pilot * player_getShip(const char *shipname)
Gets a specific ship.
Definition: player.c:2663
int pfleet_toggleDeploy(PlayerShip_t *ps, int deploy)
Toggles a player ship as deployed.
Definition: player_fleet.c:45
void pfleet_update(void)
Updates the used fleet capacity of the player.
Definition: player_fleet.c:24
static const double c[]
Definition: rng.c:264
const char * ship_classDisplay(const Ship *s)
Gets the ship's display class in human readable form.
Definition: ship.c:162
int ss_statsDesc(const ShipStats *s, char *buf, int len, int newline)
Writes the ship statistics description.
Definition: shipstats.c:744
const char * sp_description(unsigned int spid)
Gets the description of a slot property (in English).
Definition: slots.c:160
const char * sp_display(unsigned int spid)
Gets the display name of a slot property (in English).
Definition: slots.c:150
Outfit * outfit
Definition: equipment.h:15
double altx
Definition: equipment.h:18
PlayerShip_t * selected
Definition: equipment.h:14
double alty
Definition: equipment.h:19
The actual hook parameter.
Definition: hook.h:35
const char * str
Definition: hook.h:39
union HookParam::@4 u
HookParamType type
Definition: hook.h:36
OutfitSlotSize size
Definition: outfit.h:105
unsigned int spid
Definition: outfit.h:102
OutfitSlotType type
Definition: outfit.h:104
A ship outfit, depends radically on the type.
Definition: outfit.h:304
char * limit
Definition: outfit.h:317
OutfitSlot slot
Definition: outfit.h:311
char * name
Definition: outfit.h:305
int quantity
Definition: pilot.h:99
Stores an outfit the pilot has.
Definition: pilot.h:108
PilotOutfitAmmo ammo
Definition: pilot.h:135
ShipOutfitSlot * sslot
Definition: pilot.h:114
const Outfit * outfit
Definition: pilot.h:112
ShipStats lua_stats
Definition: pilot.h:140
The representation of an in-game pilot.
Definition: pilot.h:210
Solid * solid
Definition: pilot.h:220
ShipStats stats
Definition: pilot.h:286
unsigned int id
Definition: pilot.h:211
PilotWeaponSet weapon_sets[PILOT_WEAPON_SETS]
Definition: pilot.h:311
double thrust
Definition: pilot.h:235
double crew
Definition: pilot.h:231
double ew_stealth
Definition: pilot.h:266
PilotOutfitSlot * outfit_structure
Definition: pilot.h:293
double energy_regen
Definition: pilot.h:259
PilotOutfitSlot ** outfits
Definition: pilot.h:292
PilotOutfitSlot * outfit_utility
Definition: pilot.h:294
PilotOutfitSlot * outfit_intrinsic
Definition: pilot.h:296
double armour_max
Definition: pilot.h:247
double speed
Definition: pilot.h:237
const Ship * ship
Definition: pilot.h:219
double fuel_max
Definition: pilot.h:252
double ew_detection
Definition: pilot.h:264
int autoweap
Definition: pilot.h:313
double energy_max
Definition: pilot.h:258
char * name
Definition: pilot.h:212
double fuel_consumption
Definition: pilot.h:254
double shield_regen
Definition: pilot.h:250
double ew_evasion
Definition: pilot.h:265
double turn
Definition: pilot.h:240
PilotOutfitSlot * outfit_weapon
Definition: pilot.h:295
double shield_max
Definition: pilot.h:248
double dmg_absorb
Definition: pilot.h:251
double armour_regen
Definition: pilot.h:249
int big_icons
Definition: conf.h:126
Player ship.
Definition: player.h:73
time_t acquired_date
Definition: player.h:85
double time_played
Definition: player.h:83
double dmg_done_armour
Definition: player.h:87
double dmg_taken_armour
Definition: player.h:89
int deployed
Definition: player.h:80
double dmg_taken_shield
Definition: player.h:88
unsigned int landed_times
Definition: player.h:92
Pilot * p
Definition: player.h:74
unsigned int ships_destroyed[SHIP_CLASS_TOTAL]
Definition: player.h:90
char * acquired
Definition: player.h:84
unsigned int jumped_times
Definition: player.h:91
PilotWeaponSet weapon_sets[PILOT_WEAPON_SETS]
Definition: player.h:75
double dmg_done_shield
Definition: player.h:86
int favourite
Definition: player.h:77
Pilot * p
Definition: player.h:101
PlayerShip_t ps
Definition: player.h:102
int fleet_used
Definition: player.h:130
int fleet_capacity
Definition: player.h:131
int eq_outfitMode
Definition: player.h:126
int exclusive
Definition: ship.h:73
OutfitSlot slot
Definition: ship.h:71
int locked
Definition: ship.h:75
double time_mod
Definition: shipstats.h:308
Represents a space ship.
Definition: ship.h:94
double shield_regen
Definition: ship.h:129
double dt_default
Definition: ship.h:123
double cap_cargo
Definition: ship.h:122
char * name
Definition: ship.h:95
double thrust
Definition: ship.h:112
double energy_regen
Definition: ship.h:131
double armour
Definition: ship.h:126
double armour_regen
Definition: ship.h:127
int crew
Definition: ship.h:117
double dmg_absorb
Definition: ship.h:132
int points
Definition: ship.h:99
double speed
Definition: ship.h:114
double turn
Definition: ship.h:113
int rarity
Definition: ship.h:100
glTexture * gfx_store
Definition: ship.h:140
double energy
Definition: ship.h:130
glTexture ** gfx_overlays
Definition: ship.h:142
double shield
Definition: ship.h:128
double mass
Definition: ship.h:118
double mass
Definition: physics.h:18
int h
Definition: font.h:18
Abstraction for rendering sprite sheets.
Definition: opengl_tex.h:34
Represents a 2d vector.
Definition: vec2.h:32
void window_dimWidget(unsigned int wid, const char *name, int *w, int *h)
Gets the dimensions of a widget.
Definition: toolkit.c:416
void window_setFocus(unsigned int wid, const char *wgtname)
Sets the focused widget in a window.
Definition: toolkit.c:2460
void window_dimWindow(unsigned int wid, int *w, int *h)
Gets the dimensions of a window.
Definition: toolkit.c:371
int window_existsID(unsigned int wid)
Checks to see if a window with a certain ID exists.
Definition: toolkit.c:614
void toolkit_drawAltText(int bx, int by, const char *alt)
Draws an alt text.
Definition: toolkit.c:1426
void window_canFocusWidget(unsigned int wid, const char *name, int canfocus)
Allows or disallows focusing a widget.
Definition: toolkit.c:523
void toolkit_drawRect(int x, int y, int w, int h, const glColour *c, const glColour *lc)
Draws a rectangle.
Definition: toolkit.c:1340
void window_moveWidget(unsigned int wid, const char *name, int x, int y)
Moves a widget.
Definition: toolkit.c:467
void window_posWidget(unsigned int wid, const char *name, int *x, int *y)
Gets a widget's position.
Definition: toolkit.c:442
void window_destroyWidget(unsigned int wid, const char *wgtname)
Destroys a widget in a window.
Definition: toolkit.c:1162
int widget_isCovered(unsigned int wid, const char *name, int x, int y)
Checks to see if a widget is covered or not.
Definition: toolkit.c:568
void toolkit_drawOutlineThick(int x, int y, int w, int h, int b, int thick, const glColour *c, const glColour *lc)
Draws an outline.
Definition: toolkit.c:1213
int widget_exists(unsigned int wid, const char *wgtname)
Checks to see if a widget exists.
Definition: toolkit.c:1139
char * window_getFocus(unsigned int wid)
Gets the focused widget in a window (does strdup!!).
Definition: toolkit.c:2486