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