naev 0.11.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"
13#include "shipstats.h"
14
15#include "log.h"
16#include "nstring.h"
17
28
34typedef struct ShipStatsLookup_ {
35 /* Explicitly set. */
36 ShipStatsType type;
37 const char *name;
38 const char *display;
39 const char *unit;
45 /* Self calculated. */
46 size_t offset;
48
49/* Flexible do everything macro. */
50#define ELEM( t, n, dsp, u, d , i) \
51 { .type=t, .name=#n, .display=dsp, .unit=u, .data=d, .inverted=i, .offset=offsetof( ShipStats, n ) }
52/* Standard types. */
53#define D__ELEM( t, n, dsp ) \
54 ELEM( t, n, dsp, N_("%"), SS_DATA_TYPE_DOUBLE, 0 )
55#define DI_ELEM( t, n, dsp ) \
56 ELEM( t, n, dsp, N_("%"), SS_DATA_TYPE_DOUBLE, 1 )
57
58#define A__ELEM( t, n, dsp, u ) \
59 ELEM( t, n, dsp, u, SS_DATA_TYPE_DOUBLE_ABSOLUTE, 0 )
60#define AI_ELEM( t, n, dsp, u) \
61 ELEM( t, n, dsp, u, SS_DATA_TYPE_DOUBLE_ABSOLUTE, 1 )
62
63#define P__ELEM( t, n, dsp ) \
64 ELEM( t, n, dsp, N_("%"), SS_DATA_TYPE_DOUBLE_ABSOLUTE_PERCENT, 0 )
65#define PI_ELEM( t, n, dsp ) \
66 ELEM( t, n, dsp, N_("%"), SS_DATA_TYPE_DOUBLE_ABSOLUTE_PERCENT, 1 )
67
68#define I__ELEM( t, n, dsp, u ) \
69 ELEM( t, n, dsp, u, SS_DATA_TYPE_INTEGER, 0 )
70#define II_ELEM( t, n, dsp ) \
71 ELEM( t, n, dsp, u, SS_DATA_TYPE_INTEGER, 1 )
72
73#define B__ELEM( t, n, dsp ) \
74 ELEM( t, n, dsp, NULL, SS_DATA_TYPE_BOOLEAN, 0 )
75#define BI_ELEM( t, n, dsp ) \
76 ELEM( t, n, dsp, NULL, SS_DATA_TYPE_BOOLEAN, 1 )
77
79#define N__ELEM( t ) \
80 { .type=t, .name=NULL, .display=NULL, .unit=NULL, .inverted=0, .offset=0 }
81
85static const ShipStatsLookup ss_lookup[] = {
86 /* Null element. */
87 N__ELEM( SS_TYPE_NIL ),
88
89 D__ELEM( SS_TYPE_D_SPEED_MOD, speed_mod, N_("Speed") ),
90 D__ELEM( SS_TYPE_D_TURN_MOD, turn_mod, N_("Turn") ),
91 D__ELEM( SS_TYPE_D_ACCEL_MOD, accel_mod, N_("Accel") ),
92 D__ELEM( SS_TYPE_D_CARGO_MOD, cargo_mod, N_("Cargo Space") ),
93 D__ELEM( SS_TYPE_D_FUEL_MOD, fuel_mod, N_("Fuel Cpacity") ),
94 D__ELEM( SS_TYPE_D_ARMOUR_MOD, armour_mod, N_("Armour Strength") ),
95 D__ELEM( SS_TYPE_D_ARMOUR_REGEN_MOD, armour_regen_mod, N_("Armour Regeneration") ),
96 D__ELEM( SS_TYPE_D_SHIELD_MOD, shield_mod, N_("Shield Strength") ),
97 D__ELEM( SS_TYPE_D_SHIELD_REGEN_MOD, shield_regen_mod, N_("Shield Regeneration") ),
98 D__ELEM( SS_TYPE_D_ENERGY_MOD, energy_mod, N_("Energy Capacity") ),
99 D__ELEM( SS_TYPE_D_ENERGY_REGEN_MOD, energy_regen_mod, N_("Energy Regeneration") ),
100 D__ELEM( SS_TYPE_D_CPU_MOD, cpu_mod, N_("CPU Capacity") ),
101 DI_ELEM( SS_TYPE_D_COOLDOWN_MOD, cooldown_mod, N_("Ability Cooldown") ),
102
103 DI_ELEM( SS_TYPE_D_JUMP_DELAY, jump_delay, N_("Jump Time") ),
104 DI_ELEM( SS_TYPE_D_LAND_DELAY, land_delay, N_("Landing Time") ),
105 DI_ELEM( SS_TYPE_D_CARGO_INERTIA, cargo_inertia, N_("Cargo Inertia") ),
106
107 DI_ELEM( SS_TYPE_D_EW_HIDE, ew_hide, N_("Detected Range") ),
108 DI_ELEM( SS_TYPE_D_EW_SIGNATURE, ew_signature, N_("Signature Range") ),
109 DI_ELEM( SS_TYPE_D_EW_STEALTH, ew_stealth, N_("Stealth Range") ),
110 D__ELEM( SS_TYPE_D_EW_DETECT, ew_detect, N_("Detection") ),
111 D__ELEM( SS_TYPE_D_EW_TRACK, ew_track, N_("Tracking") ),
112 D__ELEM( SS_TYPE_D_EW_JUMPDETECT, ew_jump_detect, N_("Jump Detection") ),
113 DI_ELEM( SS_TYPE_D_EW_STEALTH_TIMER, ew_stealth_timer, N_("Stealth Discovered Speed") ),
114 DI_ELEM( SS_TYPE_D_EW_SCANNED_TIME, ew_scanned_time, N_("Scanned Speed") ),
115
116 D__ELEM( SS_TYPE_D_LAUNCH_RATE, launch_rate, N_("Fire Rate (Launcher)") ),
117 D__ELEM( SS_TYPE_D_LAUNCH_RANGE, launch_range, N_("Launch Range") ),
118 D__ELEM( SS_TYPE_D_LAUNCH_DAMAGE, launch_damage, N_("Damage (Launcher)") ),
119 D__ELEM( SS_TYPE_D_AMMO_CAPACITY, ammo_capacity, N_("Ammo Capacity") ),
120 DI_ELEM( SS_TYPE_D_LAUNCH_LOCKON, launch_lockon, N_("Launch Lock-on") ),
121 DI_ELEM( SS_TYPE_D_LAUNCH_CALIBRATION, launch_calibration, N_("Launch Calibration") ),
122 D__ELEM( SS_TYPE_D_LAUNCH_RELOAD, launch_reload, N_("Ammo Reload Rate") ),
123
124 D__ELEM( SS_TYPE_D_FBAY_DAMAGE, fbay_damage, N_("Fighter Damage") ),
125 D__ELEM( SS_TYPE_D_FBAY_HEALTH, fbay_health, N_("Fighter Health") ),
126 D__ELEM( SS_TYPE_D_FBAY_MOVEMENT, fbay_movement, N_("Fighter Movement") ),
127 D__ELEM( SS_TYPE_D_FBAY_CAPACITY, fbay_capacity, N_("Fighter Bay Capacity") ),
128 D__ELEM( SS_TYPE_D_FBAY_RATE, fbay_rate, N_("Fighter Bay Launch Rate") ),
129 D__ELEM( SS_TYPE_D_FBAY_RELOAD, fbay_reload, N_("Fighter Reload Rate") ),
130
131 DI_ELEM( SS_TYPE_D_FORWARD_HEAT, fwd_heat, N_("Heat (Cannon)") ),
132 D__ELEM( SS_TYPE_D_FORWARD_DAMAGE, fwd_damage, N_("Damage (Cannon)") ),
133 D__ELEM( SS_TYPE_D_FORWARD_FIRERATE, fwd_firerate, N_("Fire Rate (Cannon)") ),
134 DI_ELEM( SS_TYPE_D_FORWARD_ENERGY, fwd_energy, N_("Energy Usage (Cannon)") ),
135 D__ELEM( SS_TYPE_D_FORWARD_DAMAGE_AS_DISABLE,fwd_dam_as_dis,N_("Damage as Disable (Cannon)") ),
136
137 DI_ELEM( SS_TYPE_D_TURRET_HEAT, tur_heat, N_("Heat (Turret)") ),
138 D__ELEM( SS_TYPE_D_TURRET_DAMAGE, tur_damage, N_("Damage (Turret)") ),
139 D__ELEM( SS_TYPE_D_TURRET_TRACKING, tur_tracking, N_("Tracking (Turret)") ),
140 D__ELEM( SS_TYPE_D_TURRET_FIRERATE, tur_firerate, N_("Fire Rate (Turret)") ),
141 DI_ELEM( SS_TYPE_D_TURRET_ENERGY, tur_energy, N_("Energy Usage (Turret)") ),
142 D__ELEM( SS_TYPE_D_TURRET_DAMAGE_AS_DISABLE, tur_dam_as_dis,N_("Damage as Disable (Turret)") ),
143
144 D__ELEM( SS_TYPE_D_HEAT_DISSIPATION, heat_dissipation, N_("Heat Dissipation") ),
145 D__ELEM( SS_TYPE_D_STRESS_DISSIPATION, stress_dissipation, N_("Stress Dissipation") ),
146 D__ELEM( SS_TYPE_D_CREW, crew_mod, N_("Crew") ),
147 DI_ELEM( SS_TYPE_D_MASS, mass_mod, N_("Ship Mass") ),
148 D__ELEM( SS_TYPE_D_ENGINE_LIMIT_REL, engine_limit_rel, N_("Engine Mass Limit") ),
149 D__ELEM( SS_TYPE_D_LOOT_MOD, loot_mod, N_("Boarding Bonus") ),
150 DI_ELEM( SS_TYPE_D_TIME_MOD, time_mod, N_("Time Constant") ),
151 D__ELEM( SS_TYPE_D_TIME_SPEEDUP, time_speedup, N_("Action Speed") ),
152 DI_ELEM( SS_TYPE_D_COOLDOWN_TIME, cooldown_time, N_("Ship Cooldown Time") ),
153 D__ELEM( SS_TYPE_D_JUMP_DISTANCE, jump_distance, N_("Jump Distance") ),
154 DI_ELEM( SS_TYPE_D_JUMP_WARMUP, jump_warmup, N_("Jump Warmup") ),
155 D__ELEM( SS_TYPE_D_MINING_BONUS, mining_bonus, N_("Mining Bonus") ),
156
157 A__ELEM( SS_TYPE_A_ACCEL, accel, N_("Accel"), _UNIT_ACCEL ),
158 A__ELEM( SS_TYPE_A_TURN, turn, N_("Turn Rate"), _UNIT_ROTATION ),
159 A__ELEM( SS_TYPE_A_SPEED, speed, N_("Maximum Speed"), _UNIT_SPEED ),
160 A__ELEM( SS_TYPE_A_ENERGY, energy, N_("Energy Capacity"), _UNIT_ENERGY ),
161 A__ELEM( SS_TYPE_A_ENERGY_REGEN, energy_regen, N_("Energy Regeneration"), _UNIT_POWER ),
162 AI_ELEM( SS_TYPE_A_ENERGY_REGEN_MALUS, energy_regen_malus, N_("Energy Usage"), _UNIT_POWER ),
163 AI_ELEM( SS_TYPE_A_ENERGY_LOSS, energy_loss, N_("Energy Usage"), _UNIT_POWER ),
164 A__ELEM( SS_TYPE_A_SHIELD, shield, N_("Shield Capacity"), _UNIT_ENERGY ),
165 A__ELEM( SS_TYPE_A_SHIELD_REGEN, shield_regen, N_("Shield Regeneration"), _UNIT_POWER ),
166 AI_ELEM( SS_TYPE_A_SHIELD_REGEN_MALUS, shield_regen_malus, N_("Shield Usage"), _UNIT_POWER ),
167 A__ELEM( SS_TYPE_A_ARMOUR, armour, N_("Armour"), _UNIT_ENERGY ),
168 A__ELEM( SS_TYPE_A_ARMOUR_REGEN, armour_regen, N_("Armour Regeneration"), _UNIT_POWER ),
169 AI_ELEM( SS_TYPE_A_ARMOUR_REGEN_MALUS, armour_regen_malus, N_("Armour Damage"), _UNIT_POWER ),
170 A__ELEM( SS_TYPE_A_DAMAGE, damage, N_("Damage"), _UNIT_POWER ),
171 A__ELEM( SS_TYPE_A_DISABLE, disable, N_("Disable"), _UNIT_POWER ),
172
173 A__ELEM( SS_TYPE_A_CPU_MAX, cpu_max, N_("CPU Capacity"), _UNIT_CPU ),
174 A__ELEM( SS_TYPE_A_ENGINE_LIMIT, engine_limit, N_("Engine Mass Limit"), _UNIT_MASS ),
175 A__ELEM( SS_TYPE_A_FUEL_REGEN, fuel_regen, N_("Fuel Regeneration"), _UNIT_PER_TIME ),
176 A__ELEM( SS_TYPE_A_ASTEROID_SCAN, asteroid_scan, N_("Asteroid Scanner Range"), _UNIT_DISTANCE ),
177 A__ELEM( SS_TYPE_A_NEBULA_VISIBILITY, nebu_visibility, N_("Nebula Visibility"), _UNIT_DISTANCE ),
178
179 P__ELEM( SS_TYPE_P_ABSORB, absorb, N_("Damage Absorption") ),
180
181 P__ELEM( SS_TYPE_P_NEBULA_ABSORB, nebu_absorb, N_("Nebula Resistance") ),
182 P__ELEM( SS_TYPE_P_JAMMING_CHANCE, jam_chance, N_("Missile jamming chance") ),
183
184 I__ELEM( SS_TYPE_I_FUEL, fuel, N_("Fuel"), _UNIT_UNIT ),
185 I__ELEM( SS_TYPE_I_CARGO, cargo, N_("Cargo"), _UNIT_MASS ),
186 I__ELEM( SS_TYPE_I_CREW, crew, N_("Crew"), _UNIT_UNIT ),
187
188 B__ELEM( SS_TYPE_B_HIDDEN_JUMP_DETECT, misc_hidden_jump_detect, N_("Hidden Jump Detection") ),
189 B__ELEM( SS_TYPE_B_INSTANT_JUMP, misc_instant_jump, N_("Instant Jump") ),
190 B__ELEM( SS_TYPE_B_REVERSE_THRUST, misc_reverse_thrust, N_("Reverse Thrusters") ),
191
192 /* Sentinel. */
193 N__ELEM( SS_TYPE_SENTINEL )
194};
195
196/*
197 * Prototypes.
198 */
199static const char* ss_printD_colour( double d, const ShipStatsLookup *sl );
200static const char* ss_printI_colour( int i, const ShipStatsLookup *sl );
201static int ss_printD( char *buf, int len, int newline, double d, const ShipStatsLookup *sl );
202static int ss_printA( char *buf, int len, int newline, double d, const ShipStatsLookup *sl );
203static int ss_printI( char *buf, int len, int newline, int i, const ShipStatsLookup *sl );
204static int ss_printB( char *buf, int len, int newline, int b, const ShipStatsLookup *sl );
205static double ss_statsGetInternal( const ShipStats *s, ShipStatsType type );
206static int ss_statsGetLuaInternal( lua_State *L, const ShipStats *s, ShipStatsType type, int internal );
207
208ShipStatList* ss_statsSetList( ShipStatList *head, ShipStatsType type, double value, int overwrite, int raw )
209{
210 const ShipStatsLookup *sl;
211 ShipStatList *ll = NULL;
212 ShipStatList *newhead = head;
213 int init = overwrite;
214
215 if (type == SS_TYPE_NIL)
216 return NULL;
217 sl = &ss_lookup[ type ];
218
219 /* See if there is an element to modify or overwrite. */
220 if (head != NULL) {
221 for (ShipStatList *l=head; l!=NULL; l=l->next) {
222 if (type==l->type) {
223 ll = l;
224 break;
225 }
226 }
227 }
228
229 /* Allocate. */
230 if (ll==NULL) {
231 newhead = ll = malloc( sizeof(ShipStatList) );
232 ll->next = head;
233 ll->target = 0;
234 ll->type = type;
235 init = 1; /* Force initialization. */
236 }
237
238 if (init) {
239 switch (sl->data) {
241 ll->d.d = 1.;
242 break;
245 ll->d.d = 0.;
246 break;
249 ll->d.i = 0;
250 break;
251 }
252 }
253
254 /* Set the data. */
255 switch (sl->data) {
257 if (raw)
258 ll->d.d *= value;
259 else
260 ll->d.d *= value / 100.;
261 break;
262
264 if (raw)
265 ll->d.d += value;
266 else
267 ll->d.d += value / 100.;
268 break;
269
271 ll->d.d += value;
272 break;
273
275 ll->d.i |= (fabs(value) > 1e-5);
276 break;
277
279 ll->d.i += round(value);
280 break;
281 }
282
283 return newhead;
284}
285
292ShipStatList* ss_listFromXML( xmlNodePtr node )
293{
294 const ShipStatsLookup *sl;
295 ShipStatList *ll;
296 ShipStatsType type;
297
298 /* Try to get type. */
299 type = ss_typeFromName( (char*) node->name );
300 if (type == SS_TYPE_NIL)
301 return NULL;
302
303 /* Allocate. */
304 ll = malloc( sizeof(ShipStatList) );
305 ll->next = NULL;
306 ll->target = 0;
307 ll->type = type;
308
309 /* Set the data. */
310 sl = &ss_lookup[ type ];
311 switch (sl->data) {
314 ll->d.d = xml_getFloat(node) / 100.;
315 break;
316
318 ll->d.d = xml_getFloat(node);
319 break;
320
322 ll->d.i = !!xml_getInt(node);
323 break;
324
326 ll->d.i = xml_getInt(node);
327 break;
328 }
329
330 /* Sort them. */
331 ss_sort( &ll );
332
333 return ll;
334}
335
343int ss_listToXML( xmlTextWriterPtr writer, const ShipStatList *ll )
344{
345 for (const ShipStatList *l=ll; l!=NULL; l=l->next) {
346 const ShipStatsLookup *sl = &ss_lookup[ l->type ];
347 switch (sl->data) {
350 xmlw_elem( writer, sl->name, "%f", l->d.d * 100 );
351 break;
352
354 xmlw_elem( writer, sl->name, "%f", l->d.d );
355 break;
356
359 xmlw_elem( writer, sl->name, "%d", l->d.i );
360 break;
361 }
362 }
363 return 0;
364}
365
366static int shipstat_sort( const void *a, const void *b )
367{
368 const ShipStatList **la = (const ShipStatList**) a;
369 const ShipStatList **lb = (const ShipStatList**) b;
370 const ShipStatsLookup *sla = &ss_lookup[ (*la)->type ];
371 const ShipStatsLookup *slb = &ss_lookup[ (*lb)->type ];
372 return strcmp( sla->name, slb->name );
373}
374
382{
383 int n, i;
384 ShipStatList **arr;
385
386 /* Nothing to do. */
387 if (*ll==NULL)
388 return 0;
389
390 n = 0;
391 for (ShipStatList *l=*ll; l!=NULL; l=l->next)
392 n++;
393
394 arr = malloc( sizeof(ShipStatList*) * n );
395 i = 0;
396 for (ShipStatList *l=*ll; l!=NULL; l=l->next) {
397 arr[i] = l;
398 i++;
399 }
400 qsort( arr, n, sizeof(ShipStatList*), shipstat_sort );
401
402 *ll = arr[0];
403 for (i=1; i<n; i++)
404 arr[i-1]->next = arr[i];
405 arr[n-1]->next = NULL;
406 free( arr );
407 return 0;
408}
409
410
414int ss_check (void)
415{
416 for (ShipStatsType i=0; i<=SS_TYPE_SENTINEL; i++) {
417 if (ss_lookup[i].type != i) {
418 WARN(_("ss_lookup: %s should have id %d but has %d"),
419 ss_lookup[i].name, i, ss_lookup[i].type );
420 return -1;
421 }
422 }
423
424 return 0;
425}
426
431{
432 char *ptr;
433
434 /* Clear the memory. */
435 memset( stats, 0, sizeof(ShipStats) );
436
437 ptr = (char*) stats;
438 for (int i=0; i<SS_TYPE_SENTINEL; i++) {
439 const ShipStatsLookup *sl = &ss_lookup[ i ];
440
441 /* Only want valid names. */
442 if (sl->name == NULL)
443 continue;
444
445 /* Handle doubles. */
446 switch (sl->data) {
448 {
449 double *dbl;
450 const char *fieldptr = &ptr[ sl->offset ];
451 memcpy(&dbl, &fieldptr, sizeof(double*));
452 *dbl = 1.0;
453 break;
454 }
455
456 /* No need to set, memset does the work. */
461 break;
462 }
463 }
464
465 return 0;
466}
467
474int ss_statsMerge( ShipStats *dest, const ShipStats *src )
475{
476 int *destint;
477 const int *srcint;
478 double *destdbl;
479 const double *srcdbl;
480 char *destptr;
481 const char *srcptr;
482
483 destptr = (char*) dest;
484 srcptr = (const char*) src;
485 for (int i=0; i<SS_TYPE_SENTINEL; i++) {
486 const ShipStatsLookup *sl = &ss_lookup[ i ];
487
488 /* Only want valid names. */
489 if (sl->name == NULL)
490 continue;
491
492 switch (sl->data) {
494 destdbl = (double*) &destptr[ sl->offset ];
495 srcdbl = (const double*) &srcptr[ sl->offset ];
496 *destdbl = (*destdbl) * (*srcdbl);
497 break;
498
501 destdbl = (double*) &destptr[ sl->offset ];
502 srcdbl = (const double*) &srcptr[ sl->offset ];
503 *destdbl = (*destdbl) + (*srcdbl);
504 break;
505
507 destint = (int*) &destptr[ sl->offset ];
508 srcint = (const int*) &srcptr[ sl->offset ];
509 *destint = (*destint) + (*srcint);
510 break;
511
513 destint = (int*) &destptr[ sl->offset ];
514 srcint = (const int*) &srcptr[ sl->offset ];
515 *destint = !!((*destint) + (*srcint));
516 break;
517 }
518 }
519
520 return 0;
521}
522
531{
532 char *ptr;
533 char *fieldptr;
534 double *dbl;
535 int *i;
536 const ShipStatsLookup *sl = &ss_lookup[ list->type ];
537
538 ptr = (char*) stats;
539 switch (sl->data) {
541 fieldptr = &ptr[ sl->offset ];
542 memcpy(&dbl, &fieldptr, sizeof(double*));
543 *dbl *= 1.0+list->d.d;
544 if (*dbl < 0.) /* Don't let the values go negative. */
545 *dbl = 0.;
546 break;
547
550 fieldptr = &ptr[ sl->offset ];
551 memcpy(&dbl, &fieldptr, sizeof(double*));
552 *dbl += list->d.d;
553 break;
554
556 fieldptr = &ptr[ sl->offset ];
557 memcpy(&i, &fieldptr, sizeof(int*));
558 *i += list->d.i;
559 break;
560
562 fieldptr = &ptr[ sl->offset ];
563 memcpy(&i, &fieldptr, sizeof(int*));
564 *i = 1; /* Can only set to true. */
565 break;
566 }
567
568 return 0;
569}
570
579int ss_statsMergeSingleScale( ShipStats *stats, const ShipStatList *list, double scale )
580{
581 char *ptr;
582 char *fieldptr;
583 double *dbl;
584 int *i;
585 const ShipStatsLookup *sl = &ss_lookup[ list->type ];
586
587 ptr = (char*) stats;
588 switch (sl->data) {
590 fieldptr = &ptr[ sl->offset ];
591 memcpy(&dbl, &fieldptr, sizeof(double*));
592 *dbl *= 1.0+list->d.d * scale;
593 if (*dbl < 0.) /* Don't let the values go negative. */
594 *dbl = 0.;
595 break;
596
599 fieldptr = &ptr[ sl->offset ];
600 memcpy(&dbl, &fieldptr, sizeof(double*));
601 *dbl += list->d.d * scale;
602 break;
603
605 fieldptr = &ptr[ sl->offset ];
606 memcpy(&i, &fieldptr, sizeof(int*));
607 *i += list->d.i * scale;
608 break;
609
611 fieldptr = &ptr[ sl->offset ];
612 memcpy(&i, &fieldptr, sizeof(int*));
613 *i = 1; /* Can only set to true. */
614 break;
615 }
616
617 return 0;
618}
619
628{
629 if (list==NULL)
630 return 0;
631 int ret = 0;
632 for (const ShipStatList *ll = list; ll != NULL; ll = ll->next)
633 ret |= ss_statsMergeSingle( stats, ll );
634 return ret;
635}
636
645int ss_statsMergeFromListScale( ShipStats *stats, const ShipStatList* list, double scale )
646{
647 if (list==NULL)
648 return 0;
649 int ret = 0;
650 for (const ShipStatList *ll = list; ll != NULL; ll = ll->next)
651 ret |= ss_statsMergeSingleScale( stats, ll, scale );
652 return ret;
653}
654
663const char* ss_nameFromType( ShipStatsType type )
664{
665 return ss_lookup[ type ].name;
666}
667
674size_t ss_offsetFromType( ShipStatsType type )
675{
676 return ss_lookup[ type ].offset;
677}
678
685ShipStatsType ss_typeFromName( const char *name )
686{
687 for (int i=0; i<SS_TYPE_SENTINEL; i++)
688 if ((ss_lookup[i].name != NULL) && (strcmp(name,ss_lookup[i].name)==0))
689 return ss_lookup[i].type;
690
691 WARN(_("ss_typeFromName: No ship stat matching '%s'"), name);
692 return SS_TYPE_NIL;
693}
694
698static const char* ss_printD_colour( double d, const ShipStatsLookup *sl )
699{
700 if (sl->inverted)
701 return d < 0. ? "g" : "r";
702 return d > 0. ? "g" : "r";
703}
704
708static const char* ss_printI_colour( int i, const ShipStatsLookup *sl )
709{
710 if (sl->inverted)
711 return i < 0 ? "g" : "r";
712 return i > 0 ? "g" : "r";
713}
714
718static int ss_printD( char *buf, int len, int newline, double d, const ShipStatsLookup *sl )
719{
720 if (FABS(d) < 1e-10)
721 return 0;
722
723 return scnprintf( buf, len, p_("shipstats_double","%s#%s%s: %+g %s#0"),
724 (newline) ? "\n" : "",
725 ss_printD_colour( d, sl ),
726 _(sl->display), d*100.,
727 _(sl->unit));
728}
729
733static int ss_printA( char *buf, int len, int newline, double d, const ShipStatsLookup *sl )
734{
735 if (FABS(d) < 1e-10)
736 return 0;
737 return scnprintf( buf, len, p_("shipstats_absolute","%s#%s%s: %+g %s#0"),
738 (newline) ? "\n" : "",
739 ss_printD_colour( d, sl ),
740 _(sl->display), d, /* TODO probably use num2strU here, but we want the sign enforced. */
741 _(sl->unit));
742}
743
747static int ss_printI( char *buf, int len, int newline, int i, const ShipStatsLookup *sl )
748{
749 if (i == 0)
750 return 0 ;
751 return scnprintf( buf, len, p_("shipstats_integer","%s#%s%s: %+d %s#0"),
752 (newline) ? "\n" : "",
753 ss_printI_colour( i, sl ),
754 _(sl->display), i,
755 _(sl->unit));
756}
757
761static int ss_printB( char *buf, int len, int newline, int b, const ShipStatsLookup *sl )
762{
763 if (!b)
764 return 0;
765 return scnprintf( buf, len, p_("shipstats_boolean","%s#%s%s#0"),
766 (newline) ? "\n" : "",
767 ss_printI_colour( b, sl ),
768 _(sl->display) );
769}
770
780int ss_statsListDesc( const ShipStatList *ll, char *buf, int len, int newline )
781{
782 int i = 0;
783 int newl = newline;
784 for ( ; ll != NULL; ll=ll->next) {
785 const ShipStatsLookup *sl;
786 int left = len-i;
787 if (left < 0)
788 break;
789 sl = &ss_lookup[ ll->type ];
790
791 switch (sl->data) {
794 i += ss_printD( &buf[i], left, newl, ll->d.d, sl );
795 break;
796
798 i += ss_printA( &buf[i], left, newl, ll->d.d, sl );
799 break;
800
802 i += ss_printI( &buf[i], left, newl, ll->d.i, sl );
803 break;
804
806 i += ss_printB( &buf[i], left, newl, ll->d.i, sl );
807 break;
808 }
809
810 newl = 1;
811 }
812 return i;
813}
814
824int ss_statsDesc( const ShipStats *s, char *buf, int len, int newline )
825{
826 int l, left;
827 char *ptr;
828 char *fieldptr;
829 double *dbl;
830 int *num;
831
832 l = 0;
833 ptr = (char*) s;
834 for (int i=0; i<SS_TYPE_SENTINEL; i++) {
835 const ShipStatsLookup *sl = &ss_lookup[ i ];
836
837 /* Only want valid names. */
838 if (sl->name == NULL)
839 continue;
840
841 /* Calculate offset left. */
842 left = len-l;
843 if (left < 0)
844 break;
845
846 switch (sl->data) {
848 fieldptr = &ptr[ sl->offset ];
849 memcpy(&dbl, &fieldptr, sizeof(double*));
850 l += ss_printD( &buf[l], left, (newline||(l!=0)), ((*dbl)-1.), sl );
851 break;
852
854 fieldptr = &ptr[ sl->offset ];
855 memcpy(&dbl, &fieldptr, sizeof(double*));
856 l += ss_printD( &buf[l], left, (newline||(l!=0)), (*dbl), sl );
857 break;
858
860 fieldptr = &ptr[ sl->offset ];
861 memcpy(&dbl, &fieldptr, sizeof(double*));
862 l += ss_printA( &buf[l], left, (newline||(l!=0)), (*dbl), sl );
863 break;
864
866 fieldptr = &ptr[ sl->offset ];
867 memcpy(&num, &fieldptr, sizeof(int*));
868 l += ss_printI( &buf[l], left, (newline||(l!=0)), (*num), sl );
869 break;
870
872 fieldptr = &ptr[ sl->offset ];
873 memcpy(&num, &fieldptr, sizeof(int*));
874 l += ss_printB( &buf[l], left, (newline||(l!=0)), (*num), sl );
875 break;
876 }
877 }
878
879 return l;
880}
881
888{
889 while (ll != NULL) {
890 ShipStatList *tmp = ll;
891 ll = ll->next;
892 free(tmp);
893 }
894}
895
899int ss_statsSet( ShipStats *s, const char *name, double value, int overwrite )
900{
901 const ShipStatsLookup *sl;
902 ShipStatsType type;
903 char *ptr;
904 double *destdbl;
905 int *destint;
906 double v;
907
908 type = ss_typeFromName( name );
909 if (type == SS_TYPE_NIL) {
910 WARN(_("Unknown ship stat type '%s'!"), name );
911 return -1;
912 }
913
914 sl = &ss_lookup[ type ];
915 ptr = (char*) s;
916 switch (sl->data) {
918 destdbl = (double*) &ptr[ sl->offset ];
919 v = 1.0 + value / 100.;
920 if (overwrite)
921 *destdbl = v;
922 else
923 *destdbl *= v;
924 break;
925
927 destdbl = (double*) &ptr[ sl->offset ];
928 if (overwrite)
929 *destdbl = value / 100.;
930 else
931 *destdbl += value / 100.;
932 break;
933
935 destdbl = (double*) &ptr[ sl->offset ];
936 if (overwrite)
937 *destdbl = value;
938 else
939 *destdbl += value;
940 break;
941
943 destint = (int*) &ptr[ sl->offset ];
944 if (overwrite)
945 *destint = (fabs(value) > 1e-5);
946 else
947 *destint |= (fabs(value) > 1e-5);
948 break;
949
951 destint = (int*) &ptr[ sl->offset ];
952 if (overwrite)
953 *destint = round(value);
954 else
955 *destint += round(value);
956 break;
957 }
958
959 return 0;
960}
961
962static double ss_statsGetInternal( const ShipStats *s, ShipStatsType type )
963{
964 const ShipStatsLookup *sl;
965 const char *ptr;
966 const double *destdbl;
967 const int *destint;
968
969 sl = &ss_lookup[ type ];
970 ptr = (const char*) s;
971 switch (sl->data) {
973 destdbl = (const double*) &ptr[ sl->offset ];
974 return 100.*((*destdbl) - 1.0);
975
977 destdbl = (const double*) &ptr[ sl->offset ];
978 return 100.*(*destdbl);
979
981 destdbl = (const double*) &ptr[ sl->offset ];
982 return *destdbl;
983
986 destint = (const int*) &ptr[ sl->offset ];
987 return *destint;
988 }
989 return 0.;
990}
991
992static int ss_statsGetLuaInternal( lua_State *L, const ShipStats *s, ShipStatsType type, int internal )
993{
994 const ShipStatsLookup *sl;
995 const char *ptr;
996 const double *destdbl;
997 const int *destint;
998
999 sl = &ss_lookup[ type ];
1000 ptr = (const char*) s;
1001 switch (sl->data) {
1003 destdbl = (const double*) &ptr[ sl->offset ];
1004 if (internal)
1005 lua_pushnumber(L, *destdbl );
1006 else
1007 lua_pushnumber(L, 100.*((*destdbl) - 1.0) );
1008 return 0;
1009
1011 destdbl = (const double*) &ptr[ sl->offset ];
1012 if (internal)
1013 lua_pushnumber(L, *destdbl );
1014 else
1015 lua_pushnumber(L, 100.*(*destdbl));
1016 return 0;
1017
1019 destdbl = (const double*) &ptr[ sl->offset ];
1020 lua_pushnumber(L, *destdbl);
1021 return 0;
1022
1024 destint = (const int*) &ptr[ sl->offset ];
1025 lua_pushboolean(L, *destint);
1026 return 0;
1027
1029 destint = (const int*) &ptr[ sl->offset ];
1030 lua_pushinteger(L, *destint);
1031 return 0;
1032 }
1033 lua_pushnil(L);
1034 return -1;
1035}
1036
1040double ss_statsGet( const ShipStats *s, const char *name )
1041{
1042 ShipStatsType type = ss_typeFromName( name );
1043 if (type == SS_TYPE_NIL) {
1044 WARN(_("Unknown ship stat type '%s'!"), name );
1045 return 0;
1046 }
1047
1048 return ss_statsGetInternal( s, type );
1049}
1050
1054int ss_statsGetLua( lua_State *L, const ShipStats *s, const char *name, int internal )
1055{
1056 ShipStatsType type;
1057
1058 if (name==NULL)
1059 return ss_statsGetLuaTable( L, s, internal );
1060
1061 type = ss_typeFromName( name );
1062 if (type == SS_TYPE_NIL) {
1063 WARN(_("Unknown ship stat type '%s'!"), name );
1064 return -1;
1065 }
1066
1067 return ss_statsGetLuaInternal( L, s, type, internal );
1068}
1069
1073int ss_statsGetLuaTable( lua_State *L, const ShipStats *s, int internal )
1074{
1075 lua_newtable(L);
1076 for (int i=0; i<SS_TYPE_SENTINEL; i++) {
1077 const ShipStatsLookup *sl = &ss_lookup[ i ];
1078
1079 /* Only want valid names. */
1080 if (sl->name == NULL)
1081 continue;
1082
1083 /* Push name and get value. */
1084 lua_pushstring(L, sl->name);
1085 ss_statsGetLuaInternal( L, s, i, internal );
1086 lua_rawset( L, -3 );
1087 }
1088 return 0;
1089}
Header file with generic functions and naev-specifics.
#define FABS(x)
Definition naev.h:37
int scnprintf(char *text, size_t maxlen, const char *fmt,...)
Like snprintf(), but returns the number of characters ACTUALLY "printed" into the buffer....
Definition nstring.c:99
static const double d[]
Definition rng.c:273
int ss_statsListDesc(const ShipStatList *ll, char *buf, int len, int newline)
Writes the ship statistics description.
Definition shipstats.c:780
void ss_free(ShipStatList *ll)
Frees a list of ship stats.
Definition shipstats.c:887
static int ss_printD(char *buf, int len, int newline, double d, const ShipStatsLookup *sl)
Helper to print doubles.
Definition shipstats.c:718
int ss_statsMerge(ShipStats *dest, const ShipStats *src)
Merges two different ship stats.
Definition shipstats.c:474
int ss_statsMergeFromList(ShipStats *stats, const ShipStatList *list)
Updates a stat structure from a stat list.
Definition shipstats.c:627
StatDataType
The data type.
Definition shipstats.c:21
@ SS_DATA_TYPE_DOUBLE_ABSOLUTE_PERCENT
Definition shipstats.c:24
@ SS_DATA_TYPE_DOUBLE_ABSOLUTE
Definition shipstats.c:23
@ SS_DATA_TYPE_BOOLEAN
Definition shipstats.c:26
@ SS_DATA_TYPE_INTEGER
Definition shipstats.c:25
@ SS_DATA_TYPE_DOUBLE
Definition shipstats.c:22
static int ss_printA(char *buf, int len, int newline, double d, const ShipStatsLookup *sl)
Helper to print absolute doubles.
Definition shipstats.c:733
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:1054
static const char * ss_printD_colour(double d, const ShipStatsLookup *sl)
Some colour coding for ship stats doubles.
Definition shipstats.c:698
const char * ss_nameFromType(ShipStatsType type)
Gets the name from type.
Definition shipstats.c:663
static int ss_printI(char *buf, int len, int newline, int i, const ShipStatsLookup *sl)
Helper to print integers.
Definition shipstats.c:747
int ss_statsMergeFromListScale(ShipStats *stats, const ShipStatList *list, double scale)
Updates a stat structure from a stat list.
Definition shipstats.c:645
#define N__ELEM(t)
Definition shipstats.c:79
int ss_statsMergeSingleScale(ShipStats *stats, const ShipStatList *list, double scale)
Modifies a stat structure using a single element.
Definition shipstats.c:579
int ss_statsDesc(const ShipStats *s, char *buf, int len, int newline)
Writes the ship statistics description.
Definition shipstats.c:824
int ss_statsMergeSingle(ShipStats *stats, const ShipStatList *list)
Modifies a stat structure using a single element.
Definition shipstats.c:530
size_t ss_offsetFromType(ShipStatsType type)
Gets the offset from type.
Definition shipstats.c:674
static const ShipStatsLookup ss_lookup[]
Definition shipstats.c:85
ShipStatsType ss_typeFromName(const char *name)
Gets the type from the name.
Definition shipstats.c:685
static int ss_printB(char *buf, int len, int newline, int b, const ShipStatsLookup *sl)
Helper to print booleans.
Definition shipstats.c:761
static const char * ss_printI_colour(int i, const ShipStatsLookup *sl)
Some colour coding for ship stats integers.
Definition shipstats.c:708
int ss_listToXML(xmlTextWriterPtr writer, const ShipStatList *ll)
Creatse a shipstat list element from an xml node.
Definition shipstats.c:343
double ss_statsGet(const ShipStats *s, const char *name)
Gets a ship stat value by name.
Definition shipstats.c:1040
int ss_statsInit(ShipStats *stats)
Initializes a stat structure.
Definition shipstats.c:430
int ss_statsSet(ShipStats *s, const char *name, double value, int overwrite)
Sets a ship stat by name.
Definition shipstats.c:899
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:1073
int ss_check(void)
Checks for validity.
Definition shipstats.c:414
ShipStatList * ss_listFromXML(xmlNodePtr node)
Creates a shipstat list element from an xml node.
Definition shipstats.c:292
int ss_sort(ShipStatList **ll)
Sorts the ship stats, useful if doing saving stuff.
Definition shipstats.c:381
Represents relative ship statistics as a linked list.
Definition shipstats.h:167
ShipStatsType type
Definition shipstats.h:171
struct ShipStatList_ * next
Definition shipstats.h:168
Internal look up table for ship stats.
Definition shipstats.c:34
const char * name
Definition shipstats.c:37
const char * display
Definition shipstats.c:38
ShipStatsType type
Definition shipstats.c:36
StatDataType data
Definition shipstats.c:40
const char * unit
Definition shipstats.c:39
Represents ship statistics, properties ship can use.
Definition shipstats.h:198