Add SDL2_mixer support.
[runemen.git] / src / mana.c
blob0d5c5c54c7b5d8886072c2541394b917b767eb50
1 #include <SDL.h>
2 #include "rune.h"
3 #include "libs/binaryheap/binhl.h"
5 /* Define this to get lots of _printf's */
6 //#define DEBUG_MANA_POOLS
8 /* DYNAMIC POOLS are pools that are managed in real-time, i.e. pools that can
9 split into two and join together. STATIC POOLS are re-built each game turn
10 from the linked list information. DYNAMIC POOLS are buggy/don't work properly.
11 So I'm sticking with STATIC POOLS for now. They are easier to work with too. */
12 /* #define DYNAMIC_POOLS */
14 #ifdef DEBUG_MANA_POOLS
15 #define _printf(...) fprintf (stdout, __VA_ARGS__)
16 #else
17 #define _printf(...) { }
18 #endif
20 extern int num_units;
21 extern int num_pools;
23 extern unit_t units[MAX_UNITS];
24 extern pool_t pools[MAX_POOLS];
26 int create_pool(int id1, int id2, Uint8 stat) {
27 int pid = num_pools;
28 pool_t *pool = &pools[pid];
30 unit_t *u = &units[id1];
31 unit_t *u2 = &units[id2];
33 pool->head = u2;
34 pool->tail = u;
35 pool->stat = stat;
37 u->pool = pool;
38 _printf("CREATED POOL!\n");
40 num_pools++;
41 return pid;
44 int is_unit_looped(unit_t *start, int stat) {
45 int i;
46 for (i = 0; i < num_units; i++) units[i].block = 0;
47 unit_t *iter = start->link;
48 while (iter) {
49 if (iter->link_stat != stat) break;
50 if (iter->block == 1) break;
51 if (iter == start) return 1;
52 iter->block = 1;
53 iter = iter->link;
55 return 0;
58 void rebuild_pools() {
60 num_pools = 0;
61 int k;for (k = 0; k < MAX_STAT; k++) {
63 int i;
65 binh_list uunits = { 0 };
66 for (i = 0; i < num_units; i++) {
67 units[i].pool = NULL;
68 binhl_push(&uunits, i, units[i].ref_count[k]);
71 _printf("\n Rebuilding mana pools for [%d] (found %d units for it)\n", k, uunits.len);
73 while (uunits.len) {
75 i = binhl_pop(&uunits);
76 unit_t *u = &units[i];
78 printf("Trying unit %s\n", u->name);
80 if (u->pool) { printf ("Already proc\n"); continue;}//already procesed
81 if (!u->link) { printf("no link\n"); continue;}
82 int stat = u->link_stat;
84 if (stat != k) {printf("Wrong stat! %d\n", stat);continue;}
86 _printf("Following unit %s (count: %d)\n", u->name, u->ref_count[stat]);
88 int pid = create_pool(i, 0, u->link_stat);
90 pool_t *pool = &pools[pid];
92 u->pool = pool;
94 int making_open_chain = !is_unit_looped(u, stat);
95 u = u->link;
96 while (u) {
97 //pif (u->ref_count > 1) return;
99 _printf("Now unit %s\n", u->name);
101 if (u == pool->tail) {_printf("1\n");break;}
102 pool->head = u;
104 if (making_open_chain && is_unit_looped(u, stat)) {_printf("2\n");break;}
106 if (u->pool) break;
107 u->pool = pool;
108 _printf("Adding him to this pool\n");
109 //if (u->link->ref_count > 1) break;
111 if (u->link_stat != stat) {
112 /* Re-add him */
113 if (u->link) u->pool = NULL;
114 //binhl_push(&uunits, i, 0);
115 break;
117 u = u->link;
122 }/////
123 printf("Total pools: %d\n", num_pools);
124 #ifdef DEBUG_MANA_POOLS
125 int i;
126 for (i = 0; i < num_pools; i++) {
127 pool_t *pool = &pools[i];
128 unit_t *iter = pool->tail;
129 int j = 0;
130 _printf("Created pool %p(%d), head -- %s, tail -- %s\n", pool, i, (pool->head ? pool->head->name : "NULL"), (pool->tail ? pool->tail->name : "NULL"));
131 while(iter) {
132 _printf("Member %d -- %s, linked to %p (%s) pool\n", j, iter->name, iter->pool, iter->pool == pool ? "THIS" : "OTHER");
133 if (pool->head == iter) break;
134 iter = iter->link;
135 j++;
138 #endif
141 void add_link(int id1, int id2, Uint8 stat) {
142 unit_t *u = &units[id1];
143 unit_t *u2 = &units[id2];
145 u->baloon = 1;
146 u2->baloon = 4;
148 u->link = u2;
149 u->link_id = id2;
150 u->link_stat = stat;
151 u2->ref_count[stat]++;
152 u2->ref_counts++;
154 /* Mana Pools */
155 #ifdef DYNAMIC_MANA_POOLS
156 add_wtf(id1, id2, stat);
157 #else
158 rebuild_pools();
159 #endif
162 void update_stats(int reset)
164 int i, j;
165 if (reset) {
166 for (i = 0; i < num_units; i++) {
167 units[i].block = 0;
168 for (j = 0; j < MAX_STAT; j++) {
169 units[i].rune_stat[j] = 0;
174 for (i = 0; i < num_units; i++) {
175 unit_t *u = &units[i];
176 for (j = 0; j < MAX_STAT; j++) {
177 u->calc_stat[j] = u->base_stat[j] + u->rune_stat[j];
178 if (u->calc_stat[j] > 99) u->calc_stat[j] = 99;
179 u->stat_bid[j] = 0;
184 #define IN_POOL(POOL, UNIT) ((UNIT)->pool == (POOL))
185 #define IS_LOOPED(POOL) ((POOL)->head->link == (POOL)->tail && (POOL)->head->link_stat == (POOL)->stat)
186 #define IS_ADJACENT(POOL) ((POOL)->head->pool != (POOL) && (POOL)->head->pool)
188 void collect_pools() {
189 int i;
191 update_stats(1);
193 binh_list kpools = { 0 }; /* while iterating, collect "adjacent" pools in here */
195 _printf("Collecting energy: \n");
197 for (i = 0; i < num_pools; i++) {
198 pool_t *pool = &pools[i];
199 unit_t *iter = pool->tail;
200 int rc = 0;
201 int closed = IS_LOOPED(pool);
202 do {
203 _printf("On unit: %s\n", iter->name);
204 if (!closed && iter == pool->head) break; /* Do not collect from heads of open chains */
205 pool->pool += iter->base_stat[pool->stat];
206 iter->rune_stat[pool->stat] -= iter->base_stat[pool->stat];
207 if (iter->ref_count[pool->stat] > rc) rc = iter->ref_count[pool->stat];
208 if (iter == pool->head) break; /* We're now looping in a closed chain */
209 iter = iter->link;
211 } while (iter);// && iter->pool == pool);
213 _printf(" pool #%d [%s-%s (%d)] -- collected %d\n",i, pool->tail->name,pool->head->name, rc, pool->pool);
215 if (IS_ADJACENT(pool)) binhl_push(&kpools, i, rc);
219 void prop_pools() {
221 binh_list kpools = { 0 };
222 int i;
223 for (i = 0; i < num_pools; i++) {
224 if (IS_ADJACENT(&pools[i]) binhl_push(&kpools, i, pools[i].tail->ref_count);
227 /* forward adjacent pools */
228 while(kpools.len) {
229 i = binhl_pop(&kpools);
231 pool_t *pool = &pools[i];
233 _printf("Forwarding pool #%d [%s-%s (%d)]\n", i, pool->tail->name, pool->head->name, pool->head->ref_count[pool->stat]);
235 if (pool->head->pool == NULL) {
236 _printf("Nowhere to forward! :((\n");
237 continue;
240 pool_t *nextp = pool->head->pool;
241 nextp->pool += pool->pool;
242 pool->pool = 0;
245 update_stats(0);
248 void distrib_pools() {
249 int i;
251 // binh_list kpools = { 0 };
252 //for (i = 0; i < num_pools; i++)
253 //binhl_push(&kpools, i, pools[i].tail->ref_count);
255 for (i = 0; i < num_pools; i++) {
256 // while(kpools.len) {
257 // i = binhl_pop(&kpools);
259 _printf("Distributing pool #%d\n",i);
261 pool_t *pool = &pools[i];
263 if (IS_LOOPED(pool)) { /* Closed chain */
265 /* Pick bidders */
266 binh_list uunits = { 0 };
267 int num_total = 0, num_bids = 0;
268 int large_value = num_units * 10; /* using this to invert priority */
270 _printf("Distributing closed chain:\n");
272 unit_t *iter = pool->tail;
273 do {
275 int priority = iter->stat_bid[pool->stat] + iter->pin;
277 _printf("Examining %d=%s (priority: %d, sort: %d)\n", num_total, iter->name, priority, large_value - priority);
279 binhl_push(&uunits, num_total++, large_value - priority);
281 if (priority) num_bids++;
283 iter = iter->link;
285 } while (iter != pool->tail);
287 if (num_bids == 0) num_bids = num_total; /* zero bids == everyone */
289 _printf("Picked %d units (of %d) for distribution\n", num_bids, num_total);
291 /* Distribute among them */
292 Uint16 share = pool->pool / num_bids;
293 Uint16 bonus = pool->pool % num_bids;
295 while (num_bids--) {
297 int j = binhl_pop(&uunits); /* "j" is "offset from tail" */
299 _printf("Need to give to %d=", j);
301 for (iter = pool->tail; j > 0; j--) /* grab a unit using "j" */
303 _printf("%s->", iter->name);
304 iter = iter->link;
307 _printf("\nGiving %d to %s\n", share, iter->name);
308 iter->rune_stat[pool->stat] += share;
309 //iter->calc_stat[pool->stat] += share;
312 _printf("Giving extra %d to %s\n", bonus, iter->name);
313 iter->rune_stat[pool->stat] += bonus;
314 //iter->calc_stat[pool->stat] += bonus;
316 } else { /* Open chain */
318 /* Just give everything to pool's "head" */
319 pool->head->rune_stat[pool->stat] += pool->pool;
320 //iter->calc_stat[pool->stat] += pool->pool;
323 /* Drain the pool */
324 pool->pool = 0;
327 update_stats(0);
331 /* For testing: */
332 void random_links() {
333 int j = 100;
334 while (j--) {
335 Uint8 u = rand() % num_units;
336 int w = rand() % 5;
337 while (w--) {
338 Uint8 u2 = rand() % num_units;
339 if (u2 != u) {
340 add_link(u, u2, 1);
353 #ifdef DYNAMIC_POOLS
354 void add_to_pool(pool_t *pool, int id1, int id2, Uint8 stat) {
355 unit_t *u = &units[id1];
356 unit_t *u2 = &units[id2];
358 if (pool->head->link == u2) {
359 _printf("Adding to the top\n");
360 //pool->head->pool = pool;
361 pool->head = u2;
362 u->pool = pool;
363 } else if (pool->tail == u2) {
364 _printf("Adding to the tail\n");
365 pool->tail = u;
366 u->pool = pool;
367 } else {
368 _printf("Adding to the middle\n");
369 create_pool(id1, id2, stat);
373 pool_t* find_pool(int unit_id, Uint8 stat) {
374 unit_t *iter = &units[unit_id];
375 while (iter) {
376 _printf("Searching for pool..%s\n", iter->name);
377 if (iter->pool)
378 _printf("I have one!");
379 else
380 _printf("I don't have one!\n");
381 if (iter->pool)// && iter->pool->stat == stat)
382 return iter->pool;
383 _printf("Moving to %p\n",iter->link);
384 if (iter->link_stat == stat)
385 iter = iter->link;
386 else break;
388 int i;
389 pool_t *good = NULL;
390 for (i =0; i < num_pools; i++) {
391 if (pools[i].head ==&units[unit_id]
392 && pools[i].stat == stat) {
393 if (good) return NULL;
394 good = &pools[i];
397 return good;
400 void add_wtf(int id1, int id2, Uint8 stat) {
401 unit_t *u = &units[id1];
402 unit_t *u2 = &units[id2];
404 pool_t *pool = 0;
405 pool = find_pool(id1, stat);
406 if (pool == NULL) {
407 // pool =
408 create_pool(id1, id2, stat);
409 } else {
410 add_to_pool(pool, id1, id2, stat);
414 unit_t* find_prev(pool_t *pool, unit_t *who) {
415 unit_t*iter = pool->tail;
416 while (iter->link) {
417 if (iter->link == who) break;
418 iter = iter->link;
420 return iter;
422 pool_t* clone_pool(pool_t *pool) {
423 int pid = num_pools;
424 memcpy(&pools[pid], pool, sizeof(pool_t));
425 num_pools++;
426 return &pools[pid];
428 void switch_pool(unit_t *tail, unit_t *border, pool_t *new_pool) {
429 unit_t*iter = tail;
430 pool_t *pool = tail->pool;
431 while (iter) {
432 if (iter->pool == pool) iter->pool = new_pool;
433 if (iter->link == border) break;
434 iter = iter->link;
438 void remove_pool(pool_t *pool) {
439 int i = 0;
440 switch_pool(pool->tail, pool->head, NULL);
441 for (i = 0; i < num_pools; i++) {
442 if (&pools[i] == pool) {
443 if (i < num_pools-1) {
444 memcpy(&pools[i], &pools[num_pools], sizeof(pool_t));
446 num_pools--;
451 void split_pool(pool_t *pool, unit_t *u) {
453 /* Before we even start the split, let's consider the
454 * alternatives:
455 * o - x - o In this case, we just remove.
456 * o - o - x - o Do not create right hand pool, just CUT
457 * o - x - o - o Mutate left-hand pool
460 /* O - X - O / aka the Trigraph is easy to spot */
461 if (pool->tail->link == u && u->link == pool->head)
463 _printf("It's just a trigraph!\n");
464 remove_pool(pool);
465 return;
467 /* O - ? - ? - O / ok this is getty lame */
468 if (pool->tail->link && pool->tail->link->link && pool->tail->link->link->link == pool->head)
470 unit_t *prev = find_prev(pool, u);
471 if (u->link == pool->head) {
472 _printf("It's a riftized foragraph!\n");
473 pool->head = prev;
475 if (pool->tail->link == u) {
476 _printf("It's a leftized foragrpah...!\n");
477 switch_pool(pool->tail, u, NULL);
478 pool->tail = u->link;
481 return;
485 pool_t *nextp = clone_pool(pool);
486 unit_t *prev = find_prev(pool, u);
488 pool->head = prev;
489 nextp->tail = u->link;
491 if (nextp->tail == nextp->head) {
492 _printf("Pool is now empty, remove it!\n");
493 remove_pool(nextp);
495 else
497 unit_t *mark = nextp->tail;
498 while (mark) {
499 if (mark->pool == pool)
500 mark->pool = nextp;
501 if (mark->link->link_stat == u->link_stat)/* ??? was mark->link for some reason ??? */
502 mark = mark->link;
503 else break;
506 if (pool->tail == pool->head) {
507 _printf("Pool is now empty, remove it!\n");
508 remove_pool(pool);
512 pool_t* find_Xpool(int unit_id, Uint8 stat) {
513 unit_t *iter = &units[unit_id];
514 pool_t *good = NULL;
515 while (iter) {
516 _printf("%s links to ...", iter->name);
517 if (iter->link) _printf("%s ", iter->link->name);
518 _printf(" and has connection to pool %p\n", iter->pool);
519 if (iter->pool && iter->pool->stat == stat)
520 return iter->pool;
521 //if (iter->link_stat == stat)
522 iter = iter->link;
523 //else break;
525 int i;
526 good = NULL;
527 for (i =0; i < num_pools; i++) {
528 if (pools[i].head ==&units[unit_id]
530 // if (good)
531 return &pools[i];
532 //good = ;
535 return good;
538 void remove_wtf(int id1) {
539 unit_t *u = &units[id1];
541 pool_t *pool = 0;
542 pool = find_pool(id1, u->link_stat);
544 if (!pool) {
545 _printf("No pool found...\n");
546 pool = find_Xpool(id1, u->link_stat);
548 if (!pool) {
549 _printf("Still no pool!\n");
550 return;
553 if (pool->tail == u) {
554 _printf("Was at the very very end!\n");
555 pool->tail = pool->tail->link;
556 _printf("Shrinking pool\n");
557 if (pool->tail == pool->head) {
558 _printf("Pool is now empty, remove it!\n");
559 remove_pool(pool);
560 return;//or continue;
563 else if (pool->head == u) {
564 _printf("At the very head!\n");
565 _printf("Fidn me prev...");
567 unit_t *prev = find_prev(pool, u);
568 pool->head = prev;
569 if (pool->tail == pool->head) {
570 _printf("Pool is now empty, remove it!\n");
571 remove_pool(pool);
572 return;//or continue;
575 else {
576 split_pool(pool, u);
578 _printf("HIS POOL %p!\n",pool);
580 #endif