naev 0.11.5
commodity.c
Go to the documentation of this file.
1/*
2 * See Licensing and Copyright notice in naev.h
3 */
10#include <stdio.h>
11#include <stdint.h>
12#include "physfs.h"
13
14#include "naev.h"
17#include "commodity.h"
18
19#include "conf.h"
20#include "array.h"
21#include "economy.h"
22#include "gatherable.h"
23#include "hook.h"
24#include "log.h"
25#include "ndata.h"
26#include "nstring.h"
27#include "ntime.h"
28#include "nxml.h"
29#include "pilot.h"
30#include "player.h"
31#include "rng.h"
32#include "space.h"
33#include "spfx.h"
34
35#define XML_COMMODITY_ID "commodity"
36#define CRED_TEXT_MAX (ECON_CRED_STRLEN-4) /* Maximum length of just credits2str text, no markup */
37
38/* commodity stack */
40static Commodity** commodity_temp = NULL;
42/* @TODO remove externs. */
43extern int *econ_comm;
44
45/*
46 * Prototypes.
47 */
48/* Commodity. */
49static void commodity_freeOne( Commodity* com );
50static int commodity_parse( Commodity *temp, const char *filename );
51
59void credits2str( char *str, credits_t credits, int decimals )
60{
61 if (decimals < 0) {
62 /* TODO support , separator like fmt.credits(). */
63 snprintf( str, CRED_TEXT_MAX, _("%.*f ¤"), 0, (double)credits );
64 }
65 else if (credits >= 1000000000000000000LL)
66 snprintf( str, CRED_TEXT_MAX, _("%.*f E¤"), decimals, (double)credits / 1e18 );
67 else if (credits >= 1000000000000000LL)
68 snprintf( str, CRED_TEXT_MAX, _("%.*f P¤"), decimals, (double)credits / 1e15 );
69 else if (credits >= 1000000000000LL)
70 snprintf( str, CRED_TEXT_MAX, _("%.*f T¤"), decimals, (double)credits / 1e12 );
71 else if (credits >= 1000000000L)
72 snprintf( str, CRED_TEXT_MAX, _("%.*f G¤"), decimals, (double)credits / 1e9 );
73 else if (credits >= 1000000)
74 snprintf( str, CRED_TEXT_MAX, _("%.*f M¤"), decimals, (double)credits / 1e6 );
75 else if (credits >= 1000)
76 snprintf( str, CRED_TEXT_MAX, _("%.*f k¤"), decimals, (double)credits / 1e3 );
77 else
78 snprintf (str, CRED_TEXT_MAX, _("%.*f ¤"), decimals, (double)credits );
79}
80
89void price2str(char *str, credits_t price, credits_t credits, int decimals )
90{
91 char buf[ CRED_TEXT_MAX ];
92
93 if (price <= credits) {
94 credits2str( str, price, decimals );
95 return;
96 }
97
98 credits2str( buf, price, decimals );
99 snprintf( str, ECON_CRED_STRLEN, "#r%s#0", (char*)buf );
100}
101
108void tonnes2str( char *str, int tonnes )
109{
110 snprintf( str, ECON_MASS_STRLEN, n_( "%d tonne", "%d tonnes", tonnes ), tonnes );
111}
112
117{
118 return commodity_stack;
119}
120
127Commodity* commodity_get( const char* name )
128{
129 Commodity *c = commodity_getW( name );
130 if (c!=NULL)
131 return c;
132 WARN(_("Commodity '%s' not found in stack"), name);
133 return NULL;
134}
135
142Commodity* commodity_getW( const char* name )
143{
144 for (int i=0; i<array_size(commodity_stack); i++)
145 if (strcmp(commodity_stack[i].name, name) == 0)
146 return &commodity_stack[i];
147 for (int i=0; i<array_size(commodity_temp); i++)
148 if (strcmp(commodity_temp[i]->name, name) == 0)
149 return commodity_temp[i];
150 return NULL;
151}
152
159{
160 return array_size(econ_comm);
161}
162
170{
171 if (indx < 0 || indx >= array_size(econ_comm)) {
172 WARN(_("Commodity with index %d not found"),indx);
173 return NULL;
174 }
175 return &commodity_stack[econ_comm[indx]];
176}
177
183static void commodity_freeOne( Commodity* com )
184{
185 CommodityModifier *this,*next;
186 free(com->name);
187 free(com->description);
188 free(com->price_ref);
191 next = com->spob_modifier;
192 com->spob_modifier = NULL;
193 while (next != NULL ) {
194 this = next;
195 next = this->next;
196 free(this->name);
197 free(this);
198 }
199 next = com->faction_modifier;
200 com->faction_modifier = NULL;
201 while (next != NULL ) {
202 this=next;
203 next=this->next;
204 free(this->name);
205 free(this);
206 }
207 array_free(com->illegalto);
208 /* Clear the memory. */
209 memset(com, 0, sizeof(Commodity));
210}
211
219int commodity_compareTech( const void *commodity1, const void *commodity2 )
220{
221 const Commodity *c1, *c2;
222
223 /* Get commodities. */
224 c1 = * (const Commodity**) commodity1;
225 c2 = * (const Commodity**) commodity2;
226
227 /* Compare price. */
228 if (c1->price < c2->price)
229 return +1;
230 else if (c1->price > c2->price)
231 return -1;
232
233 /* It turns out they're the same. */
234 return strcmp( c1->name, c2->name );
235}
236
241{
244 for (int i=0; i<n; i++) {
246 if (commodity_isFlag(c,COMMODITY_FLAG_STANDARD))
247 array_push_back( &com, c );
248 }
249 return com;
250}
251
259static int commodity_parse( Commodity *temp, const char *filename )
260{
261 xmlNodePtr node, parent;
262 xmlDocPtr doc;
263
264 doc = xml_parsePhysFS( filename );
265 if (doc == NULL)
266 return -1;
267
268 parent = doc->xmlChildrenNode; /* Commodities node */
269 if (strcmp((char*)parent->name,XML_COMMODITY_ID)) {
270 ERR(_("Malformed %s file: missing root element '%s'"), filename, XML_COMMODITY_ID);
271 return -1;
272 }
273
274 /* Clear memory and set defaults. */
275 memset( temp, 0, sizeof(Commodity) );
276 temp->period = 200;
277 temp->price_mod = 1.;
278
279 /* Parse body. */
280 node = parent->xmlChildrenNode;
281 do {
282 xml_onlyNodes(node);
283
284 xmlr_strd(node, "name", temp->name);
285 xmlr_strd(node, "description", temp->description);
286 xmlr_int(node, "price", temp->price);
287 xmlr_float(node, "price_mod", temp->price_mod);
288 xmlr_strd(node, "price_ref", temp->price_ref);
289
290 if (xml_isNode(node,"gfx_space")) {
291 temp->gfx_space = xml_parseTexture( node,
292 COMMODITY_GFX_PATH"space/%s", 1, 1, OPENGL_TEX_MIPMAPS );
293 continue;
294 }
295 if (xml_isNode(node,"gfx_store")) {
296 temp->gfx_store = xml_parseTexture( node,
297 COMMODITY_GFX_PATH"%s", 1, 1, OPENGL_TEX_MIPMAPS );
298 continue;
299 }
300 if (xml_isNode(node, "standard")) {
301 commodity_setFlag( temp, COMMODITY_FLAG_STANDARD );
302 continue;
303 }
304 if (xml_isNode(node, "always_can_sell")) {
305 commodity_setFlag( temp, COMMODITY_FLAG_ALWAYS_CAN_SELL );
306 continue;
307 }
308 if (xml_isNode(node, "price_constant")) {
309 commodity_setFlag( temp, COMMODITY_FLAG_PRICE_CONSTANT );
310 continue;
311 }
312 if (xml_isNode(node, "illegalto")) {
313 xmlNodePtr cur = node->xmlChildrenNode;
314 temp->illegalto = array_create( int );
315 do {
316 xml_onlyNodes(cur);
317 if (xml_isNode(cur, "faction")) {
318 int f = faction_get( xml_get(cur) );
319 array_push_back( &temp->illegalto, f );
320 }
321 } while (xml_nextNode(node));
322 continue;
323 }
324 xmlr_float(node, "population_modifier", temp->population_modifier);
325 xmlr_float(node, "period", temp->period);
326 if (xml_isNode(node, "spob_modifier")) {
327 CommodityModifier *newdict = malloc(sizeof(CommodityModifier));
328 newdict->next = temp->spob_modifier;
329 xmlr_attr_strd(node, "type", newdict->name);
330 newdict->value = xml_getFloat(node);
331 temp->spob_modifier = newdict;
332 continue;
333 }
334 if (xml_isNode(node, "faction_modifier")) {
335 CommodityModifier *newdict = malloc(sizeof(CommodityModifier));
336 newdict->next = temp->faction_modifier;
337 xmlr_attr_strd(node, "type", newdict->name);
338 newdict->value = xml_getFloat(node);
339 temp->faction_modifier = newdict;
340 continue;
341 }
342
343 WARN(_("Commodity '%s' has unknown node '%s'"),temp->name, node->name);
344 } while (xml_nextNode(node));
345
346 if (temp->name == NULL)
347 WARN( _("Commodity from %s has invalid or no name"), COMMODITY_DATA_PATH);
348
349 if ((temp->price > 0) || (temp->price_ref != NULL)) {
350 if (temp->gfx_store == NULL) {
351 WARN(_("No <gfx_store> node found, using default texture for commodity \"%s\""), temp->name);
352 temp->gfx_store = gl_newImage( COMMODITY_GFX_PATH"_default.webp", 0 );
353 }
354 }
355 if (temp->gfx_space == NULL)
356 temp->gfx_space = gl_newImage( COMMODITY_GFX_PATH"space/_default.webp", 0 );
357
358 if (temp->price_ref != NULL) {
359 if (temp->price > 0.)
360 WARN(_("Commodity '%s' is setting both 'price' and 'price_ref'."),temp->name);
361 }
362
363#if 0 /* shouldn't be needed atm */
364#define MELEMENT(o,s) if (o) WARN( _("Commodity '%s' missing '"s"' element"), temp->name)
365 MELEMENT(temp->description==NULL,"description");
366 MELEMENT(temp->high==0,"high");
367 MELEMENT(temp->medium==0,"medium");
368 MELEMENT(temp->low==0,"low");
369#undef MELEMENT
370#endif
371
372 xmlFreeDoc(doc);
373
374 return 0;
375}
376
384int commodity_checkIllegal( const Commodity *com, int faction )
385{
386 for (int i=0; i<array_size(com->illegalto); i++) {
387 if (com->illegalto[i] == faction)
388 return 1;
389 }
390 return 0;
391}
392
399int commodity_isTemp( const char* name )
400{
401 for (int i=0; i<array_size(commodity_temp); i++)
402 if (strcmp(commodity_temp[i]->name, name) == 0)
403 return 1;
404 for (int i=0; i<array_size(commodity_stack); i++)
405 if (strcmp(commodity_stack[i].name,name)==0)
406 return 0;
407
408 WARN(_("Commodity '%s' not found in stack"), name);
409 return 0;
410}
411
419Commodity* commodity_newTemp( const char* name, const char* desc )
420{
421 Commodity **c;
422 if (commodity_temp == NULL)
424
426 *c = calloc( 1, sizeof(Commodity) );
427 (*c)->istemp = 1;
428 (*c)->name = strdup(name);
429 (*c)->description = strdup(desc);
430 return *c;
431}
432
436int commodity_tempIllegalto( Commodity *com, int faction )
437{
438 if (!com->istemp) {
439 WARN(_("Trying to modify temporary commodity '%s'!"), com->name);
440 return -1;
441 }
442
443 if (com->illegalto==NULL)
444 com->illegalto = array_create( int );
445
446 /* Don't add twice. */
447 for (int i=0; i<array_size(com->illegalto); i++) {
448 if (com->illegalto[i] == faction)
449 return 0;
450 }
451
452 array_push_back( &com->illegalto, faction );
453
454 return 0;
455}
456
463{
464 char **commodities = ndata_listRecursive( COMMODITY_DATA_PATH );
465 Uint32 time = SDL_GetTicks();
466
468 econ_comm = array_create( int );
469
471
472 for (int i=0; i<array_size(commodities); i++) {
473 Commodity c;
474 int ret = commodity_parse( &c, commodities[i] );
475 if (ret == 0) {
477
478 /* See if should get added to commodity list. */
479 if (c.price > 0.) {
480 int *e = &array_grow( &econ_comm );
482 }
483
484 /* Render if necessary. */
486 }
487 free( commodities[i] );
488 }
489 array_free( commodities );
490
491 if (conf.devmode) {
492 time = SDL_GetTicks() - time;
493 DEBUG( n_( "Loaded %d Commodity in %.3f s", "Loaded %d Commodities in %.3f s", array_size(commodity_stack) ), array_size(commodity_stack), time/1000. );
494 }
495 else
496 DEBUG( n_( "Loaded %d Commodity", "Loaded %d Commodities", array_size(commodity_stack) ), array_size(commodity_stack) );
497
498 return 0;
499}
500
504void commodity_free (void)
505{
506 for (int i=0; i<array_size(commodity_stack); i++)
509 commodity_stack = NULL;
510
511 for (int i=0; i<array_size(commodity_temp); i++) {
513 free( commodity_temp[i] );
514 }
516 commodity_temp = NULL;
517
518 /* More clean up. */
520 econ_comm = NULL;
521
523}
Provides macros to work with dynamic arrays.
#define array_free(ptr_array)
Frees memory allocated and sets array to NULL.
Definition array.h:158
#define array_create_size(basic_type, capacity)
Creates a new dynamic array of ‘basic_type’ with an initial capacity.
Definition array.h:102
static ALWAYS_INLINE int array_size(const void *array)
Returns number of elements in the array.
Definition array.h:168
#define array_grow(ptr_array)
Increases the number of elements by one and returns the last element.
Definition array.h:119
#define array_push_back(ptr_array, element)
Adds a new element at the end of the array.
Definition array.h:129
#define array_create(basic_type)
Creates a new dynamic array of ‘basic_type’.
Definition array.h:93
Commodity * commodity_getAll(void)
Gets all the commodities.
Definition commodity.c:116
Commodity * commodity_get(const char *name)
Gets a commodity by name.
Definition commodity.c:127
#define XML_COMMODITY_ID
Definition commodity.c:35
Commodity * commodity_newTemp(const char *name, const char *desc)
Creates a new temporary commodity.
Definition commodity.c:419
static void commodity_freeOne(Commodity *com)
Frees a commodity.
Definition commodity.c:183
static Commodity ** commodity_temp
Definition commodity.c:40
void commodity_free(void)
Frees all the loaded commodities.
Definition commodity.c:504
Commodity * commodity_getByIndex(const int indx)
Gets a commodity by index.
Definition commodity.c:169
static int commodity_parse(Commodity *temp, const char *filename)
Loads a commodity.
Definition commodity.c:259
void credits2str(char *str, credits_t credits, int decimals)
Converts credits to a usable string for displaying.
Definition commodity.c:59
void tonnes2str(char *str, int tonnes)
Converts tonnes to a usable string for displaying.
Definition commodity.c:108
int commodity_getN(void)
Return the number of commodities globally.
Definition commodity.c:158
int commodity_compareTech(const void *commodity1, const void *commodity2)
Function meant for use with C89, C99 algorithm qsort().
Definition commodity.c:219
void price2str(char *str, credits_t price, credits_t credits, int decimals)
Given a price and on-hand credits, outputs a colourized string.
Definition commodity.c:89
int commodity_load(void)
Loads all the commodity data.
Definition commodity.c:462
int * econ_comm
Definition economy.c:61
Commodity ** standard_commodities(void)
Return an array (array.h) of standard commodities. Free with array_free. (Don't free contents....
Definition commodity.c:240
int commodity_checkIllegal(const Commodity *com, int faction)
Checks to see if a commodity is illegal to a faction.
Definition commodity.c:384
Commodity * commodity_getW(const char *name)
Gets a commodity by name without warning.
Definition commodity.c:142
Commodity * commodity_stack
Definition commodity.c:39
int commodity_tempIllegalto(Commodity *com, int faction)
Makes a temporary commodity illegal to something.
Definition commodity.c:436
int commodity_isTemp(const char *name)
Checks to see if a commodity is temporary.
Definition commodity.c:399
int faction_get(const char *name)
Gets a faction ID by name.
Definition faction.c:184
int gatherable_load(void)
Loads the gatherable system.
Definition gatherable.c:39
void gatherable_cleanup(void)
Cleans up after the gatherable system.
Definition gatherable.c:49
void naev_renderLoadscreen(void)
Renders the loadscreen if necessary.
Definition naev.c:597
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:231
glTexture * xml_parseTexture(xmlNodePtr node, const char *path, int defsx, int defsy, const unsigned int flags)
Parses a texture handling the sx and sy elements.
Definition nxml.c:29
xmlDocPtr xml_parsePhysFS(const char *filename)
Analogous to xmlParseMemory/xmlParseFile.
Definition nxml.c:75
glTexture * gl_newImage(const char *path, const unsigned int flags)
Loads an image as a texture.
Definition opengl_tex.c:675
void gl_freeTexture(glTexture *texture)
Frees a texture.
Definition opengl_tex.c:862
static const double c[]
Definition rng.c:264
Represents a dictionary of values used to modify a commodity.
Definition commodity.h:32
Represents a commodity.
Definition commodity.h:43
char * description
Definition commodity.h:45
CommodityModifier * spob_modifier
Definition commodity.h:62
glTexture * gfx_store
Definition commodity.h:53
int * illegalto
Definition commodity.h:59
double population_modifier
Definition commodity.h:64
char * name
Definition commodity.h:44
CommodityModifier * faction_modifier
Definition commodity.h:65
double price_mod
Definition commodity.h:50
double price
Definition commodity.h:52
glTexture * gfx_space
Definition commodity.h:54
double period
Definition commodity.h:63
int istemp
Definition commodity.h:58
char * price_ref
Definition commodity.h:49
int devmode
Definition conf.h:157