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 "OS.h"
12 #include "UI.h"
13
14 /* speed at which OS drops */
15 #define GRAVITY 3
16
17 /* speed of moving Bill */
18 #define SLOW 0
19 #define FAST 1
20
21 #define WCELS 4 /* # of bill walking animation frames */
22 #define DCELS 5 /* # of bill dying animation frames */
23 #define ACELS 13 /* # of bill switching OS frames */
24
25 static Picture *lcels[WCELS], *rcels[WCELS], *acels[ACELS], *dcels[DCELS];
26 static int width, height;
27
28 static void
get_border(int * x,int * y)29 get_border(int *x, int *y) {
30 int i = RAND(0, 3);
31 int screensize = Game_screensize();
32
33 if (i % 2 == 0)
34 *x = RAND(0, screensize - width);
35 else
36 *y = RAND(0, screensize - height);
37
38 switch (i) {
39 case 0:
40 *y = -height - 16;
41 break;
42 case 1:
43 *x = screensize + 1;
44 break;
45 case 2:
46 *y = screensize + 1;
47 break;
48 case 3:
49 *x = - width - 2;
50 break;
51 }
52 }
53
54 /* Adds a bill to the in state */
55 void
Bill_enter(Bill ** billp)56 Bill_enter(Bill **billp) {
57 Bill *bill;
58 Computer *computer;
59
60 bill = xalloc(sizeof *bill);
61
62 bill->state = BILL_STATE_IN;
63 get_border(&bill->x, &bill->y);
64 bill->index = 0;
65 bill->cels = lcels;
66 bill->cargo = OS_WINGDOWS;
67 bill->x_offset = -2;
68 bill->y_offset = -15;
69 bill->target_c = RAND(0, Network_num_computers() - 1);
70 computer = Network_get_computer(bill->target_c);
71 bill->target_x = computer->x + Computer_width() - BILL_OFFSET_X;
72 bill->target_y = computer->y + BILL_OFFSET_Y;
73 Horde_inc_counter(HORDE_COUNTER_ON, 1);
74 Horde_inc_counter(HORDE_COUNTER_OFF, -1);
75 bill->prev = NULL;
76 bill->next = NULL;
77 *billp = bill;
78 }
79
80 static int
step_size(unsigned int level)81 step_size(unsigned int level) {
82 return MIN(11 + level, 15);
83 }
84
85 /* Moves bill toward his target - returns whether or not he moved */
86 static int
move(Bill * bill,int mode)87 move(Bill *bill, int mode) {
88 int xdist = bill->target_x - bill->x;
89 int ydist = bill->target_y - bill->y;
90 int step = step_size(Game_level());
91 int dx, dy;
92 int signx = xdist >= 0 ? 1 : -1;
93 int signy = ydist >= 0 ? 1 : -1;
94 xdist = abs(xdist);
95 ydist = abs(ydist);
96 if (!xdist && !ydist)
97 return 0;
98 else if (xdist < step && ydist < step) {
99 bill->x = bill->target_x;
100 bill->y = bill->target_y;
101 }
102 else {
103 dx = (xdist*step*signx)/(xdist+ydist);
104 dy = (ydist*step*signy)/(xdist+ydist);
105 if (mode == FAST) {
106 dx *= 1.25;
107 dy *= 1.25;
108 }
109 bill->x += dx;
110 bill->y += dy;
111 if (dx < 0)
112 bill->cels = lcels;
113 else if (dx > 0)
114 bill->cels = rcels;
115 }
116 return 1;
117 }
118
119 static void
draw_std(Bill * bill)120 draw_std(Bill *bill) {
121 if (bill->cargo >= 0)
122 OS_draw(bill->cargo, bill->x + bill->x_offset,
123 bill->y + bill->y_offset);
124 UI_draw(bill->cels[bill->index], bill->x, bill->y);
125 }
126
127 static void
draw_at(Bill * bill)128 draw_at(Bill *bill) {
129 Computer *computer = Network_get_computer(bill->target_c);
130 if (bill->index > 6 && bill->index < 12)
131 OS_draw(0, bill->x + bill->sx, bill->y + bill->sy);
132 if (bill->cargo >= 0)
133 OS_draw(bill->cargo, bill->x + bill->x_offset,
134 bill->y + bill->y_offset);
135 UI_draw(bill->cels[bill->index], computer->x, computer->y);
136 }
137
138 static void
draw_stray(Bill * bill)139 draw_stray(Bill *bill) {
140 OS_draw(bill->cargo, bill->x, bill->y);
141 }
142
143 void
Bill_draw(Bill * bill)144 Bill_draw(Bill *bill) {
145 switch (bill->state) {
146 case BILL_STATE_IN:
147 case BILL_STATE_OUT:
148 case BILL_STATE_DYING:
149 draw_std(bill);
150 break;
151 case BILL_STATE_AT:
152 draw_at(bill);
153 break;
154 case BILL_STATE_STRAY:
155 draw_stray(bill);
156 break;
157 default:
158 break;
159 }
160 }
161
162 /* Update Bill's position */
163 static void
update_in(Bill * bill)164 update_in(Bill *bill) {
165 int moved = move(bill, SLOW);
166 Computer *computer = Network_get_computer(bill->target_c);
167 if (!moved && computer->os != OS_WINGDOWS && !computer->busy) {
168 computer->busy = 1;
169 bill->cels = acels;
170 bill->index = 0;
171 bill->state = BILL_STATE_AT;
172 return;
173 }
174 else if (!moved) {
175 int i;
176 do {
177 i = RAND(0, Network_num_computers() - 1);
178 } while (i == bill->target_c);
179 computer = Network_get_computer(i);
180 bill->target_c = i;
181 bill->target_x = computer->x + Computer_width() - BILL_OFFSET_X;
182 bill->target_y = computer->y + BILL_OFFSET_Y;
183 }
184 bill->index++;
185 bill->index %= WCELS;
186 bill->y_offset += (8 * (bill->index % 2) - 4);
187 }
188
189 /* Update Bill standing at a computer */
190 static void
update_at(Bill * bill)191 update_at(Bill *bill) {
192 Computer *computer = Network_get_computer(bill->target_c);
193 if (bill->index == 0 && computer->os == OS_OFF) {
194 bill->index = 6;
195 if (computer->stray == NULL)
196 bill->cargo = -1;
197 else {
198 bill->cargo = computer->stray->cargo;
199 Horde_remove_bill(computer->stray);
200 computer->stray = NULL;
201 }
202 } else
203 bill->index++;
204 if (bill->index == 13) {
205 bill->y_offset = -15;
206 bill->x_offset = -2;
207 get_border(&bill->target_x, &bill->target_y);
208 bill->index = 0;
209 bill->cels = lcels;
210 bill->state = BILL_STATE_OUT;
211 computer->busy = 0;
212 return;
213 }
214 bill->y_offset = height - OS_height();
215 switch (bill->index) {
216 case 1:
217 case 2:
218 bill->x -= 8;
219 bill->x_offset +=8;
220 break;
221 case 3:
222 bill->x -= 10;
223 bill->x_offset +=10;
224 break;
225 case 4:
226 bill->x += 3;
227 bill->x_offset -=3;
228 break;
229 case 5:
230 bill->x += 2;
231 bill->x_offset -=2;
232 break;
233 case 6:
234 if (computer->os != OS_OFF) {
235 Network_inc_counter(NETWORK_COUNTER_BASE, -1);
236 Network_inc_counter(NETWORK_COUNTER_OFF, 1);
237 bill->cargo = computer->os;
238 }
239 else {
240 bill->x -= 21;
241 bill->x_offset += 21;
242 }
243 computer->os = OS_OFF;
244 bill->y_offset = -15;
245 bill->x += 20;
246 bill->x_offset -=20;
247 break;
248 case 7:
249 bill->sy = bill->y_offset;
250 bill->sx = -2;
251 break;
252 case 8:
253 bill->sy = -15;
254 bill->sx = -2;
255 break;
256 case 9:
257 bill->sy = -7;
258 bill->sx = -7;
259 bill->x -= 8;
260 bill->x_offset +=8;
261 break;
262 case 10:
263 bill->sy = 0;
264 bill->sx = -7;
265 bill->x -= 15;
266 bill->x_offset +=15;
267 break;
268 case 11:
269 bill->sy = 0;
270 bill->sx = -7;
271 computer->os = OS_WINGDOWS;
272 Network_inc_counter(NETWORK_COUNTER_OFF, -1);
273 Network_inc_counter(NETWORK_COUNTER_WIN, 1);
274 break;
275 case 12:
276 bill->x += 11;
277 bill->x_offset -=11;
278 }
279 }
280
281 /* Updates Bill fleeing with his ill gotten gain */
282 static void
update_out(Bill * bill)283 update_out(Bill *bill) {
284 int screensize = Game_screensize();
285 if (UI_intersect(bill->x, bill->y, width, height, 0, 0,
286 screensize, screensize))
287 {
288 move(bill, FAST);
289 bill->index++;
290 bill->index %= WCELS;
291 bill->y_offset += (8*(bill->index%2)-4);
292 }
293 else {
294 Horde_remove_bill(bill);
295 Horde_inc_counter(HORDE_COUNTER_ON, -1);
296 Horde_inc_counter(HORDE_COUNTER_OFF, 1);
297 }
298 }
299
300
301 /* Updates a Bill who is dying */
302 static void
update_dying(Bill * bill)303 update_dying(Bill *bill) {
304 if (bill->index < DCELS - 1){
305 bill->y_offset += (bill->index * GRAVITY);
306 bill->index++;
307 }
308 else {
309 bill->y += bill->y_offset;
310 if (bill->cargo < 0 || bill->cargo == OS_WINGDOWS)
311 Horde_remove_bill(bill);
312 else {
313 Horde_move_bill(bill);
314 bill->state = BILL_STATE_STRAY;
315 }
316 Horde_inc_counter(HORDE_COUNTER_ON, -1);
317 }
318 }
319
320 void
Bill_update(Bill * bill)321 Bill_update(Bill *bill) {
322 switch (bill->state) {
323 case BILL_STATE_IN:
324 update_in(bill);
325 break;
326 case BILL_STATE_AT:
327 update_at(bill);
328 break;
329 case BILL_STATE_OUT:
330 update_out(bill);
331 break;
332 case BILL_STATE_DYING:
333 update_dying(bill);
334 break;
335 default:
336 break;
337 }
338 }
339
340 void
Bill_set_dying(Bill * bill)341 Bill_set_dying(Bill *bill) {
342 bill->index = -1;
343 bill->cels = dcels;
344 bill->x_offset = -2;
345 bill->y_offset = -15;
346 bill->state = BILL_STATE_DYING;
347 }
348
349 int
Bill_clicked(Bill * bill,int locx,int locy)350 Bill_clicked(Bill *bill, int locx, int locy) {
351 return (locx > bill->x && locx < bill->x + width &&
352 locy > bill->y && locy < bill->y + height);
353 }
354
355 int
Bill_clickedstray(Bill * bill,int locx,int locy)356 Bill_clickedstray(Bill *bill, int locx, int locy) {
357 return (locx > bill->x && locx < bill->x + OS_width() &&
358 locy > bill->y && locy < bill->y + OS_height());
359 }
360
361 void
Bill_load_pix()362 Bill_load_pix () {
363 int i;
364 for (i = 0; i < WCELS - 1; i++) {
365 UI_load_picture_indexed("billL", i, 1, &lcels[i]);
366 UI_load_picture_indexed("billR", i, 1, &rcels[i]);
367 }
368 lcels[WCELS - 1] = lcels[1];
369 rcels[WCELS - 1] = rcels[1];
370
371 for (i = 0; i < DCELS; i++)
372 UI_load_picture_indexed("billD", i, 1, &dcels[i]);
373 width = UI_picture_width(dcels[0]);
374 height = UI_picture_height(dcels[0]);
375
376 for (i = 0; i < ACELS; i++)
377 UI_load_picture_indexed("billA", i, 1, &acels[i]);
378 }
379
380 int
Bill_width()381 Bill_width() {
382 return width;
383 }
384
385 int
Bill_height()386 Bill_height() {
387 return height;
388 }
389
390 int
Bill_get_state(Bill * bill)391 Bill_get_state(Bill *bill) {
392 return bill->state;
393 }
394