naev 0.12.5
shipstats.c
Go to the documentation of this file.
1/*
2 * See Licensing and Copyright notice in naev.h
3 */
10#include "naev.h"
12
13#include "shipstats.h"
14
15#include "log.h"
16#include "nstring.h"
17#include "physics.h"
18
29
36typedef struct ShipStatsLookup_ {
37 /* Explicitly set. */
38 ShipStatsType type;
39 const char *
41 const char *display;
42 const char *unit;
47
48 /* Self calculated. */
49 size_t offset;
51
52/* Flexible do everything macro. */
53#define ELEM( t, n, dsp, u, d, i ) \
54 { .type = t, \
55 .name = #n, \
56 .display = dsp, \
57 .unit = u, \
58 .data = d, \
59 .inverted = i, \
60 .offset = offsetof( ShipStats, n ) }
61/* Standard types. */
62#define D__ELEM( t, n, dsp ) \
63 ELEM( t, n, dsp, N_( "%" ), SS_DATA_TYPE_DOUBLE, 0 )
64#define DI_ELEM( t, n, dsp ) \
65 ELEM( t, n, dsp, N_( "%" ), SS_DATA_TYPE_DOUBLE, 1 )
66
67#define A__ELEM( t, n, dsp, u ) \
68 ELEM( t, n, dsp, u, SS_DATA_TYPE_DOUBLE_ABSOLUTE, 0 )
69#define AI_ELEM( t, n, dsp, u ) \
70 ELEM( t, n, dsp, u, SS_DATA_TYPE_DOUBLE_ABSOLUTE, 1 )
71
72#define P__ELEM( t, n, dsp ) \
73 ELEM( t, n, dsp, N_( "%" ), SS_DATA_TYPE_DOUBLE_ABSOLUTE_PERCENT, 0 )
74#define PI_ELEM( t, n, dsp ) \
75 ELEM( t, n, dsp, N_( "%" ), SS_DATA_TYPE_DOUBLE_ABSOLUTE_PERCENT, 1 )
76
77#define I__ELEM( t, n, dsp, u ) ELEM( t, n, dsp, u, SS_DATA_TYPE_INTEGER, 0 )
78#define II_ELEM( t, n, dsp ) ELEM( t, n, dsp, u, SS_DATA_TYPE_INTEGER, 1 )
79
80#define B__ELEM( t, n, dsp ) ELEM( t, n, dsp, NULL, SS_DATA_TYPE_BOOLEAN, 0 )
81#define BI_ELEM( t, n, dsp ) ELEM( t, n, dsp, NULL, SS_DATA_TYPE_BOOLEAN, 1 )
82
84#define N__ELEM( t ) \
85 { .type = t, \
86 .name = NULL, \
87 .display = NULL, \
88 .unit = NULL, \
89 .inverted = 0, \
90 .offset = 0 }
91
95static const ShipStatsLookup ss_lookup[] = {
96 /* Null element. */
97 N__ELEM( SS_TYPE_NIL ),
98
99 D__ELEM( SS_TYPE_D_SPEED_MOD, speed_mod, N_( "Speed" ) ),
100 D__ELEM( SS_TYPE_D_TURN_MOD, turn_mod, N_( "Turn" ) ),
101 D__ELEM( SS_TYPE_D_ACCEL_MOD, accel_mod, N_( "Accel" ) ),
102 D__ELEM( SS_TYPE_D_CARGO_MOD, cargo_mod, N_( "Cargo Space" ) ),
103 D__ELEM( SS_TYPE_D_FUEL_MOD, fuel_mod, N_( "Fuel Capacity" ) ),
104 DI_ELEM( SS_TYPE_D_FUEL_USAGE_MOD, fuel_usage_mod, N_( "Fuel Usage" ) ),
105 D__ELEM( SS_TYPE_D_ARMOUR_MOD, armour_mod, N_( "Armour Strength" ) ),
106 D__ELEM( SS_TYPE_D_ARMOUR_REGEN_MOD, armour_regen_mod,
107 N_( "Armour Regeneration" ) ),
108 D__ELEM( SS_TYPE_D_SHIELD_MOD, shield_mod, N_( "Shield Strength" ) ),
109 D__ELEM( SS_TYPE_D_SHIELD_REGEN_MOD, shield_regen_mod,
110 N_( "Shield Regeneration" ) ),
111 D__ELEM( SS_TYPE_D_ENERGY_MOD, energy_mod, N_( "Energy Capacity" ) ),
112 D__ELEM( SS_TYPE_D_ENERGY_REGEN_MOD, energy_regen_mod,
113 N_( "Energy Regeneration" ) ),
114 D__ELEM( SS_TYPE_D_CPU_MOD, cpu_mod, N_( "CPU Capacity" ) ),
115 DI_ELEM( SS_TYPE_D_COOLDOWN_MOD, cooldown_mod, N_( "Ability Cooldown" ) ),
116 DI_ELEM( SS_TYPE_D_SHIELDDOWN_MOD, shielddown_mod,
117 N_( "Shield Down Time" ) ),
118
119 DI_ELEM( SS_TYPE_D_JUMP_DELAY, jump_delay, N_( "Jump Time" ) ),
120 DI_ELEM( SS_TYPE_D_LAND_DELAY, land_delay, N_( "Landing Time" ) ),
121 DI_ELEM( SS_TYPE_D_CARGO_INERTIA, cargo_inertia, N_( "Cargo Inertia" ) ),
122
123 DI_ELEM( SS_TYPE_D_EW_HIDE, ew_hide, N_( "Detected Range" ) ),
124 DI_ELEM( SS_TYPE_D_EW_SIGNATURE, ew_signature, N_( "Signature Range" ) ),
125 DI_ELEM( SS_TYPE_D_EW_STEALTH, ew_stealth, N_( "Stealth Range" ) ),
126 D__ELEM( SS_TYPE_D_EW_DETECT, ew_detect, N_( "Detection" ) ),
127 D__ELEM( SS_TYPE_D_EW_TRACK, ew_track, N_( "Tracking" ) ),
128 D__ELEM( SS_TYPE_D_EW_JUMPDETECT, ew_jump_detect, N_( "Jump Detection" ) ),
129 DI_ELEM( SS_TYPE_D_EW_STEALTH_TIMER, ew_stealth_timer,
130 N_( "Stealth Discovered Rate" ) ),
131 DI_ELEM( SS_TYPE_D_EW_SCANNED_TIME, ew_scanned_time, N_( "Scanned Speed" ) ),
132
133 D__ELEM( SS_TYPE_D_WEAPON_RANGE, weapon_range, N_( "Weapon Range" ) ),
134 D__ELEM( SS_TYPE_D_WEAPON_DAMAGE, weapon_damage, N_( "Weapon Damage" ) ),
135 D__ELEM( SS_TYPE_D_WEAPON_FIRERATE, weapon_firerate,
136 N_( "Weapon Fire Rate" ) ),
137 DI_ELEM( SS_TYPE_D_WEAPON_ENERGY, weapon_energy,
138 N_( "Weapon Energy Usage" ) ),
139
140 D__ELEM( SS_TYPE_D_LAUNCH_RATE, launch_rate, N_( "Fire Rate (Launcher)" ) ),
141 D__ELEM( SS_TYPE_D_LAUNCH_RANGE, launch_range, N_( "Launch Range" ) ),
142 D__ELEM( SS_TYPE_D_LAUNCH_DAMAGE, launch_damage, N_( "Damage (Launcher)" ) ),
143 DI_ELEM( SS_TYPE_D_LAUNCH_ENERGY, launch_energy,
144 N_( "Energy Usage (Launcher)" ) ),
145 D__ELEM( SS_TYPE_D_AMMO_CAPACITY, ammo_capacity, N_( "Ammo Capacity" ) ),
146 DI_ELEM( SS_TYPE_D_LAUNCH_LOCKON, launch_lockon, N_( "Launch Lock-on" ) ),
147 DI_ELEM( SS_TYPE_D_LAUNCH_CALIBRATION, launch_calibration,
148 N_( "Launch Calibration" ) ),
149 D__ELEM( SS_TYPE_D_LAUNCH_RELOAD, launch_reload, N_( "Ammo Reload Rate" ) ),
150 D__ELEM( SS_TYPE_D_LAUNCH_ACCEL, launch_accel, N_( "Ammo Accel" ) ),
151 D__ELEM( SS_TYPE_D_LAUNCH_SPEED, launch_speed, N_( "Ammo Speed" ) ),
152 D__ELEM( SS_TYPE_D_LAUNCH_TURN, launch_turn, N_( "Ammo Turn" ) ),
153
154 D__ELEM( SS_TYPE_D_FBAY_DAMAGE, fbay_damage, N_( "Fighter Damage" ) ),
155 D__ELEM( SS_TYPE_D_FBAY_HEALTH, fbay_health, N_( "Fighter Health" ) ),
156 D__ELEM( SS_TYPE_D_FBAY_MOVEMENT, fbay_movement, N_( "Fighter Movement" ) ),
157 D__ELEM( SS_TYPE_D_FBAY_CAPACITY, fbay_capacity,
158 N_( "Fighter Bay Capacity" ) ),
159 D__ELEM( SS_TYPE_D_FBAY_RATE, fbay_rate, N_( "Fighter Bay Launch Rate" ) ),
160 D__ELEM( SS_TYPE_D_FBAY_RELOAD, fbay_reload, N_( "Fighter Reload Rate" ) ),
161
162 DI_ELEM( SS_TYPE_D_FORWARD_HEAT, fwd_heat, N_( "Heat (Cannon)" ) ),
163 D__ELEM( SS_TYPE_D_FORWARD_DAMAGE, fwd_damage, N_( "Damage (Cannon)" ) ),
164 D__ELEM( SS_TYPE_D_FORWARD_FIRERATE, fwd_firerate,
165 N_( "Fire Rate (Cannon)" ) ),
166 DI_ELEM( SS_TYPE_D_FORWARD_ENERGY, fwd_energy,
167 N_( "Energy Usage (Cannon)" ) ),
168 D__ELEM( SS_TYPE_D_FORWARD_DAMAGE_AS_DISABLE, fwd_dam_as_dis,
169 N_( "Damage as Disable (Cannon)" ) ),
170 D__ELEM( SS_TYPE_D_FORWARD_RANGE, fwd_range, N_( "Weapon Range (Cannon)" ) ),
171
172 DI_ELEM( SS_TYPE_D_TURRET_HEAT, tur_heat, N_( "Heat (Turret)" ) ),
173 D__ELEM( SS_TYPE_D_TURRET_DAMAGE, tur_damage, N_( "Damage (Turret)" ) ),
174 D__ELEM( SS_TYPE_D_TURRET_TRACKING, tur_tracking,
175 N_( "Tracking (Turret)" ) ),
176 D__ELEM( SS_TYPE_D_TURRET_FIRERATE, tur_firerate,
177 N_( "Fire Rate (Turret)" ) ),
178 DI_ELEM( SS_TYPE_D_TURRET_ENERGY, tur_energy,
179 N_( "Energy Usage (Turret)" ) ),
180 D__ELEM( SS_TYPE_D_TURRET_DAMAGE_AS_DISABLE, tur_dam_as_dis,
181 N_( "Damage as Disable (Turret)" ) ),
182 D__ELEM( SS_TYPE_D_TURRET_RANGE, tur_range, N_( "Weapon Range (Turret)" ) ),
183
184 D__ELEM( SS_TYPE_D_HEAT_DISSIPATION, heat_dissipation,
185 N_( "Heat Dissipation" ) ),
186 D__ELEM( SS_TYPE_D_STRESS_DISSIPATION, stress_dissipation,
187 N_( "Stress Dissipation" ) ),
188 D__ELEM( SS_TYPE_D_CREW, crew_mod, N_( "Crew" ) ),
189 DI_ELEM( SS_TYPE_D_MASS, mass_mod, N_( "Ship Mass" ) ),
190 D__ELEM( SS_TYPE_D_ENGINE_LIMIT_REL, engine_limit_rel,
191 N_( "Engine Mass Limit" ) ),
192 D__ELEM( SS_TYPE_D_LOOT_MOD, loot_mod, N_( "Boarding Bonus" ) ),
193 DI_ELEM( SS_TYPE_D_TIME_MOD, time_mod, N_( "Time Constant" ) ),
194 D__ELEM( SS_TYPE_D_TIME_SPEEDUP, time_speedup, N_( "Action Speed" ) ),
195 DI_ELEM( SS_TYPE_D_COOLDOWN_TIME, cooldown_time,
196 N_( "Ship Cooldown Time" ) ),
197 D__ELEM( SS_TYPE_D_JUMP_DISTANCE, jump_distance, N_( "Jump Distance" ) ),
198 DI_ELEM( SS_TYPE_D_JUMP_WARMUP, jump_warmup, N_( "Jump Warm-up" ) ),
199 D__ELEM( SS_TYPE_D_MINING_BONUS, mining_bonus, N_( "Mining Bonus" ) ),
200
201 A__ELEM( SS_TYPE_A_ACCEL, accel, N_( "Accel" ), _UNIT_ACCEL ),
202 A__ELEM( SS_TYPE_A_TURN, turn, N_( "Turn Rate" ), _UNIT_ROTATION ),
203 A__ELEM( SS_TYPE_A_SPEED, speed, N_( "Maximum Speed" ), _UNIT_SPEED ),
204 A__ELEM( SS_TYPE_A_ENERGY, energy, N_( "Energy Capacity" ), _UNIT_ENERGY ),
205 A__ELEM( SS_TYPE_A_ENERGY_REGEN, energy_regen, N_( "Energy Regeneration" ),
206 _UNIT_POWER ),
207 AI_ELEM( SS_TYPE_A_ENERGY_REGEN_MALUS, energy_regen_malus,
208 N_( "Energy Usage" ), _UNIT_POWER ),
209 A__ELEM( SS_TYPE_A_SHIELD, shield, N_( "Shield Capacity" ), _UNIT_ENERGY ),
210 A__ELEM( SS_TYPE_A_SHIELD_REGEN, shield_regen, N_( "Shield Regeneration" ),
211 _UNIT_POWER ),
212 AI_ELEM( SS_TYPE_A_SHIELD_REGEN_MALUS, shield_regen_malus,
213 N_( "Shield Usage" ), _UNIT_POWER ),
214 A__ELEM( SS_TYPE_A_ARMOUR, armour, N_( "Armour" ), _UNIT_ENERGY ),
215 A__ELEM( SS_TYPE_A_ARMOUR_REGEN, armour_regen, N_( "Armour Regeneration" ),
216 _UNIT_POWER ),
217 AI_ELEM( SS_TYPE_A_ARMOUR_REGEN_MALUS, armour_regen_malus,
218 N_( "Armour Damage" ), _UNIT_POWER ),
219 A__ELEM( SS_TYPE_A_DAMAGE, damage, N_( "Damage" ), _UNIT_POWER ),
220 A__ELEM( SS_TYPE_A_DISABLE, disable, N_( "Disable" ), _UNIT_POWER ),
221
222 A__ELEM( SS_TYPE_A_CPU_MAX, cpu_max, N_( "CPU Capacity" ), _UNIT_CPU ),
223 A__ELEM( SS_TYPE_A_ENGINE_LIMIT, engine_limit, N_( "Engine Mass Limit" ),
224 _UNIT_MASS ),
225 A__ELEM( SS_TYPE_A_FUEL_REGEN, fuel_regen, N_( "Fuel Regeneration" ),
226 _UNIT_PER_TIME ),
227 A__ELEM( SS_TYPE_A_ASTEROID_SCAN, asteroid_scan,
228 N_( "Asteroid Scanner Range" ), _UNIT_DISTANCE ),
229 A__ELEM( SS_TYPE_A_NEBULA_VISIBILITY, nebu_visibility,
230 N_( "Nebula Visibility" ), _UNIT_DISTANCE ),
231
232 P__ELEM( SS_TYPE_P_ABSORB, absorb, N_( "Damage Absorption" ) ),
233
234 P__ELEM( SS_TYPE_P_NEBULA_ABSORB, nebu_absorb, N_( "Nebula Resistance" ) ),
235 P__ELEM( SS_TYPE_P_JAMMING_CHANCE, jam_chance,
236 N_( "Missile jamming chance" ) ),
237
238 I__ELEM( SS_TYPE_I_FUEL, fuel, N_( "Fuel" ), _UNIT_UNIT ),
239 I__ELEM( SS_TYPE_I_CARGO, cargo, N_( "Cargo" ), _UNIT_MASS ),
240 I__ELEM( SS_TYPE_I_CREW, crew, N_( "Crew" ), _UNIT_UNIT ),
241
242 B__ELEM( SS_TYPE_B_HIDDEN_JUMP_DETECT, misc_hidden_jump_detect,
243 N_( "Hidden Jump Detection" ) ),
244 B__ELEM( SS_TYPE_B_INSTANT_JUMP, misc_instant_jump, N_( "Instant Jump" ) ),
245 B__ELEM( SS_TYPE_B_REVERSE_THRUST, misc_reverse_thrust,
246 N_( "Reverse Thrusters" ) ),
247
248 /* Sentinel. */
249 N__ELEM( SS_TYPE_SENTINEL ) };
250
251/*
252 * Prototypes.
253 */
254static const char *ss_printD_colour( double d, const ShipStatsLookup *sl );
255static const char *ss_printI_colour( int i, const ShipStatsLookup *sl );
256static int ss_printD( char *buf, int len, int newline, double d,
257 const ShipStatsLookup *sl );
258static int ss_printA( char *buf, int len, int newline, double d,
259 const ShipStatsLookup *sl );
260static int ss_printI( char *buf, int len, int newline, int i,
261 const ShipStatsLookup *sl );
262static int ss_printB( char *buf, int len, int newline, int b,
263 const ShipStatsLookup *sl );
264static double ss_statsGetInternal( const ShipStats *s, ShipStatsType type,
265 int raw );
266static int ss_statsGetLuaInternal( lua_State *L, const ShipStats *s,
267 ShipStatsType type, int internal );
268static void ss_adjustDoubleStat( double *statptr, double adjustment,
269 int inverted );
270
271ShipStatList *ss_statsSetList( ShipStatList *head, ShipStatsType type,
272 double value, int overwrite, int raw )
273{
274 const ShipStatsLookup *sl;
275 ShipStatList *ll = NULL;
276 ShipStatList *newhead = head;
277 int init = overwrite;
278 double v;
279
280 if ( type == SS_TYPE_NIL )
281 return NULL;
282 sl = &ss_lookup[type];
283
284 /* See if there is an element to modify or overwrite. */
285 if ( head != NULL ) {
286 for ( ShipStatList *l = head; l != NULL; l = l->next ) {
287 if ( type == l->type ) {
288 ll = l;
289 break;
290 }
291 }
292 }
293
294 /* Allocate. */
295 if ( ll == NULL ) {
296 newhead = ll = malloc( sizeof( ShipStatList ) );
297 ll->next = head;
298 ll->target = 0;
299 ll->type = type;
300 init = 1; /* Force initialization. */
301 }
302
303 if ( init ) {
304 switch ( sl->data ) {
306 ll->d.d = 1.;
307 break;
310 ll->d.d = 0.;
311 break;
314 ll->d.i = 0;
315 break;
316 }
317 }
318
319 /* Set the data. */
320 switch ( sl->data ) {
322 v = ( raw ) ? value : value / 100.;
323 ll->d.d *= v;
324 break;
325
327 v = ( raw ) ? value : value / 100.;
328 ll->d.d += v;
329 break;
330
332 ll->d.d += value;
333 break;
334
336 ll->d.i |= ( fabs( value ) > DOUBLE_TOL );
337 break;
338
340 ll->d.i += round( value );
341 break;
342 }
343
344 return newhead;
345}
346
353ShipStatList *ss_listFromXML( xmlNodePtr node )
354{
355 const ShipStatsLookup *sl;
356 ShipStatList *ll;
357 ShipStatsType type;
358
359 /* Try to get type. */
360 type = ss_typeFromName( (char *)node->name );
361 if ( type == SS_TYPE_NIL )
362 return NULL;
363
364 /* Allocate. */
365 ll = malloc( sizeof( ShipStatList ) );
366 ll->next = NULL;
367 ll->target = 0;
368 ll->type = type;
369
370 /* Set the data. */
371 sl = &ss_lookup[type];
372 switch ( sl->data ) {
375 ll->d.d = xml_getFloat( node ) / 100.;
376 break;
377
379 ll->d.d = xml_getFloat( node );
380 break;
381
383 ll->d.i = !!xml_getInt( node );
384 break;
385
387 ll->d.i = xml_getInt( node );
388 break;
389 }
390
391 /* Sort them. */
392 ss_sort( &ll );
393
394 return ll;
395}
396
404int ss_listToXML( xmlTextWriterPtr writer, const ShipStatList *ll )
405{
406 for ( const ShipStatList *l = ll; l != NULL; l = l->next ) {
407 const ShipStatsLookup *sl = &ss_lookup[l->type];
408 switch ( sl->data ) {
411 xmlw_elem( writer, sl->name, "%f", l->d.d * 100 );
412 break;
413
415 xmlw_elem( writer, sl->name, "%f", l->d.d );
416 break;
417
420 xmlw_elem( writer, sl->name, "%d", l->d.i );
421 break;
422 }
423 }
424 return 0;
425}
426
427static int shipstat_sort( const void *a, const void *b )
428{
429 const ShipStatList **la = (const ShipStatList **)a;
430 const ShipStatList **lb = (const ShipStatList **)b;
431 const ShipStatsLookup *sla = &ss_lookup[( *la )->type];
432 const ShipStatsLookup *slb = &ss_lookup[( *lb )->type];
433 return strcmp( sla->name, slb->name );
434}
435
443{
444 int n, i;
445 ShipStatList **arr;
446
447 /* Nothing to do. */
448 if ( *ll == NULL )
449 return 0;
450
451 n = 0;
452 for ( ShipStatList *l = *ll; l != NULL; l = l->next )
453 n++;
454
455 arr = malloc( sizeof( ShipStatList * ) * n );
456 i = 0;
457 for ( ShipStatList *l = *ll; l != NULL; l = l->next ) {
458 arr[i] = l;
459 i++;
460 }
461 qsort( arr, n, sizeof( ShipStatList * ), shipstat_sort );
462
463 *ll = arr[0];
464 for ( i = 1; i < n; i++ )
465 arr[i - 1]->next = arr[i];
466 arr[n - 1]->next = NULL;
467 free( arr );
468 return 0;
469}
470
474int ss_check( void )
475{
476 for ( ShipStatsType i = 0; i <= SS_TYPE_SENTINEL; i++ ) {
477 if ( ss_lookup[i].type != i ) {
478 WARN( _( "ss_lookup: %s should have id %d but has %d" ),
479 ss_lookup[i].name, i, ss_lookup[i].type );
480 return -1;
481 }
482 }
483
484 return 0;
485}
486
491{
492 char *ptr;
493
494 /* Clear the memory. */
495 memset( stats, 0, sizeof( ShipStats ) );
496
497 ptr = (char *)stats;
498 for ( int i = 0; i < SS_TYPE_SENTINEL; i++ ) {
499 const ShipStatsLookup *sl = &ss_lookup[i];
500
501 /* Only want valid names. */
502 if ( sl->name == NULL )
503 continue;
504
505 /* Handle doubles. */
506 switch ( sl->data ) {
507 case SS_DATA_TYPE_DOUBLE: {
508 double *dbl;
509 const char *fieldptr = &ptr[sl->offset];
510 memcpy( &dbl, &fieldptr, sizeof( double * ) );
511 *dbl = 1.0;
512 break;
513 }
514
515 /* No need to set, memset does the work. */
520 break;
521 }
522 }
523
524 return 0;
525}
526
533int ss_statsMerge( ShipStats *dest, const ShipStats *src )
534{
535 int *destint;
536 const int *srcint;
537 double *destdbl;
538 const double *srcdbl;
539 char *destptr;
540 const char *srcptr;
541
542 destptr = (char *)dest;
543 srcptr = (const char *)src;
544 for ( int i = 0; i < SS_TYPE_SENTINEL; i++ ) {
545 const ShipStatsLookup *sl = &ss_lookup[i];
546
547 /* Only want valid names. */
548 if ( sl->name == NULL )
549 continue;
550
551 switch ( sl->data ) {
553 destdbl = (double *)(void *)&destptr[sl->offset];
554 srcdbl = (const double *)(const void *)&srcptr[sl->offset];
555 *destdbl = ( *destdbl ) * ( *srcdbl );
556 break;
557
560 destdbl = (double *)(void *)&destptr[sl->offset];
561 srcdbl = (const double *)(const void *)&srcptr[sl->offset];
562 *destdbl = ( *destdbl ) + ( *srcdbl );
563 break;
564
566 destint = (int *)&destptr[sl->offset];
567 srcint = (const int *)&srcptr[sl->offset];
568 *destint = ( *destint ) + ( *srcint );
569 break;
570
572 destint = (int *)&destptr[sl->offset];
573 srcint = (const int *)&srcptr[sl->offset];
574 *destint = !!( ( *destint ) + ( *srcint ) );
575 break;
576 }
577 }
578
579 return 0;
580}
581
590{
591 return ss_statsMergeSingleScale( stats, list, 1 );
592}
593
597static void ss_adjustDoubleStat( double *statptr, double adjustment,
598 int inverted )
599{
600 double currstat = *statptr;
601 /*
602 * Normal stats are additive, as having them multiplicative resulted in
603 * rediculous positive values for stacked builds Inverted stats remain
604 * multiplicative, for the same reason as above, except in this case we want
605 * to avoid excessively low stats due to stacking, and making the inverted
606 * stats multiplicative achieves this.
607 */
608 *statptr = ( inverted ) ? ( currstat * ( 1. + adjustment ) )
609 : ( currstat + adjustment );
610}
611
621 double scale )
622{
623 char *ptr;
624 char *fieldptr;
625 double *dbl;
626 int *i;
627 const ShipStatsLookup *sl = &ss_lookup[list->type];
628
629 ptr = (char *)stats;
630 switch ( sl->data ) {
632 fieldptr = &ptr[sl->offset];
633 memcpy( &dbl, &fieldptr, sizeof( double * ) );
634 ss_adjustDoubleStat( dbl, list->d.d * scale, sl->inverted );
635 break;
638 fieldptr = &ptr[sl->offset];
639 memcpy( &dbl, &fieldptr, sizeof( double * ) );
640 *dbl += list->d.d * scale;
641 break;
642
644 fieldptr = &ptr[sl->offset];
645 memcpy( &i, &fieldptr, sizeof( int * ) );
646 *i += list->d.i * scale;
647 break;
648
650 fieldptr = &ptr[sl->offset];
651 memcpy( &i, &fieldptr, sizeof( int * ) );
652 *i = 1; /* Can only set to true. */
653 break;
654 }
655
656 return 0;
657}
658
667{
668 if ( list == NULL )
669 return 0;
670 int ret = 0;
671 for ( const ShipStatList *ll = list; ll != NULL; ll = ll->next )
672 ret |= ss_statsMergeSingle( stats, ll );
673 return ret;
674}
675
685 double scale )
686{
687 if ( list == NULL )
688 return 0;
689 int ret = 0;
690 for ( const ShipStatList *ll = list; ll != NULL; ll = ll->next )
691 ret |= ss_statsMergeSingleScale( stats, ll, scale );
692 return ret;
693}
694
703const char *ss_nameFromType( ShipStatsType type )
704{
705 return ss_lookup[type].name;
706}
707
714size_t ss_offsetFromType( ShipStatsType type )
715{
716 return ss_lookup[type].offset;
717}
718
725ShipStatsType ss_typeFromName( const char *name )
726{
727 for ( int i = 0; i < SS_TYPE_SENTINEL; i++ )
728 if ( ( ss_lookup[i].name != NULL ) &&
729 ( strcmp( name, ss_lookup[i].name ) == 0 ) )
730 return ss_lookup[i].type;
731
732 WARN( _( "ss_typeFromName: No ship stat matching '%s'" ), name );
733 return SS_TYPE_NIL;
734}
735
739static const char *ss_printD_colour( double d, const ShipStatsLookup *sl )
740{
741 if ( sl->inverted )
742 return ( d < 0. ) ? "g" : "r";
743 return ( d > 0. ) ? "g" : "r";
744}
745
749static const char *ss_printI_colour( int i, const ShipStatsLookup *sl )
750{
751 if ( sl->inverted )
752 return ( i < 0 ) ? "g" : "r";
753 return ( i > 0 ) ? "g" : "r";
754}
755
759static int ss_printD( char *buf, int len, int newline, double d,
760 const ShipStatsLookup *sl )
761{
762 if ( FABS( d ) < DOUBLE_TOL )
763 return 0;
764
765 return scnprintf( buf, len, p_( "shipstats_double", "%s#%s%s: %+g %s#0" ),
766 ( newline ) ? "\n" : "", ss_printD_colour( d, sl ),
767 _( sl->display ), d * 100., _( sl->unit ) );
768}
769
773static int ss_printA( char *buf, int len, int newline, double d,
774 const ShipStatsLookup *sl )
775{
776 if ( FABS( d ) < DOUBLE_TOL )
777 return 0;
778 return scnprintf(
779 buf, len, p_( "shipstats_absolute", "%s#%s%s: %+g %s#0" ),
780 ( newline ) ? "\n" : "", ss_printD_colour( d, sl ), _( sl->display ),
781 d, /* TODO probably use num2strU here, but we want the sign enforced. */
782 _( sl->unit ) );
783}
784
788static int ss_printI( char *buf, int len, int newline, int i,
789 const ShipStatsLookup *sl )
790{
791 if ( i == 0 )
792 return 0;
793 return scnprintf( buf, len, p_( "shipstats_integer", "%s#%s%s: %+d %s#0" ),
794 ( newline ) ? "\n" : "", ss_printI_colour( i, sl ),
795 _( sl->display ), i, _( sl->unit ) );
796}
797
801static int ss_printB( char *buf, int len, int newline, int b,
802 const ShipStatsLookup *sl )
803{
804 if ( !b )
805 return 0;
806 return scnprintf( buf, len, p_( "shipstats_boolean", "%s#%s%s#0" ),
807 ( newline ) ? "\n" : "", ss_printI_colour( b, sl ),
808 _( sl->display ) );
809}
810
820int ss_statsListDesc( const ShipStatList *ll, char *buf, int len, int newline )
821{
822 int i = 0;
823 int newl = newline;
824 for ( ; ll != NULL; ll = ll->next ) {
825 const ShipStatsLookup *sl;
826 int left = len - i;
827 if ( left < 0 )
828 break;
829 sl = &ss_lookup[ll->type];
830
831 switch ( sl->data ) {
834 i += ss_printD( &buf[i], left, newl, ll->d.d, sl );
835 break;
836
838 i += ss_printA( &buf[i], left, newl, ll->d.d, sl );
839 break;
840
842 i += ss_printI( &buf[i], left, newl, ll->d.i, sl );
843 break;
844
846 i += ss_printB( &buf[i], left, newl, ll->d.i, sl );
847 break;
848 }
849
850 newl = 1;
851 }
852 return i;
853}
854
864int ss_statsDesc( const ShipStats *s, char *buf, int len, int newline )
865{
866 int l, left;
867 char *ptr;
868 char *fieldptr;
869 double *dbl;
870 int *num;
871
872 if ( len > 0 )
873 buf[0] = '\0';
874 l = 0;
875 ptr = (char *)s;
876 for ( int i = 0; i < SS_TYPE_SENTINEL; i++ ) {
877 const ShipStatsLookup *sl = &ss_lookup[i];
878
879 /* Only want valid names. */
880 if ( sl->name == NULL )
881 continue;
882
883 /* Calculate offset left. */
884 left = len - l;
885 if ( left < 0 )
886 break;
887
888 switch ( sl->data ) {
890 fieldptr = &ptr[sl->offset];
891 memcpy( &dbl, &fieldptr, sizeof( double * ) );
892 l += ss_printD( &buf[l], left, ( newline || ( l != 0 ) ),
893 ( ( *dbl ) - 1. ), sl );
894 break;
895
897 fieldptr = &ptr[sl->offset];
898 memcpy( &dbl, &fieldptr, sizeof( double * ) );
899 l +=
900 ss_printD( &buf[l], left, ( newline || ( l != 0 ) ), ( *dbl ), sl );
901 break;
902
904 fieldptr = &ptr[sl->offset];
905 memcpy( &dbl, &fieldptr, sizeof( double * ) );
906 l +=
907 ss_printA( &buf[l], left, ( newline || ( l != 0 ) ), ( *dbl ), sl );
908 break;
909
911 fieldptr = &ptr[sl->offset];
912 memcpy( &num, &fieldptr, sizeof( int * ) );
913 l +=
914 ss_printI( &buf[l], left, ( newline || ( l != 0 ) ), ( *num ), sl );
915 break;
916
918 fieldptr = &ptr[sl->offset];
919 memcpy( &num, &fieldptr, sizeof( int * ) );
920 l +=
921 ss_printB( &buf[l], left, ( newline || ( l != 0 ) ), ( *num ), sl );
922 break;
923 }
924 }
925
926 return l;
927}
928
935{
936 while ( ll != NULL ) {
937 ShipStatList *tmp = ll;
938 ll = ll->next;
939 free( tmp );
940 }
941}
942
946int ss_statsSet( ShipStats *s, const char *name, double value, int overwrite )
947{
948 const ShipStatsLookup *sl;
949 ShipStatsType type;
950 char *ptr;
951 double *destdbl;
952 int *destint;
953 double v;
954
955 type = ss_typeFromName( name );
956 if ( type == SS_TYPE_NIL ) {
957 WARN( _( "Unknown ship stat type '%s'!" ), name );
958 return -1;
959 }
960
961 sl = &ss_lookup[type];
962 ptr = (char *)s;
963 switch ( sl->data ) {
965 destdbl = (double *)(void *)&ptr[sl->offset];
966 v = value / 100.;
967 if ( overwrite )
968 *destdbl = 1.0;
969 ss_adjustDoubleStat( destdbl, v, sl->inverted );
970 break;
971
973 destdbl = (double *)(void *)&ptr[sl->offset];
974 if ( overwrite )
975 *destdbl = value / 100.;
976 else
977 *destdbl += value / 100.;
978 break;
979
981 destdbl = (double *)(void *)&ptr[sl->offset];
982 if ( overwrite )
983 *destdbl = value;
984 else
985 *destdbl += value;
986 break;
987
989 destint = (int *)&ptr[sl->offset];
990 if ( overwrite )
991 *destint = ( fabs( value ) > DOUBLE_TOL );
992 else
993 *destint |= ( fabs( value ) > DOUBLE_TOL );
994 break;
995
997 destint = (int *)&ptr[sl->offset];
998 if ( overwrite )
999 *destint = round( value );
1000 else
1001 *destint += round( value );
1002 break;
1003 }
1004
1005 return 0;
1006}
1007
1008static double ss_statsGetInternal( const ShipStats *s, ShipStatsType type,
1009 int raw )
1010{
1011 const ShipStatsLookup *sl;
1012 const char *ptr;
1013 const double *destdbl;
1014 const int *destint;
1015 double v;
1016
1017 sl = &ss_lookup[type];
1018 ptr = (const char *)s;
1019 switch ( sl->data ) {
1021 destdbl = (const double *)(const void *)&ptr[sl->offset];
1022 v = ( *destdbl ) - 1.0;
1023 if ( raw )
1024 return v;
1025 return 100. * v;
1026
1028 destdbl = (const double *)(const void *)&ptr[sl->offset];
1029 if ( raw )
1030 return *destdbl;
1031 return 100. * ( *destdbl );
1032
1034 destdbl = (const double *)(const void *)&ptr[sl->offset];
1035 return *destdbl;
1036
1039 destint = (const int *)&ptr[sl->offset];
1040 return *destint;
1041 }
1042 return 0.;
1043}
1044
1045static int ss_statsGetLuaInternal( lua_State *L, const ShipStats *s,
1046 ShipStatsType type, int internal )
1047{
1048 const ShipStatsLookup *sl;
1049 const char *ptr;
1050 const double *destdbl;
1051 const int *destint;
1052
1053 sl = &ss_lookup[type];
1054 ptr = (const char *)s;
1055 switch ( sl->data ) {
1057 destdbl = (const double *)(const void *)&ptr[sl->offset];
1058 if ( internal )
1059 lua_pushnumber( L, *destdbl );
1060 else
1061 lua_pushnumber( L, 100. * ( ( *destdbl ) - 1.0 ) );
1062 return 0;
1063
1065 destdbl = (const double *)(const void *)&ptr[sl->offset];
1066 if ( internal )
1067 lua_pushnumber( L, *destdbl );
1068 else
1069 lua_pushnumber( L, 100. * ( *destdbl ) );
1070 return 0;
1071
1073 destdbl = (const double *)(const void *)&ptr[sl->offset];
1074 lua_pushnumber( L, *destdbl );
1075 return 0;
1076
1078 destint = (const int *)&ptr[sl->offset];
1079 lua_pushboolean( L, *destint );
1080 return 0;
1081
1083 destint = (const int *)&ptr[sl->offset];
1084 lua_pushinteger( L, *destint );
1085 return 0;
1086 }
1087 lua_pushnil( L );
1088 return -1;
1089}
1090
1094double ss_statsGet( const ShipStats *s, const char *name )
1095{
1096 ShipStatsType type = ss_typeFromName( name );
1097 if ( type == SS_TYPE_NIL ) {
1098 WARN( _( "Unknown ship stat type '%s'!" ), name );
1099 return 0;
1100 }
1101
1102 return ss_statsGetInternal( s, type, 0 );
1103}
1104
1108double ss_statsGetRaw( const ShipStats *s, ShipStatsType type )
1109{
1110 return ss_statsGetInternal( s, type, 1 );
1111}
1112
1116int ss_statsGetLua( lua_State *L, const ShipStats *s, const char *name,
1117 int internal )
1118{
1119 ShipStatsType type;
1120
1121 if ( name == NULL )
1122 return ss_statsGetLuaTable( L, s, internal );
1123
1124 type = ss_typeFromName( name );
1125 if ( type == SS_TYPE_NIL ) {
1126 WARN( _( "Unknown ship stat type '%s'!" ), name );
1127 return -1;
1128 }
1129
1130 return ss_statsGetLuaInternal( L, s, type, internal );
1131}
1132
1136int ss_statsGetLuaTable( lua_State *L, const ShipStats *s, int internal )
1137{
1138 lua_newtable( L );
1139 for ( int i = 0; i < SS_TYPE_SENTINEL; i++ ) {
1140 const ShipStatsLookup *sl = &ss_lookup[i];
1141
1142 /* Only want valid names. */
1143 if ( sl->name == NULL )
1144 continue;
1145
1146 /* Push name and get value. */
1147 lua_pushstring( L, sl->name );
1148 ss_statsGetLuaInternal( L, s, i, internal );
1149 lua_rawset( L, -3 );
1150 }
1151 return 0;
1152}
1153
1157int ss_statsGetLuaTableList( lua_State *L, const ShipStatList *list,
1158 int internal )
1159{
1160 lua_newtable( L );
1161 if ( list == NULL )
1162 return 0;
1163 for ( const ShipStatList *ll = list; ll != NULL; ll = ll->next ) {
1164 const ShipStatsLookup *sl = &ss_lookup[ll->type];
1165
1166 /* Push name and get value. */
1167 lua_pushstring( L, ss_nameFromType( ll->type ) );
1168 switch ( sl->data ) {
1170 lua_pushnumber( L, ( internal ) ? ll->d.d : ( ll->d.d - 1. ) * 100. );
1171 break;
1172
1174 lua_pushnumber( L, ( internal ) ? ll->d.d : ll->d.d * 100. );
1175 break;
1176
1178 lua_pushnumber( L, ll->d.d );
1179 break;
1180
1182 lua_pushinteger( L, ll->d.i );
1183 break;
1184
1186 lua_pushboolean( L, ll->d.i );
1187 break;
1188 }
1189 lua_rawset( L, -3 );
1190 }
1191 return 0;
1192}
Header file with generic functions and naev-specifics.
#define FABS(x)
Definition naev.h:34
int scnprintf(char *text, size_t maxlen, const char *fmt,...)
Like snprintf(), but returns the number of characters ACTUALLY "printed" into the buffer....
Definition nstring.c:102
static const double d[]
Definition rng.c:263
int ss_statsListDesc(const ShipStatList *ll, char *buf, int len, int newline)
Writes the ship statistics description.
Definition shipstats.c:820
void ss_free(ShipStatList *ll)
Frees a list of ship stats.
Definition shipstats.c:934
static int ss_printD(char *buf, int len, int newline, double d, const ShipStatsLookup *sl)
Helper to print doubles.
Definition shipstats.c:759
int ss_statsMerge(ShipStats *dest, const ShipStats *src)
Merges two different ship stats.
Definition shipstats.c:533
int ss_statsMergeFromList(ShipStats *stats, const ShipStatList *list)
Updates a stat structure from a stat list.
Definition shipstats.c:666
StatDataType
The data type.
Definition shipstats.c:22
@ SS_DATA_TYPE_DOUBLE_ABSOLUTE_PERCENT
Definition shipstats.c:25
@ SS_DATA_TYPE_DOUBLE_ABSOLUTE
Definition shipstats.c:24
@ SS_DATA_TYPE_BOOLEAN
Definition shipstats.c:27
@ SS_DATA_TYPE_INTEGER
Definition shipstats.c:26
@ SS_DATA_TYPE_DOUBLE
Definition shipstats.c:23
static int ss_printA(char *buf, int len, int newline, double d, const ShipStatsLookup *sl)
Helper to print absolute doubles.
Definition shipstats.c:773
static void ss_adjustDoubleStat(double *statptr, double adjustment, int inverted)
Makes adjustments so the stats are positively additive.
Definition shipstats.c:597
int ss_statsGetLua(lua_State *L, const ShipStats *s, const char *name, int internal)
Gets a ship stat value by name and pushes it to Lua.
Definition shipstats.c:1116
static const char * ss_printD_colour(double d, const ShipStatsLookup *sl)
Some colour coding for ship stats doubles.
Definition shipstats.c:739
const char * ss_nameFromType(ShipStatsType type)
Gets the name from type.
Definition shipstats.c:703
static int ss_printI(char *buf, int len, int newline, int i, const ShipStatsLookup *sl)
Helper to print integers.
Definition shipstats.c:788
int ss_statsMergeFromListScale(ShipStats *stats, const ShipStatList *list, double scale)
Updates a stat structure from a stat list.
Definition shipstats.c:684
#define N__ELEM(t)
Definition shipstats.c:84
int ss_statsMergeSingleScale(ShipStats *stats, const ShipStatList *list, double scale)
Modifies a stat structure using a single element.
Definition shipstats.c:620
int ss_statsDesc(const ShipStats *s, char *buf, int len, int newline)
Writes the ship statistics description.
Definition shipstats.c:864
int ss_statsMergeSingle(ShipStats *stats, const ShipStatList *list)
Modifies a stat structure using a single element.
Definition shipstats.c:589
size_t ss_offsetFromType(ShipStatsType type)
Gets the offset from type.
Definition shipstats.c:714
static const ShipStatsLookup ss_lookup[]
Definition shipstats.c:95
ShipStatsType ss_typeFromName(const char *name)
Gets the type from the name.
Definition shipstats.c:725
static int ss_printB(char *buf, int len, int newline, int b, const ShipStatsLookup *sl)
Helper to print booleans.
Definition shipstats.c:801
static const char * ss_printI_colour(int i, const ShipStatsLookup *sl)
Some colour coding for ship stats integers.
Definition shipstats.c:749
int ss_listToXML(xmlTextWriterPtr writer, const ShipStatList *ll)
Creatse a shipstat list element from an xml node.
Definition shipstats.c:404
int ss_statsGetLuaTableList(lua_State *L, const ShipStatList *list, int internal)
Converts ship stats to a Lua table, which is pushed on the Lua stack.
Definition shipstats.c:1157
double ss_statsGet(const ShipStats *s, const char *name)
Gets a ship stat value by name.
Definition shipstats.c:1094
int ss_statsInit(ShipStats *stats)
Initializes a stat structure.
Definition shipstats.c:490
int ss_statsSet(ShipStats *s, const char *name, double value, int overwrite)
Sets a ship stat by name.
Definition shipstats.c:946
int ss_statsGetLuaTable(lua_State *L, const ShipStats *s, int internal)
Converts ship stats to a Lua table, which is pushed on the Lua stack.
Definition shipstats.c:1136
int ss_check(void)
Checks for validity.
Definition shipstats.c:474
double ss_statsGetRaw(const ShipStats *s, ShipStatsType type)
Gets a ship stat value by name.
Definition shipstats.c:1108
ShipStatList * ss_listFromXML(xmlNodePtr node)
Creates a shipstat list element from an xml node.
Definition shipstats.c:353
int ss_sort(ShipStatList **ll)
Sorts the ship stats, useful if doing saving stuff.
Definition shipstats.c:442
Represents relative ship statistics as a linked list.
Definition shipstats.h:198
ShipStatsType type
Definition shipstats.h:202
struct ShipStatList_ * next
Definition shipstats.h:199
Internal look up table for ship stats.
Definition shipstats.c:36
const char * name
Definition shipstats.c:40
const char * display
Definition shipstats.c:41
ShipStatsType type
Definition shipstats.c:38
StatDataType data
Definition shipstats.c:43
const char * unit
Definition shipstats.c:42
Represents ship statistics, properties ship can use.
Definition shipstats.h:229
static void weapon_damage(Weapon *w, const Damage *dmg)
Applies damage to a weapon.
Definition weapon.c:1900