1 #include <stdlib.h>
2
3 #include "types.h"
4 #include "util.h"
5
6 #include "Bill.h"
7 #include "Computer.h"
8 #include "Game.h"
9 #include "Horde.h"
10 #include "Network.h"
11 #include "UI.h"
12
13 static Bill *alive, *strays;
14 static int counters[HORDE_COUNTER_MAX + 1];
15
16 #define MAX_BILLS 100 /* max Bills per level */
17
18 #define UNLINK(bill, list) \
19 do { \
20 if ((bill)->next != NULL) \
21 (bill)->next->prev = (bill)->prev; \
22 if ((bill)->prev != NULL) \
23 (bill)->prev->next = (bill)->next; \
24 else if ((bill) == list) \
25 (list) = (bill)->next; \
26 (bill)->prev = NULL; \
27 (bill)->next = NULL; \
28 } while (0)
29
30 #define PREPEND(bill, list) \
31 do { \
32 (bill)->next = (list); \
33 if ((list) != NULL) \
34 (list)->prev = (bill); \
35 (list) = (bill); \
36 } while (0)
37
38 static int
on(unsigned int lev)39 on(unsigned int lev) {
40 int perlevel = (int)((8 + 3 * lev) * Game_scale(2));
41 return MIN(perlevel, MAX_BILLS);
42 }
43
44 static int
max_at_once(unsigned int lev)45 max_at_once(unsigned int lev) {
46 return MIN(2 + lev / 4, 12);
47 }
48
49 static int
between(unsigned int lev)50 between(unsigned int lev) {
51 return MAX(14 - lev / 3, 10);
52 }
53
54 /* Launches Bills whenever called */
55 static void
launch(int max)56 launch(int max) {
57 Bill *bill;
58 int n;
59 int off_screen = counters[HORDE_COUNTER_OFF];
60
61 if (max == 0 || off_screen == 0)
62 return;
63 n = RAND(1, MIN(max, off_screen));
64 for (; n > 0; n--) {
65 Bill_enter(&bill);
66 PREPEND(bill, alive);
67 }
68 }
69
70 void
Horde_setup()71 Horde_setup() {
72 Bill *bill;
73 while (alive != NULL) {
74 bill = alive;
75 UNLINK(bill, alive);
76 free(bill);
77 }
78 while (strays != NULL) {
79 bill = strays;
80 UNLINK(bill, strays);
81 free(bill);
82 }
83 counters[HORDE_COUNTER_OFF] = on(Game_level());
84 counters[HORDE_COUNTER_ON] = 0;
85 }
86
87 void
Horde_update(int iteration)88 Horde_update(int iteration) {
89 Bill *bill, *next;
90 int level = Game_level();
91 if (iteration % between(level) == 0)
92 launch(max_at_once(level));
93 for (bill = alive; bill != NULL; bill = next) {
94 next = bill->next;
95 Bill_update(bill);
96 }
97 }
98
99 void
Horde_draw()100 Horde_draw() {
101 Bill *bill;
102
103 for (bill = strays; bill != NULL; bill = bill->next)
104 Bill_draw(bill);
105 for (bill = alive; bill != NULL; bill = bill->next)
106 Bill_draw(bill);
107 }
108
109 void
Horde_move_bill(Bill * bill)110 Horde_move_bill(Bill *bill) {
111 UNLINK(bill, alive);
112 PREPEND(bill, strays);
113 }
114
115 void
Horde_remove_bill(Bill * bill)116 Horde_remove_bill(Bill *bill) {
117 if (bill->state == BILL_STATE_STRAY)
118 UNLINK(bill, strays);
119 else
120 UNLINK(bill, alive);
121 Network_clear_stray(bill);
122 free(bill);
123 }
124
125 void
Horde_add_bill(Bill * bill)126 Horde_add_bill(Bill *bill) {
127 if (bill->state == BILL_STATE_STRAY)
128 PREPEND(bill, strays);
129 else
130 PREPEND(bill, alive);
131 }
132
133 Bill *
Horde_clicked_stray(int x,int y)134 Horde_clicked_stray(int x, int y) {
135 Bill *bill;
136
137 for (bill = strays; bill != NULL; bill = bill->next) {
138 if (!Bill_clickedstray(bill, x, y))
139 continue;
140 UNLINK(bill, strays);
141 return bill;
142 }
143 return NULL;
144 }
145
146 int
Horde_process_click(int x,int y)147 Horde_process_click(int x, int y) {
148 Bill *bill;
149 int counter = 0;
150
151 for (bill = alive; bill != NULL; bill = bill->next) {
152 if (bill->state == BILL_STATE_DYING ||
153 !Bill_clicked(bill, x, y))
154 continue;
155 if (bill->state == BILL_STATE_AT) {
156 Computer *comp;
157 comp = Network_get_computer(bill->target_c);
158 comp->busy = 0;
159 comp->stray = bill;
160 }
161 Bill_set_dying(bill);
162 counter++;
163 }
164 return counter;
165 }
166
167 void
Horde_inc_counter(int counter,int val)168 Horde_inc_counter(int counter, int val) {
169 counters[counter] += val;
170 }
171
172 int
Horde_get_counter(int counter)173 Horde_get_counter(int counter) {
174 return counters[counter];
175 }
176