naev 0.12.5
difficulty.c
1/*
2 * See Licensing and Copyright notice in naev.h
3 */
10#include <stdlib.h>
11
12#include "naev.h"
14
15#include "difficulty.h"
16
17#include "array.h"
18#include "conf.h"
19#include "ndata.h"
20#include "nxml.h"
21
22#define DIFFICULTY_XML_ID "difficulty"
23
24static Difficulty *difficulty_stack = NULL;
25static const Difficulty *difficulty_default = NULL;
26static const Difficulty *difficulty_global = NULL;
27static const Difficulty *difficulty_local = NULL;
28static const Difficulty *difficulty_current = NULL;
29
33int difficulty_load( void )
34{
35 char **difficulty_files = ndata_listRecursive( DIFFICULTY_PATH );
36 difficulty_stack = array_create( Difficulty );
37 for ( int i = 0; i < array_size( difficulty_files ); i++ ) {
39 xmlDocPtr doc;
40 xmlNodePtr node, cur;
41
42 /* Load and read the data. */
43 doc = xml_parsePhysFS( difficulty_files[i] );
44 if ( doc == NULL )
45 continue;
46
47 /* Check to see if document exists. */
48 node = doc->xmlChildrenNode;
49 if ( !xml_isNode( node, DIFFICULTY_XML_ID ) ) {
50 WARN( _( "Malformed '%s' file: missing root element '%s'" ),
51 difficulty_files[i], DIFFICULTY_XML_ID );
52 xmlFreeDoc( doc );
53 continue;
54 }
55
56 /* Initialize. */
57 memset( &d, 0, sizeof( Difficulty ) );
58
59 /* Properties. */
60 xmlr_attr_strd( node, "name", d.name );
61 xmlr_attr_int_opt( node, "default", d.def );
62
63 /* Get the stats. */
64 cur = node->xmlChildrenNode;
65 do {
66 xml_onlyNodes( cur );
67
68 /* Load the description. */
69 xmlr_strd( cur, "description", d.description );
70
71 /* Rest should be ship stats. */
72 ShipStatList *ll = ss_listFromXML( cur );
73 if ( ll != NULL ) {
74 ll->next = d.stats;
75 d.stats = ll;
76 continue;
77 }
78 WARN( _( "Difficulty '%s' has unknown node '%s'" ), d.name,
79 cur->name );
80 } while ( xml_nextNode( cur ) );
81
82 xmlFreeDoc( doc );
83
84 array_push_back( &difficulty_stack, d );
85 }
86
87 /* Find out default. */
88 for ( int i = 0; i < array_size( difficulty_stack ); i++ ) {
89 Difficulty *dd = &difficulty_stack[i];
90 if ( dd->def ) {
91 if ( difficulty_default )
92 WARN( _( "More than one difficulty with default flag set!" ) );
93 difficulty_default = dd;
94 }
95 }
96 if ( difficulty_default == NULL ) {
97 WARN( _( "No default difficulty set!" ) );
98 difficulty_default = difficulty_stack;
99 }
100 difficulty_current = difficulty_default; /* Load default. */
101
102 /* Load the global difficulty. */
103 if ( conf.difficulty != NULL )
104 difficulty_setGlobal( difficulty_get( conf.difficulty ) );
105
106 for ( int i = 0; i < array_size( difficulty_files ); i++ )
107 free( difficulty_files[i] );
108 array_free( difficulty_files );
109 return 0;
110}
111
115void difficulty_free( void )
116{
117 for ( int i = 0; i < array_size( difficulty_stack ); i++ ) {
118 Difficulty *d = &difficulty_stack[i];
119 free( d->name );
120 free( d->description );
121 ss_free( d->stats );
122 }
123 array_free( difficulty_stack );
124}
125
129const Difficulty *difficulty_cur( void )
130{
131 return difficulty_current;
132}
133
137const Difficulty *difficulty_getAll( void )
138{
139 return difficulty_stack;
140}
141
142static const Difficulty *difficulty_getDefault( void )
143{
144 if ( difficulty_global != NULL )
145 return difficulty_global;
146 else
147 return difficulty_default;
148}
149
153const Difficulty *difficulty_get( const char *name )
154{
155 if ( name == NULL )
156 return difficulty_getDefault();
157 for ( int i = 0; i < array_size( difficulty_stack ); i++ ) {
158 const Difficulty *d = &difficulty_stack[i];
159 if ( strcmp( name, d->name ) == 0 )
160 return d;
161 }
162 WARN( _( "Unknown difficulty setting '%s'" ), name );
163 return difficulty_default;
164}
165
166static void difficulty_update( void )
167{
168 if ( difficulty_local != NULL )
169 difficulty_current = difficulty_local;
170 else if ( difficulty_global != NULL )
171 difficulty_current = difficulty_global;
172 else
173 difficulty_current = difficulty_default;
174}
175
179void difficulty_setGlobal( const Difficulty *d )
180{
181 difficulty_global = d;
182 difficulty_update();
183}
184
188void difficulty_setLocal( const Difficulty *d )
189{
190 difficulty_local = d;
191 difficulty_update();
192}
193
199char *difficulty_display( const Difficulty *d )
200{
201 int l;
202 char *display = malloc( STRMAX );
203 l = scnprintf( display, STRMAX, _( "Difficulty %s" ), _( d->name ) );
204 l += scnprintf( &display[l], STRMAX - l, "\n" );
205 if ( d->description != NULL )
206 l += scnprintf( &display[l], STRMAX - l, "%s\n", _( d->description ) );
207 l += scnprintf( &display[l], STRMAX - l,
208 _( "This difficulty applies the following effect to the "
209 "player ships:" ) );
210 ss_statsListDesc( d->stats, &display[l], STRMAX - l, 1 );
211 return display;
212}
213
217int difficulty_apply( ShipStats *s )
218{
219 return ss_statsMergeFromList( s, difficulty_current->stats );
220}
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_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
Header file with generic functions and naev-specifics.
char ** ndata_listRecursive(const char *path)
Lists all the visible files in a directory, at any depth.
Definition ndata.c:286
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
xmlDocPtr xml_parsePhysFS(const char *filename)
Analogous to xmlParseMemory/xmlParseFile.
Definition nxml.c:70
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
int ss_statsMergeFromList(ShipStats *stats, const ShipStatList *list)
Updates a stat structure from a stat list.
Definition shipstats.c:666
ShipStatList * ss_listFromXML(xmlNodePtr node)
Creates a shipstat list element from an xml node.
Definition shipstats.c:353
Represents relative ship statistics as a linked list.
Definition shipstats.h:198
struct ShipStatList_ * next
Definition shipstats.h:199
Represents ship statistics, properties ship can use.
Definition shipstats.h:229