econ.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674
  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include "econ.h"
  4. #define MAX_ACTORS 1024*1024
  5. #define MAX_ITEMS 1024*1024
  6. #define MAX_CASHFLOW 1024*1024
  7. #define MAX_ASSETS 1024*1024
  8. #define MAX_COMMODITIES 1024
  9. #define CLAMP(v, min, max) (v < min ? v : (v > max ? max : v))
  10. void Economy_tick(Economy* ec) {
  11. /*
  12. // process cashflows
  13. VECMP_EACH(&ec->cashflow, ind, cf) {
  14. // TODO: handle overflow
  15. if(cf->from == ECON_MAGIC) {
  16. VECMP_ITEM(&ec->cash, cf->to) += cf->amount;
  17. }
  18. else if(cf->to == ECON_MAGIC) {
  19. VECMP_ITEM(&ec->cash, cf->from) -= cf->amount;
  20. }
  21. else {
  22. money_t tmp = VECMP_ITEM(&ec->cash, cf->from);
  23. tmp = CLAMP(cf->amount, tmp, ECON_CASHMAX);
  24. VECMP_ITEM(&ec->cash, cf->to) += tmp;
  25. VECMP_ITEM(&ec->cash, cf->from) -= tmp;
  26. // TODO: trigger bankruptcy
  27. }
  28. }
  29. */
  30. // transport should tick first or last
  31. tickMine(ec);
  32. tickFactory(ec);
  33. tickStore(ec);
  34. tickCompany(ec);
  35. tickPerson(ec);
  36. // external interaction
  37. if(frandNorm() > .9) {
  38. entityid_t companyid = Econ_CreateCompany(ec, "Initech");
  39. }
  40. }
  41. #define DEFINE_GET_COMPONENT(type) \
  42. type* Econ_Get##type(Economy*ec, compid_t id) { \
  43. return &VECMP_ITEM(&(ec->type), id); \
  44. }
  45. DEFINE_GET_COMPONENT(Entity)
  46. DEFINE_GET_COMPONENT(Movement)
  47. DEFINE_GET_COMPONENT(Position)
  48. DEFINE_GET_COMPONENT(Money)
  49. DEFINE_GET_COMPONENT(PathFollow)
  50. #define NEW_COMPONENT(ec, type, id, e) \
  51. econid_t id; \
  52. type* e; \
  53. VECMP_INC(&(ec)->type); \
  54. id = VECMP_LAST_INS_INDEX(&(ec)->type); \
  55. e = &VECMP_ITEM(&(ec)->type, id); \
  56. memset(e, 0, sizeof(*e));
  57. entityid_t Econ_NewEntity(Economy* ec, enum EntityType type, void* userData, char* name) {
  58. NEW_COMPONENT(ec, Entity, id, e);
  59. e->type = type;
  60. e->userData = userData;
  61. e->name = name;
  62. ec->entityCounts[type]++;
  63. return id;
  64. }
  65. void Economy_init(Economy* ec) {
  66. memset(ec, 0, sizeof(*ec));
  67. // VECMP_INIT(&ec->cash, MAX_ACTORS);
  68. VECMP_INIT(&ec->cashflow, MAX_CASHFLOW);
  69. // VECMP_INIT(&ec->assets, MAX_ASSETS);
  70. // VECMP_INIT(&ec->actors, MAX_ACTORS);
  71. // VECMP_INIT(&ec->cfDescriptions, MAX_CASHFLOW);
  72. VECMP_INIT(&ec->Entity, 16384);
  73. // fill in id 0
  74. Econ_NewEntity(ec, ET_None, NULL, "Null Entity");
  75. #define X(type, a) VECMP_INIT(&ec->type, 8192);
  76. ENTITY_TYPE_LIST
  77. #undef X
  78. #define X(type, a) VECMP_INIT(&ec->type, 8192);
  79. COMP_TYPE_LIST
  80. #undef X
  81. // ec->markets = calloc(1, sizeof(*ec->markets) * MAX_COMMODITIES);
  82. // for(uint32_t i = 0; i < MAX_COMMODITIES; i++) ec->markets[i].commodity = i;
  83. // ec->comNames = calloc(1, sizeof(*ec->comNames) * MAX_COMMODITIES);
  84. for(int y = 0; y < 64; y++) {
  85. for(int x = 0; x < 64; x++) {
  86. entityid_t pcid; // wrong
  87. Parcel* p;
  88. pcid = Econ_NewEntParcel(ec, &p);
  89. entityid_t pid = Econ_NewEntity(ec, ET_Parcel, p, "Mapgen Parcel");
  90. p->id = pid;
  91. p->loc.x = x;
  92. p->loc.y = y;
  93. p->price = 1000;
  94. p->minerals = 1000000;
  95. ec->parcelGrid[x][y] = pid;
  96. }
  97. }
  98. }
  99. void Entity_InitMoney(Economy* ec, entityid_t eid) {
  100. Entity* e = Econ_GetEntity(ec, eid);
  101. e->money = Econ_NewCompMoney(ec, NULL);
  102. }
  103. entityid_t Econ_CreatePerson(Economy* ec, char* name) {
  104. Person* p;
  105. compid_t perid = Econ_NewEntPerson(ec, &p);
  106. entityid_t pid = Econ_NewEntity(ec, ET_Person, p, name);
  107. p->name = name;
  108. p->id = pid;
  109. Entity_InitMoney(ec, pid);
  110. return pid;
  111. }
  112. entityid_t Econ_CreateCompany(Economy* ec, char* name) {
  113. Company* c;
  114. compid_t compid = Econ_NewEntCompany(ec, &c);
  115. entityid_t cid = Econ_NewEntity(ec, ET_Company, c, name);
  116. c->name = name;
  117. c->id = cid;
  118. Entity_InitMoney(ec, cid);
  119. return cid;
  120. }
  121. entityid_t Econ_CreateMine(Economy* ec, entityid_t parcel_id, char* name) {
  122. Mine* c;
  123. compid_t compid = Econ_NewEntMine(ec, &c);
  124. entityid_t cid = Econ_NewEntity(ec, ET_Mine, c, name);
  125. c->parcel = parcel_id;
  126. c->name = name;
  127. c->id = cid;
  128. c->metals = 0;
  129. return cid;
  130. }
  131. entityid_t Econ_CreateFactory(Economy* ec, entityid_t parcel_id, char* name) {
  132. Factory* c;
  133. compid_t compid = Econ_NewEntFactory(ec, &c);
  134. entityid_t cid = Econ_NewEntity(ec, ET_Factory, c, name);
  135. c->parcel = parcel_id;
  136. c->name = name;
  137. c->id = cid;
  138. c->widgets = 0;
  139. return cid;
  140. }
  141. entityid_t Econ_CreateStore(Economy* ec, entityid_t parcel_id, char* name) {
  142. Store* c;
  143. compid_t compid = Econ_NewEntStore(ec, &c);
  144. entityid_t cid = Econ_NewEntity(ec, ET_Store, c, name);
  145. c->parcel = parcel_id;
  146. c->name = name;
  147. c->id = cid;
  148. c->widgets = 0;
  149. return cid;
  150. }
  151. /*
  152. econid_t Economy_AddActor(Economy* ec, char* name, money_t cash) {
  153. econid_t id;
  154. EcActor* ac;
  155. VECMP_INSERT(&ec->cash, cash);
  156. id = VECMP_LAST_INS_INDEX(&ec->cash);
  157. char* n = strdup(name);
  158. ac = &VECMP_ITEM(&ec->actors, id);
  159. ac->id = id;
  160. ac->name = n;
  161. return id;
  162. }
  163. */
  164. econid_t Economy_AddCashflow(
  165. Economy* ec,
  166. money_t amount,
  167. econid_t from,
  168. econid_t to,
  169. uint32_t freq,
  170. char* desc
  171. ) {
  172. econid_t id;
  173. VECMP_INSERT(&ec->cashflow, ((EcCashflow){
  174. .from = from,
  175. .to = to,
  176. .amount = amount,
  177. .frequency = freq
  178. }));
  179. id = VECMP_LAST_INS_INDEX(&ec->cashflow);
  180. // VECMP_ITEM(&ec->cfDescriptions, id) = strdup(desc);
  181. return id;
  182. }
  183. /*
  184. econid_t Economy_AddAsset(Economy* ec, EcAsset* ass) {
  185. econid_t id;
  186. VECMP_INSERT(&ec->assets, *ass);
  187. ass = VECMP_LAST_INSERT(&ec->assets);
  188. id = VECMP_LAST_INS_INDEX(&ec->cash);
  189. ass->id = id;
  190. return id;
  191. }
  192. int Economy_BuyAsset(Economy* ec, EcAsset* ass, EcActor* buyer, money_t price) {
  193. money_t* bal = &VEC_ITEM(&ec->cash, buyer->id);
  194. if(*bal < price) {
  195. // TODO: log fault
  196. return 1;
  197. }
  198. ass->purchasePrice = price;
  199. ass->curEstValue = price;
  200. ass->buyNowPrice = price * 2;
  201. ass->owner = buyer->id;
  202. *bal -= price;
  203. return 0;
  204. }
  205. */
  206. entityid_t buyLand(Economy* ec, entityid_t buyer, Parcel** parOut) {
  207. Entity* bent = Econ_GetEntity(ec, buyer);
  208. Money* m = Econ_GetCompMoney(ec, bent->money);
  209. VECMP_EACH(&ec->Parcel, pi, p) {
  210. if(p->owner) continue;
  211. if(1 || m->cash > p->price) {
  212. m->cash -= p->price;
  213. p->owner = buyer;
  214. if(parOut) *parOut = p;
  215. return p->id;
  216. }
  217. }
  218. return 0;
  219. }
  220. // tick functions
  221. void doMine(Economy* ec, Mine* m) {
  222. Entity* pent = Econ_GetEntity(ec, m->parcel);
  223. Parcel* p = pent->userData;
  224. p->minerals -= 10;
  225. m->metals += 3;
  226. Econ_CommodityExNihilo(ec, CT_Ore, -10);
  227. Econ_CommodityExNihilo(ec, CT_Metal, 3);
  228. if(m->metals > 10) {
  229. m->metals -= 10;
  230. Entity* cent = Econ_GetEntity(ec, m->owner);
  231. Company* c = cent->userData;
  232. c->metalsInTransit += 10;
  233. }
  234. }
  235. entityid_t buildMine(Economy* ec, Company* c, Parcel* p) {
  236. entityid_t mineID = Econ_CreateMine(ec, p->id, "Smaller Hole");
  237. Mine* mine = Econ_GetEntity(ec, mineID)->userData;
  238. mine->owner = c->id;
  239. p->structure = mineID;
  240. return mineID;
  241. }
  242. entityid_t buildFactory(Economy* ec, Company* c, Parcel* p) {
  243. entityid_t fid = Econ_CreateFactory(ec, p->id, "Smog Mill");
  244. Factory* f = Econ_GetEntity(ec, fid)->userData;
  245. f->owner = c->id;
  246. p->structure = fid;
  247. return fid;
  248. }
  249. entityid_t buildStore(Economy* ec, Company* c, Parcel* p) {
  250. entityid_t fid = Econ_CreateStore(ec, p->id, "SMart");
  251. Store* f = Econ_GetEntity(ec, fid)->userData;
  252. f->owner = c->id;
  253. p->structure = fid;
  254. return fid;
  255. }
  256. void doCompany(Economy* ec, Company* c) {
  257. Entity* cent = Econ_GetEntity(ec, c->id);
  258. Money* money = Econ_GetCompMoney(ec, cent->money);
  259. char hasMine = 1;
  260. char hasFactory = 1;
  261. char hasStore = 1;
  262. Parcel* emptyParcel = NULL;
  263. if(VEC_LEN(&c->mines) == 0) hasMine = 0;
  264. if(VEC_LEN(&c->factories) == 0) hasFactory = 0;
  265. if(VEC_LEN(&c->stores) == 0) hasStore = 0;
  266. VEC_EACH(&c->parcels, pi, pid) {
  267. Entity* pent = Econ_GetEntity(ec, pid);
  268. Parcel* p = pent->userData;
  269. if(p->structure == 0) {
  270. emptyParcel = p;
  271. break;
  272. }
  273. }
  274. if((!hasMine || !hasFactory || !hasStore) && emptyParcel == NULL) {
  275. Parcel* par;
  276. entityid_t parid = buyLand(ec, c->id, &par);
  277. VEC_PUSH(&c->parcels, parid);
  278. return;
  279. }
  280. if(!hasMine) {
  281. entityid_t mid = buildMine(ec, c, emptyParcel);
  282. VEC_PUSH(&c->mines, mid);
  283. return;
  284. }
  285. if(!hasFactory) {
  286. entityid_t mid = buildFactory(ec, c, emptyParcel);
  287. VEC_PUSH(&c->factories, mid);
  288. return;
  289. }
  290. if(!hasStore) {
  291. entityid_t mid = buildStore(ec, c, emptyParcel);
  292. VEC_PUSH(&c->stores, mid);
  293. return;
  294. }
  295. // at this point we have a factory and a mine and a store
  296. // move some metal to the factory
  297. Entity* fent = Econ_GetEntity(ec, VEC_ITEM(&c->factories, 0));
  298. Entity* sent = Econ_GetEntity(ec, VEC_ITEM(&c->stores, 0));
  299. Factory* f = fent->userData;
  300. Factory* s = sent->userData;
  301. if(c->metalsInTransit > 0) {
  302. f->metals += c->metalsInTransit;
  303. c->metalsInTransit = 0;
  304. }
  305. if(c->widgetsInTransit > 0) {
  306. s->widgets += c->widgetsInTransit;
  307. c->widgetsInTransit = 0;
  308. }
  309. // check if have mine -> build mine
  310. // check if have land -> buy land
  311. // check if have workers -> hire workers
  312. // check if have factory -> build factory
  313. // check if have land -> buy land
  314. // check if have workers -> hire workers
  315. // check if have store -> build store
  316. // check if have land -> buy land
  317. // check if have workers -> hire workers
  318. // create products
  319. // transport metals to factory
  320. // transport products to store
  321. // produce items
  322. // sell products
  323. // ???
  324. // profit!!!
  325. }
  326. void doPerson(Economy* ec, Person* p) {
  327. // find job
  328. // find house
  329. // buy widgets
  330. }
  331. void doHouse(Economy* ec, House* p) {
  332. // random maintenance events
  333. }
  334. void doStore(Economy* ec, Store* s) {
  335. if(s->widgets > 0) {
  336. s->widgets--;
  337. s->sales += 30;
  338. }
  339. }
  340. void doFactory(Economy* ec, Factory* f) {
  341. if(f->metals > 10) {
  342. f->metals -= 10;
  343. f->widgets++;
  344. Econ_CommodityExNihilo(ec, CT_Widget, 1);
  345. Econ_CommodityExNihilo(ec, CT_Metal, -10);
  346. }
  347. if(f->widgets >= 10) {
  348. Entity* cent = Econ_GetEntity(ec, f->owner);
  349. Company* c = cent->userData;
  350. c->widgetsInTransit += 10;
  351. }
  352. }
  353. void doParcel(Economy* ec, Parcel* p) {}
  354. void doFarm(Economy* ec, Farm* f) {}
  355. // tick loop functions
  356. #define X(type, needsDoFn) void tick##type(Economy* ec) { \
  357. VECMP_EACH(&ec->type, ci, c) { \
  358. do##type(ec, c); \
  359. } \
  360. }
  361. ENTITY_TYPE_LIST
  362. #undef X
  363. #define X(type, a) compid_t Econ_NewComp##type(Economy* ec, type** out) { \
  364. compid_t id; \
  365. type* e; \
  366. VECMP_INC(&(ec)->type); \
  367. id = VECMP_LAST_INS_INDEX(&ec->type); \
  368. e = &VECMP_ITEM(&ec->type, id); \
  369. memset(e, 0, sizeof(*e)); \
  370. if(out) *out = e; \
  371. \
  372. return id; \
  373. }
  374. COMP_TYPE_LIST
  375. #undef X
  376. #define X(type, a) compid_t Econ_NewEnt##type(Economy* ec, type** out) { \
  377. compid_t id; \
  378. type* e; \
  379. VECMP_INC(&(ec)->type); \
  380. id = VECMP_LAST_INS_INDEX(&ec->type); \
  381. e = &VECMP_ITEM(&ec->type, id); \
  382. memset(e, 0, sizeof(*e)); \
  383. if(out) *out = e; \
  384. \
  385. return id; \
  386. }
  387. ENTITY_TYPE_LIST
  388. #undef X
  389. #define X(type, a) type* Econ_GetEnt##type(Economy* ec, compid_t id) { \
  390. type* e; \
  391. e = &VECMP_ITEM(&(ec->type), id); \
  392. return e; \
  393. }
  394. ENTITY_TYPE_LIST
  395. #undef X
  396. #define X(type, a) type* Econ_GetComp##type(Economy* ec, compid_t id) { \
  397. type* e; \
  398. e = &VECMP_ITEM(&(ec->type), id); \
  399. return e; \
  400. }
  401. COMP_TYPE_LIST
  402. #undef X
  403. static size_t CommoditySet_find_index(CommoditySet* cs, commodityid_t comm) {
  404. ptrdiff_t R = cs->fill - 1;
  405. ptrdiff_t L = 0;
  406. ptrdiff_t i;
  407. while(R - L > 0) {
  408. // midpoint
  409. i = L + ((R - L) / 2);
  410. if(cs->buckets[i].comm < comm) {
  411. L = i + 1;
  412. }
  413. else if(cs->buckets[i].comm > comm) {
  414. R = i - 1;
  415. }
  416. else {
  417. return i;
  418. }
  419. }
  420. return (cs->buckets[L].comm < comm) ? L + 1 : L;
  421. }
  422. CommoditySet* CommoditySet_New(int size) {
  423. CommoditySet* cs = calloc(1, sizeof(*cs) + sizeof(cs->buckets[0]) * size);
  424. cs->length = size;
  425. return cs;
  426. }
  427. // must never be given a null pointer
  428. // returns zero for success, 1 if the set could not accept more
  429. int CommoditySet_Add(CommoditySet* cs, commodityid_t comm, qty_t qty, int compact) {
  430. // find the slot
  431. size_t i = CommoditySet_find_index(cs, comm);
  432. if(cs->buckets[i].comm == comm) {
  433. cs->buckets[i].qty += qty; // TODO: check saturation
  434. // purge zero-value items, if desired
  435. if(compact && cs->buckets[i].qty == 0) {
  436. memmove(&cs->buckets[i], &cs->buckets[i + 1], (cs->fill - i - 1) * sizeof(cs->buckets[0]));
  437. cs->fill--;
  438. }
  439. return 0;
  440. }
  441. // check for room
  442. if(cs->fill >= cs->length) return 1; // overflow
  443. memmove(&cs->buckets[i + 1], &cs->buckets[i], (cs->fill - i) * sizeof(cs->buckets[0]));
  444. cs->buckets[i].comm = comm;
  445. cs->buckets[i].qty = qty;
  446. cs->fill++;
  447. return 0;
  448. }
  449. // must never be given a null pointer
  450. qty_t CommoditySet_Get(CommoditySet* cs, commodityid_t comm) {
  451. // find the slot
  452. size_t i = CommoditySet_find_index(cs, comm);
  453. if(cs->buckets[i].comm == comm) {
  454. return cs->buckets[i].qty;
  455. }
  456. return 0;
  457. }
  458. void Econ_CommodityExNihilo(Economy* ec, commodityid_t comm, qty_t qty) {
  459. ec->commodityTotals[comm] += qty;
  460. }