16#if HAVE_SUITESPARSE_CS_H
17#include <suitesparse/cs.h>
37#define ECON_BASE_RES 30.
38#define ECON_SELF_RES 3.
39#define ECON_FACTION_MOD 0.1
40#define ECON_PROD_MODIFIER \
42#define ECON_PROD_VAR 0.01
97 const Spob *p, ntime_t tme )
111 return (credits_t)( price + 0.5 );
115 if ( commodity_isFlag( com, COMMODITY_FLAG_PRICE_CONSTANT ) )
134 WARN( _(
"Price for commodity '%s' not known." ), com->
name );
139 for ( i = 0; i <
array_size( p->commodities ); i++ ) {
140 if ( ( strcmp( p->commodities[i]->name, com->
name ) == 0 ) )
144 WARN( _(
"Price for commodity '%s' not known on this spob." ),
148 commPrice = &p->commodityPrice[i];
154 commPrice->
sysVariation * sin( 2. * M_PI * t / commPrice->sysPeriod ) +
156 sin( 2. * M_PI * t / commPrice->
spobPeriod ) );
157 return (credits_t)( price + 0.5 );
172 credits_t *mean,
double *std )
184 *mean = (credits_t)( (
double)*mean * com->
price_mod + 0.5 );
190 if ( commodity_isFlag( com, COMMODITY_FLAG_PRICE_CONSTANT ) ) {
206 WARN( _(
"Average price for commodity '%s' not known." ), com->
name );
213 for ( i = 0; i <
array_size( p->commodities ); i++ ) {
214 if ( ( strcmp( p->commodities[i]->name, com->
name ) == 0 ) )
218 WARN( _(
"Price for commodity '%s' not known on this spob." ),
224 commPrice = &p->commodityPrice[i];
225 if ( commPrice->
cnt > 0 ) {
226 *mean = (credits_t)( commPrice->
sum / commPrice->
cnt +
228 *std = ( sqrt( commPrice->
sum2 / commPrice->
cnt -
229 ( commPrice->
sum * commPrice->
sum ) /
230 ( commPrice->
cnt * commPrice->
cnt ) ) );
256 *mean = (credits_t)( (
double)*mean * com->
price_mod + 0.5 );
258 return ( (
double)ret * com->
price_mod + 0.5 );
262 if ( commodity_isFlag( com, COMMODITY_FLAG_PRICE_CONSTANT ) ) {
273 for (
int j = 0; j <
array_size( sys->spobs ); j++ ) {
274 const Spob *p = sys->spobs[j];
275 for (
int k = 0; k <
array_size( p->commodities ); k++ ) {
276 if ( ( strcmp( p->commodities[k]->name, com->
name ) != 0 ) )
279 if ( commPrice->
cnt > 0 ) {
280 av += commPrice->
sum / commPrice->
cnt;
281 av2 += commPrice->
sum * commPrice->
sum /
282 ( commPrice->
cnt * commPrice->
cnt );
291 av2 = sqrt( av2 / cnt - av * av );
292 *mean = (credits_t)( av + 0.5 );
295 WARN( _(
"Average price for commodity '%s' not known." ), com->
name );
310static double econ_calcJumpR( StarSystem *A, StarSystem *B )
318 R += (A->nebu_density + B->nebu_density) / 1000.;
319 R += (A->nebu_volatility + B->nebu_volatility) / 100.;
322 if ((A->faction != -1) && (B->faction != -1)) {
325 else if (
areAllies(A->faction, B->faction))
339static double econ_calcSysI(
unsigned int dt, StarSystem *sys,
int price )
343 double prodfactor, p;
347 ddt = (double)(dt / NTIME_UNIT_LENGTH);
351 for (i=0; i<sys->nspobs; i++) {
352 spob = sys->spobs[i];
353 if (spob_hasService(spob, SPOB_SERVICE_INHABITED)) {
358 prodfactor = spob->cur_prodfactor;
363 (spob->cur_prodfactor - prodfactor)*ddt;
365 spob->cur_prodfactor = prodfactor;
382static int econ_createGMatrix (
void)
391 WARN(_(
"Unable to create CSparse Matrix."));
399 for (
int j=0; j <
array_size(sys->jumps); j++) {
402 R = econ_calcJumpR( sys, sys->jumps[j].target );
407 ret = cs_entry( M, i, sys->jumps[j].target->id, -R );
409 WARN(_(
"Unable to enter CSparse Matrix Cell."));
410 ret = cs_entry( M, sys->jumps[j].target->id, i, -R );
412 WARN(_(
"Unable to enter CSparse Matrix Cell."));
417 cs_entry( M, i, i, Rsum );
422 econ_G = cs_compress( M );
424 WARN(_(
"Unable to create economy G Matrix."));
512 double scale, offset;
522 WARN(_(
"Out of Memory"));
541 ret = cs_qrsol( 3,
econ_G, X );
543 WARN(_(
"Failed to solve the Economy System."));
616 double base, scale, factor;
617 const char *factionname;
620 if ( !spob_hasService( spob, SPOB_SERVICE_COMMODITY ) )
625 WARN( _(
"Spob '%s' appears to have commodity '%s' defined, but no "
637 while ( cm != NULL ) {
638 if ( ( strcmp( spob->
class, cm->name ) == 0 ) ) {
644 commodityPrice->
price *= scale;
654 32 * ( spob->
gfx_spaceName[strlen( SPOB_GFX_SPACE_PATH )] % 32 ) +
661 strlen( SPOB_GFX_EXTERIOR_PATH ) - 19 ) /
672 factor = tanh( ( log( (
double)spob->
population ) - log( 1e8 ) ) / 2 );
674 commodityPrice->
price *= 1 + factor * base;
676 commodityPrice->
spobPeriod *= 1 + factor * 0.5;
685 while ( cm != NULL ) {
686 if ( strcmp( factionname, cm->name ) == 0 ) {
692 commodityPrice->
price *= scale;
716 for (
int i = 0; i <
array_size( sys->spobs ); i++ ) {
717 Spob *spob = sys->spobs[i];
725 1 / ( 1 - sys->radius / 300e3 );
739 for ( k = 0; k <
array_size( avprice ); k++ ) {
766 for ( k = 0; k <
array_size( avprice ); k++ ) {
769 avprice[k].sysPeriod /= avprice[k].
updateTime;
774 for (
int i = 0; i <
array_size( sys->spobs ); i++ ) {
775 Spob *spob = sys->spobs[i];
777 for ( k = 0; k <
array_size( avprice ); k++ ) {
790 sys->averagePrice = avprice;
800 StarSystem *neighbour;
809 for (
int i = 0; i <
array_size( sys->jumps );
811 neighbour = sys->jumps[i].target;
812 for (
int k = 0; k <
array_size( neighbour->averagePrice ); k++ ) {
813 if ( ( strcmp( neighbour->averagePrice[k].name, avprice[j].
name ) ==
815 price += neighbour->averagePrice[k].price;
822 avprice[j].
sum = price / n;
836 for (
int j = 0; j <
array_size( avprice ); j++ ) {
838 avprice[j].
price = 0.5 * ( avprice[j].
price + avprice[j].
sum );
841 for (
int i = 0; i <
array_size( sys->spobs ); i++ ) {
842 Spob *spob = sys->spobs[i];
844 for (
int k = 0; k <
array_size( avprice ); k++ ) {
849 0.75 * avprice[k].
price );
863 sys->averagePrice = NULL;
875 for (
int j = 0; j <
array_size( sys->spobs ); j++ ) {
876 Spob *spob = sys->spobs[j];
911 while ( next != NULL ) {
919 while ( next != NULL ) {
932void economy_initialiseSingleSystem( StarSystem *sys,
Spob *spob )
939void economy_averageSeenPrices(
const Spob *p )
942 for (
int i = 0; i <
array_size( p->commodities ); i++ ) {
953 cp->
sum2 += price * price;
958void economy_averageSeenPricesAtTime(
const Spob *p,
const ntime_t tupdate )
961 for (
int i = 0; i <
array_size( p->commodities ); i++ ) {
971 cp->
sum2 += price * price;
983 for (
int j = 0; j <
array_size( sys->spobs ); j++ ) {
984 Spob *p = sys->spobs[j];
985 for (
int k = 0; k <
array_size( p->commodityPrice ); k++ ) {
1004 for (
int k = 0; k <
array_size( p->commodityPrice ); k++ ) {
1021 xmlNodePtr node = parent->xmlChildrenNode;
1026 if ( xml_isNode( node,
"economy" ) ) {
1027 xmlNodePtr cur = node->xmlChildrenNode;
1030 xml_onlyNodes( cur );
1031 if ( xml_isNode( cur,
"system" ) ) {
1033 xmlNodePtr nodeSpob = cur->xmlChildrenNode;
1035 xml_onlyNodes( nodeSpob );
1036 if ( xml_isNode( nodeSpob,
"spob" ) ) {
1037 xmlr_attr_strd( nodeSpob,
"name", str );
1040 WARN( _(
"Spob '%s' has saved economy data but doesn't "
1046 xmlNodePtr nodeCommodity = nodeSpob->xmlChildrenNode;
1048 xml_onlyNodes( nodeCommodity );
1049 if ( xml_isNode( nodeCommodity,
"commodity" ) ) {
1050 xmlr_attr_strd( nodeCommodity,
"name", str );
1063 xmlr_attr_float( nodeCommodity,
"sum", cp->
sum );
1064 xmlr_attr_float( nodeCommodity,
"sum2",
1066 xmlr_attr_int( nodeCommodity,
"cnt", cp->
cnt );
1067 xmlr_attr_long( nodeCommodity,
"time",
1071 }
while ( xml_nextNode( nodeCommodity ) );
1073 }
while ( xml_nextNode( nodeSpob ) );
1074 }
else if ( xml_isNode( cur,
"lastPurchase" ) ) {
1075 xmlr_attr_strd( cur,
"name", str );
1078 c->lastPurchasePrice = xml_getLong( cur );
1082 }
while ( xml_nextNode( cur ) );
1084 }
while ( xml_nextNode( node ) );
1097 xmlw_startElem( writer,
"economy" );
1100 xmlw_startElem( writer,
"lastPurchase" );
1103 xmlw_endElem( writer );
1109 for (
int j = 0; j <
array_size( sys->spobs ); j++ ) {
1110 Spob *p = sys->spobs[j];
1112 for (
int k = 0; k <
array_size( p->commodities ); k++ ) {
1116 if ( doneSys == 0 ) {
1118 xmlw_startElem( writer,
"system" );
1119 xmlw_attr( writer,
"name",
"%s", sys->name );
1121 if ( doneSpob == 0 ) {
1123 xmlw_startElem( writer,
"spob" );
1124 xmlw_attr( writer,
"name",
"%s", p->name );
1126 xmlw_startElem( writer,
"commodity" );
1127 xmlw_attr( writer,
"name",
"%s", p->commodities[k]->name );
1128 xmlw_attr( writer,
"sum",
"%f", cp->
sum );
1129 xmlw_attr( writer,
"sum2",
"%f", cp->
sum2 );
1130 xmlw_attr( writer,
"cnt",
"%d", cp->
cnt );
1131 xmlw_attr( writer,
"time",
"%" PRIu64, cp->
updateTime );
1132 xmlw_endElem( writer );
1135 if ( doneSpob == 1 )
1136 xmlw_endElem( writer );
1139 xmlw_endElem( writer );
1141 xmlw_endElem( writer );
Provides macros to work with dynamic arrays.
#define array_free(ptr_array)
Frees memory allocated and sets array to NULL.
static ALWAYS_INLINE int array_size(const void *array)
Returns number of elements in the array.
#define array_grow(ptr_array)
Increases the number of elements by one and returns the last element.
#define array_shrink(ptr_array)
Shrinks memory to fit only ‘size’ elements.
#define array_create(basic_type)
Creates a new dynamic array of ‘basic_type’.
Commodity * commodity_get(const char *name)
Gets a commodity by name.
Commodity * commodity_stack
StarSystem * systems_stack
static void economy_smoothCommodityPrice(StarSystem *sys)
Calculates smoothing of commodity price based on neighbouring systems.
static int economy_calcPrice(Spob *spob, Commodity *commodity, CommodityPrice *commodityPrice)
Used during startup to set price and variation of the economy, depending on spob information.
int economy_init(void)
Initializes the economy.
void economy_clearKnown(void)
Clears all system knowledge.
static int econ_initialized
int economy_update(unsigned int dt)
Updates the economy.
void economy_addQueuedUpdate(void)
Increments the queued update counter.
int economy_sysLoad(xmlNodePtr parent)
Loads player's economy properties from an XML node.
void economy_destroy(void)
Destroys the economy.
static void economy_calcUpdatedCommodityPrice(StarSystem *sys)
Modifies commodity price based on neighbouring systems.
credits_t economy_getPriceAtTime(const Commodity *com, const StarSystem *sys, const Spob *p, ntime_t tme)
Gets the price of a good on a spob in a system.
static void economy_modifySystemCommodityPrice(StarSystem *sys)
Modifies commodity price based on system characteristics.
int economy_getAveragePrice(const Commodity *com, credits_t *mean, double *std)
Gets the average price of a good as seen by the player (anywhere).
void economy_initialiseCommodityPrices(void)
Initialises commodity prices for the sinusoidal economy model.
void economy_clearSingleSpob(Spob *p)
Clears all economy knowledge of a given spob. Used by the unidiff system.
#define ECON_PROD_MODIFIER
int economy_execQueued(void)
Calls economy_refresh if an economy update is queued.
credits_t economy_getPrice(const Commodity *com, const StarSystem *sys, const Spob *p)
Gets the price of a good on a spob in a system.
int economy_sysSave(xmlTextWriterPtr writer)
Saves what is needed to be saved for economy.
int economy_refresh(void)
Regenerates the economy matrix. Should be used if the universe changes in any permanent way.
int economy_getAverageSpobPrice(const Commodity *com, const Spob *p, credits_t *mean, double *std)
Gets the average price of a good on a spob in a system, using a rolling average over the times the pl...
int areEnemies(int a, int b)
Checks whether two factions are enemies.
const char * faction_name(int f)
Gets a factions "real" (internal) name.
int areAllies(int a, int b)
Checks whether two factions are allies or not.
Header file with generic functions and naev-specifics.
ntime_t ntime_get(void)
Gets the current time.
double ntime_convertSeconds(ntime_t t)
Converts the time to seconds.
Spob * spob_get(const char *spobname)
Gets a spob based on its name.
Represents a dictionary of values used to modify a commodity.
CommodityModifier * spob_modifier
double population_modifier
CommodityModifier * faction_modifier
Represents a Space Object (SPOB), including and not limited to planets, stations, wormholes,...
CommodityPrice * commodityPrice