17#if HAVE_SUITESPARSE_CS_H
18#include <suitesparse/cs.h>
43#define ECON_BASE_RES 30.
44#define ECON_SELF_RES 3.
45#define ECON_FACTION_MOD 0.1
46#define ECON_PROD_MODIFIER 500000.
47#define ECON_PROD_VAR 0.01
86 const StarSystem *sys,
const Spob *p )
102 const StarSystem *sys,
const Spob *p, ntime_t tme )
116 return (credits_t) (price+0.5);
120 if (commodity_isFlag(com, COMMODITY_FLAG_PRICE_CONSTANT))
139 WARN(_(
"Price for commodity '%s' not known."), com->
name);
144 for (i=0; i<
array_size(p->commodities); i++) {
145 if ((strcmp(p->commodities[i]->name, com->
name)==0))
149 WARN(_(
"Price for commodity '%s' not known on this spob."), com->
name);
152 commPrice = &p->commodityPrice[i];
157 * sin(2. * M_PI * t / commPrice->sysPeriod)
159 * sin(2. * M_PI * t / commPrice->
spobPeriod));
160 return (credits_t) (price+0.5);
182 *mean = (credits_t) ((
double)*mean*com->
price_mod+0.5);
188 if (commodity_isFlag(com, COMMODITY_FLAG_PRICE_CONSTANT)) {
204 WARN(_(
"Average price for commodity '%s' not known."), com->
name);
211 for (i=0; i<
array_size(p->commodities); i++) {
212 if ((strcmp(p->commodities[i]->name, com->
name) == 0))
216 WARN(_(
"Price for commodity '%s' not known on this spob."), com->
name);
221 commPrice = &p->commodityPrice[i];
222 if (commPrice->
cnt > 0) {
223 *mean = (credits_t)(commPrice->
sum/commPrice->
cnt + 0.5);
224 *std = (sqrt(commPrice->
sum2 / commPrice->
cnt
225 - (commPrice->
sum * commPrice->
sum)
226 / (commPrice->
cnt * commPrice->
cnt)));
255 *mean = (credits_t) ((
double)*mean*com->
price_mod+0.5);
261 if (commodity_isFlag(com, COMMODITY_FLAG_PRICE_CONSTANT)) {
277 WARN(_(
"Average price for commodity '%s' not known."), com->
name);
284 for (
int j=0; j<
array_size(sys->spobs); j++) {
285 Spob *p = sys->spobs[j];
288 for (k=0; k<
array_size(p->commodities); k++) {
289 if ((strcmp(p->commodities[k]->name, com->
name) == 0 ))
293 commPrice=&p->commodityPrice[k];
294 if ( commPrice->
cnt>0) {
295 av += commPrice->
sum/commPrice->
cnt;
296 av2 += commPrice->
sum*commPrice->
sum/(commPrice->
cnt*commPrice->
cnt);
304 av2 = sqrt(av2/cnt - av*av);
306 *mean = (credits_t)(av + 0.5);
319static double econ_calcJumpR( StarSystem *A, StarSystem *B )
327 R += (A->nebu_density + B->nebu_density) / 1000.;
328 R += (A->nebu_volatility + B->nebu_volatility) / 100.;
331 if ((A->faction != -1) && (B->faction != -1)) {
334 else if (
areAllies(A->faction, B->faction))
348static double econ_calcSysI(
unsigned int dt, StarSystem *sys,
int price )
352 double prodfactor, p;
356 ddt = (double)(dt / NTIME_UNIT_LENGTH);
360 for (i=0; i<sys->nspobs; i++) {
361 spob = sys->spobs[i];
362 if (spob_hasService(spob, SPOB_SERVICE_INHABITED)) {
367 prodfactor = spob->cur_prodfactor;
372 (spob->cur_prodfactor - prodfactor)*ddt;
374 spob->cur_prodfactor = prodfactor;
391static int econ_createGMatrix (
void)
402 ERR(_(
"Unable to create CSparse Matrix."));
413 R = econ_calcJumpR( sys, sys->jumps[j].target );
418 ret = cs_entry( M, i, sys->jumps[j].target->id, -R );
420 WARN(_(
"Unable to enter CSparse Matrix Cell."));
421 ret = cs_entry( M, sys->jumps[j].target->id, i, -R );
423 WARN(_(
"Unable to enter CSparse Matrix Cell."));
428 cs_entry( M, i, i, Rsum );
433 econ_G = cs_compress( M );
435 ERR(_(
"Unable to create economy G Matrix."));
522 double scale, offset;
532 WARN(_(
"Out of Memory"));
551 ret = cs_qrsol( 3,
econ_G, X );
553 WARN(_(
"Failed to solve the Economy System."));
624 double base, scale, factor;
625 const char *factionname;
628 if (!spob_hasService( spob, SPOB_SERVICE_COMMODITY ))
633 WARN(_(
"Spob '%s' appears to have commodity '%s' defined, but no faction."), spob->
name, commodity->
name);
644 if ((strcmp( spob->
class, cm->name ) == 0)) {
650 commodityPrice->
price *= scale;
664 scale = 1 + (strlen(spob->
gfx_exterior) - strlen(SPOB_GFX_EXTERIOR_PATH) - 19) / 100.;
673 factor = tanh( ( log((
double)spob->
population) - log(1e8) ) / 2 );
675 commodityPrice->
price *= 1 + factor * base;
677 commodityPrice->
spobPeriod *= 1 + factor * 0.5;
686 while ( cm != NULL ) {
687 if ( strcmp( factionname, cm->name ) == 0 ) {
693 commodityPrice->
price *= scale;
717 for (
int i=0; i<
array_size(sys->spobs); i++) {
718 Spob *spob = sys->spobs[i];
767 for (
int i=0; i<
array_size(sys->spobs); i++) {
768 Spob *spob = sys->spobs[i];
781 sys->averagePrice = avprice;
791 StarSystem *neighbour;
802 neighbour=sys->jumps[i].target;
803 for ( k=0; k<
array_size(neighbour->averagePrice); k++ ) {
804 if ( ( strcmp( neighbour->averagePrice[k].name, avprice[j].
name ) == 0 ) ) {
805 price+=neighbour->averagePrice[k].price;
812 avprice[j].
sum=price/n;
840 + 0.75*avprice[k].
price );
852 sys->averagePrice=NULL;
864 for (
int j=0; j<
array_size(sys->spobs); j++) {
865 Spob *spob = sys->spobs[j];
897 while (next != NULL) {
905 while (next != NULL) {
917void economy_initialiseSingleSystem( StarSystem *sys,
Spob *spob )
924void economy_averageSeenPrices(
const Spob *p )
927 for (
int i=0; i <
array_size(p->commodities); i++) {
937 cp->
sum2 += price*price;
942void economy_averageSeenPricesAtTime(
const Spob *p,
const ntime_t tupdate )
945 for (
int i=0; i <
array_size(p->commodities); i++) {
954 cp->
sum2 += price*price;
966 for (
int j=0; j<
array_size(sys->spobs); j++) {
967 Spob *p = sys->spobs[j];
968 for (
int k=0; k<
array_size(p->commodityPrice); k++) {
986 for (
int k=0; k<
array_size(p->commodityPrice); k++) {
1003 xmlNodePtr node = parent->xmlChildrenNode;
1008 if (xml_isNode(node,
"economy")) {
1009 xmlNodePtr cur = node->xmlChildrenNode;
1013 if (xml_isNode(cur,
"system")) {
1015 xmlNodePtr nodeSpob = cur->xmlChildrenNode;
1017 xml_onlyNodes(nodeSpob);
1018 if (xml_isNode(nodeSpob,
"spob")) {
1019 xmlr_attr_strd(nodeSpob,
"name",str);
1022 WARN(_(
"Spob '%s' has saved economy data but doesn't exist!"), str);
1026 xmlNodePtr nodeCommodity = nodeSpob->xmlChildrenNode;
1028 xml_onlyNodes(nodeCommodity);
1029 if (xml_isNode(nodeCommodity,
"commodity")) {
1030 xmlr_attr_strd(nodeCommodity,
"name",str);
1040 xmlr_attr_float(nodeCommodity,
"sum",cp->
sum);
1041 xmlr_attr_float(nodeCommodity,
"sum2",cp->
sum2);
1042 xmlr_attr_int(nodeCommodity,
"cnt",cp->
cnt);
1043 xmlr_attr_long(nodeCommodity,
"time",cp->
updateTime);
1046 }
while (xml_nextNode(nodeCommodity));
1048 }
while (xml_nextNode(nodeSpob));
1049 }
else if (xml_isNode(cur,
"lastPurchase")) {
1050 xmlr_attr_strd(cur,
"name", str);
1053 c->lastPurchasePrice = xml_getLong(cur);
1057 }
while (xml_nextNode(cur));
1059 }
while (xml_nextNode(node));
1072 xmlw_startElem(writer,
"economy");
1075 xmlw_startElem(writer,
"lastPurchase");
1078 xmlw_endElem(writer);
1084 for (
int j=0; j<
array_size(sys->spobs); j++) {
1085 Spob *p = sys->spobs[j];
1087 for (
int k=0; k<
array_size(p->commodities); k++) {
1092 xmlw_startElem(writer,
"system");
1093 xmlw_attr(writer,
"name",
"%s",sys->name);
1097 xmlw_startElem(writer,
"spob");
1098 xmlw_attr(writer,
"name",
"%s",p->name);
1100 xmlw_startElem(writer,
"commodity");
1101 xmlw_attr(writer,
"name",
"%s",p->commodities[k]->name);
1102 xmlw_attr(writer,
"sum",
"%f",cp->
sum);
1103 xmlw_attr(writer,
"sum2",
"%f",cp->
sum2);
1104 xmlw_attr(writer,
"cnt",
"%d",cp->
cnt);
1105 xmlw_attr(writer,
"time",
"%"PRIu64,cp->
updateTime);
1106 xmlw_endElem(writer);
1110 xmlw_endElem(writer);
1113 xmlw_endElem(writer);
1115 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.
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.
StarSystem * systems_stack
Commodity * commodity_stack
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