naev 0.12.6
damagetype.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 "damagetype.h"
14
15#include "array.h"
16#include "log.h"
17#include "ndata.h"
18#include "nxml.h"
19#include "shipstats.h"
20
21#define DTYPE_XML_ID "dtype"
22
28typedef struct DTYPE_ {
29 char *name;
30 char *display;
31 double sdam;
32 double adam;
33 double knock;
34 size_t soffset;
35 size_t aoffset;
36} DTYPE;
37
38static DTYPE *dtype_types = NULL;
39
40/*
41 * prototypes
42 */
43static int DTYPE_parse( DTYPE *temp, const char *file );
44static void DTYPE_free( DTYPE *damtype );
45static DTYPE *dtype_validType( int type );
46static int dtype_cmp( const void *p1, const void *p2 );
47
51static int dtype_cmp( const void *p1, const void *p2 )
52{
53 const DTYPE *d1 = (const DTYPE *)p1;
54 const DTYPE *d2 = (const DTYPE *)p2;
55 return strcmp( d1->name, d2->name );
56}
57
65static int DTYPE_parse( DTYPE *temp, const char *file )
66{
67 xmlNodePtr node, parent;
68 xmlDocPtr doc;
69 char *stat;
70
71 /* Load and read the data. */
72 doc = xml_parsePhysFS( file );
73 if ( doc == NULL )
74 return -1;
75
76 /* Check to see if document exists. */
77 parent = doc->xmlChildrenNode;
78 if ( !xml_isNode( parent, DTYPE_XML_ID ) ) {
79 WARN( _( "Malformed '%s' file: missing root element '%s'" ), file,
81 return -1;
82 }
83
84 /* Clear data. */
85 memset( temp, 0, sizeof( DTYPE ) );
86
87 xmlr_attr_strd( parent, "name", temp->name );
88 xmlr_attr_strd( parent, "display", temp->display );
89
90 /* Extract the data. */
91 node = parent->xmlChildrenNode;
92 do {
93 xml_onlyNodes( node );
94
95 if ( xml_isNode( node, "shield" ) ) {
96 temp->sdam = xml_getFloat( node );
97
98 xmlr_attr_strd( node, "stat", stat );
99 if ( stat != NULL ) {
100 temp->soffset = ss_offsetFromType( ss_typeFromName( stat ) );
101 free( stat );
102 }
103
104 continue;
105 } else if ( xml_isNode( node, "armour" ) ) {
106 temp->adam = xml_getFloat( node );
107
108 xmlr_attr_strd( node, "stat", stat );
109 if ( stat != NULL ) {
110 temp->aoffset = ss_offsetFromType( ss_typeFromName( stat ) );
111 free( stat );
112 }
113
114 continue;
115 }
116 xmlr_float( node, "knockback", temp->knock );
117
118 WARN( _( "Unknown node of type '%s' in damage node '%s'." ), node->name,
119 temp->name );
120 } while ( xml_nextNode( node ) );
121
122#define MELEMENT( o, s ) \
123 if ( o ) \
124 WARN( _( "DTYPE '%s' invalid '"s \
125 "' element" ), \
126 temp->name )
127 MELEMENT( temp->sdam < 0., "shield" );
128 MELEMENT( temp->adam < 0., "armour" );
129 MELEMENT( temp->knock < 0., "knockback" );
130#undef MELEMENT
131
132 /* Clean up. */
133 xmlFreeDoc( doc );
134
135 return 0;
136}
137
143static void DTYPE_free( DTYPE *damtype )
144{
145 free( damtype->name );
146 damtype->name = NULL;
147 free( damtype->display );
148 damtype->display = NULL;
149}
150
157int dtype_get( const char *name )
158{
159 const DTYPE d = { .name = (char *)name };
160 const DTYPE *dout = bsearch( &d, dtype_types, array_size( dtype_types ),
161 sizeof( DTYPE ), dtype_cmp );
162 if ( dout == NULL ) {
163 WARN( _( "Damage type '%s' not found in stack." ), name );
164 return -1;
165 }
166 return dout - dtype_types;
167}
168
172static DTYPE *dtype_validType( int type )
173{
174 if ( ( type < 0 ) || ( type >= array_size( dtype_types ) ) ) {
175 WARN( _( "Damage type '%d' is invalid." ), type );
176 return NULL;
177 }
178 return &dtype_types[type];
179}
180
184const char *dtype_damageTypeToStr( int type )
185{
186 DTYPE *dmg = dtype_validType( type );
187 if ( dmg == NULL )
188 return NULL;
189 return ( dmg->display == NULL ) ? dmg->name : dmg->display;
190}
191
197int dtype_load( void )
198{
199 const DTYPE dtype_raw_type = {
200 .name = strdup( N_( "raw" ) ),
201 .display = NULL,
202 .sdam = 1.,
203 .adam = 1.,
204 .knock = 0.,
205 .soffset = 0,
206 .aoffset = 0,
207 };
208 char **dtype_files = ndata_listRecursive( DTYPE_DATA_PATH );
209
210 /* Load up the individual damage types. */
212 array_push_back( &dtype_types, dtype_raw_type );
213
214 for ( int i = 0; i < array_size( dtype_files ); i++ ) {
215 DTYPE dtype;
216 int ret = DTYPE_parse( &dtype, dtype_files[i] );
217 if ( ret == 0 )
218 array_push_back( &dtype_types, dtype );
219 free( dtype_files[i] );
220 }
221 array_free( dtype_files );
222
223 /* Shrink back to minimum - shouldn't change ever. */
224 qsort( dtype_types, array_size( dtype_types ), sizeof( DTYPE ), dtype_cmp );
226
227 return 0;
228}
229
233void dtype_free( void )
234{
235 /* clear the damtypes */
236 for ( int i = 0; i < array_size( dtype_types ); i++ )
237 DTYPE_free( &dtype_types[i] );
239 dtype_types = NULL;
240}
241
251int dtype_raw( int type, double *shield, double *armour, double *knockback )
252{
253 const DTYPE *dtype = dtype_validType( type );
254 if ( dtype == NULL )
255 return -1;
256 if ( shield != NULL )
257 *shield = dtype->sdam;
258 if ( armour != NULL )
259 *armour = dtype->adam;
260 if ( knockback != NULL )
261 *knockback = dtype->knock;
262 return 0;
263}
264
275void dtype_calcDamage( double *dshield, double *darmour, double absorb,
276 double *knockback, const Damage *dmg,
277 const ShipStats *s )
278{
279 DTYPE *dtype;
280 char *ptr;
281 double multiplier;
282
283 /* Must be valid. */
284 dtype = dtype_validType( dmg->type );
285 if ( dtype == NULL )
286 return;
287
288 /* Set if non-nil. */
289 if ( dshield != NULL ) {
290 if ( ( dtype->soffset == 0 ) || ( s == NULL ) )
291 *dshield = dtype->sdam * dmg->damage * absorb;
292 else {
293 /*
294 * If an offset has been specified, look for a double at that offset
295 * in the ShipStats struct, and used it as a multiplier.
296 *
297 * The 1. - n logic serves to convert the value from absorption to
298 * damage multiplier.
299 */
300 ptr = (char *)s;
301 memcpy( &multiplier, &ptr[dtype->soffset], sizeof( double ) );
302 multiplier = MAX( 0., 1. - multiplier );
303 *dshield = dtype->sdam * dmg->damage * absorb * multiplier;
304 }
305 }
306 if ( darmour != NULL ) {
307 if ( ( dtype->aoffset ) == 0 || ( s == NULL ) )
308 *darmour = dtype->adam * dmg->damage * absorb;
309 else {
310 ptr = (char *)s;
311 memcpy( &multiplier, &ptr[dtype->aoffset], sizeof( double ) );
312 multiplier = MAX( 0., 1. - multiplier );
313 *darmour = dtype->adam * dmg->damage * absorb * multiplier;
314 }
315 }
316
317 if ( knockback != NULL )
318 *knockback = dtype->knock;
319}
Provides macros to work with dynamic arrays.
#define array_free(ptr_array)
Frees memory allocated and sets array to NULL.
Definition array.h:170
static ALWAYS_INLINE int array_size(const void *array)
Returns number of elements in the array.
Definition array.h:179
#define array_shrink(ptr_array)
Shrinks memory to fit only ‘size’ elements.
Definition array.h:160
#define array_push_back(ptr_array, element)
Adds a new element at the end of the array.
Definition array.h:134
#define array_create(basic_type)
Creates a new dynamic array of ‘basic_type’.
Definition array.h:93
int dtype_load(void)
Loads the dtype stack.
Definition damagetype.c:197
static void DTYPE_free(DTYPE *damtype)
Frees a DTYPE.
Definition damagetype.c:143
int dtype_raw(int type, double *shield, double *armour, double *knockback)
Gets the raw modulation stats of a damage type.
Definition damagetype.c:251
void dtype_calcDamage(double *dshield, double *darmour, double absorb, double *knockback, const Damage *dmg, const ShipStats *s)
Gives the real shield damage, armour damage and knockback modifier.
Definition damagetype.c:275
static DTYPE * dtype_types
Definition damagetype.c:38
int dtype_get(const char *name)
Gets the id of a dtype based on name.
Definition damagetype.c:157
void dtype_free(void)
Frees the dtype stack.
Definition damagetype.c:233
#define DTYPE_XML_ID
Definition damagetype.c:21
static int DTYPE_parse(DTYPE *temp, const char *file)
Parses an XML file containing a DTYPE.
Definition damagetype.c:65
static DTYPE * dtype_validType(int type)
Gets the damage type.
Definition damagetype.c:172
const char * dtype_damageTypeToStr(int type)
Gets the human readable string from damage type.
Definition damagetype.c:184
static int dtype_cmp(const void *p1, const void *p2)
For sorting and bsearching.
Definition damagetype.c:51
Header file with generic functions and naev-specifics.
#define MAX(x, y)
Definition naev.h:37
char ** ndata_listRecursive(const char *path)
Lists all the visible files in a directory, at any depth.
Definition ndata.c:286
xmlDocPtr xml_parsePhysFS(const char *filename)
Analogous to xmlParseMemory/xmlParseFile.
Definition nxml.c:70
static const double d[]
Definition rng.c:263
size_t ss_offsetFromType(ShipStatsType type)
Gets the offset from type.
Definition shipstats.c:714
ShipStatsType ss_typeFromName(const char *name)
Gets the type from the name.
Definition shipstats.c:725
A damage type.
Definition damagetype.c:28
size_t soffset
Definition damagetype.c:34
double knock
Definition damagetype.c:33
double adam
Definition damagetype.c:32
char * name
Definition damagetype.c:29
char * display
Definition damagetype.c:30
size_t aoffset
Definition damagetype.c:35
double sdam
Definition damagetype.c:31
Core damage that an outfit does.
Definition outfit.h:168
int type
Definition outfit.h:169
double damage
Definition outfit.h:173
Represents ship statistics, properties ship can use.
Definition shipstats.h:229