1 /*
2  * xrick/src/e_rick.c
3  *
4  * Copyright (C) 1998-2002 BigOrno (bigorno@bigorno.net). All rights reserved.
5  *
6  * The use and distribution terms for this software are contained in the file
7  * named README, which can be found in the root of this distribution. By
8  * using this software in any fashion, you are agreeing to be bound by the
9  * terms of this license.
10  *
11  * You must not remove this notice, or any other, from this software.
12  */
13 
14 #include "system.h"
15 #include "config.h"
16 #include "game.h"
17 #include "ents.h"
18 #include "e_rick.h"
19 
20 #include "e_bullet.h"
21 #include "e_bomb.h"
22 #include "control.h"
23 #include "maps.h"
24 #include "util.h"
25 
26 /*
27  * public vars
28  */
29 S16 e_rick_stop_x = 0;
30 S16 e_rick_stop_y = 0;
31 U8 e_rick_state = 0;
32 
33 /*
34  * local vars
35  */
36 static U8 scrawl;
37 
38 static U8 trigger = FALSE;
39 
40 static S8 offsx;
41 static U8 ylow;
42 static S16 offsy;
43 
44 static U8 seq;
45 
46 static U8 save_crawl;
47 static U16 save_x, save_y;
48 
49 
50 /*
51  * Box test
52  *
53  * ASM 113E (based on)
54  *
55  * e: entity to test against (corresponds to SI in asm code -- here DI
56  *    is assumed to point to rick).
57  * ret: TRUE/intersect, FALSE/not.
58  */
59 U8
e_rick_boxtest(U8 e)60 e_rick_boxtest(U8 e)
61 {
62 	/*
63 	 * rick: x+0x05 to x+0x11, y+[0x08 if rick's crawling] to y+0x14
64 	 * entity: x to x+w, y to y+h
65 	 */
66 
67 	if (E_RICK_ENT.x + 0x11 < ent_ents[e].x ||
68 		E_RICK_ENT.x + 0x05 > ent_ents[e].x + ent_ents[e].w ||
69 		E_RICK_ENT.y + 0x14 < ent_ents[e].y ||
70 		E_RICK_ENT.y + (E_RICK_STTST(E_RICK_STCRAWL) ? 0x08 : 0x00) > ent_ents[e].y + ent_ents[e].h - 1)
71 		return FALSE;
72 	else
73 		return TRUE;
74 }
75 
76 
77 
78 
79 /*
80  * Go zombie
81  *
82  * ASM 1851
83  */
84 void
e_rick_gozombie(void)85 e_rick_gozombie(void)
86 {
87 #ifdef ENABLE_CHEATS
88 	if (game_cheat2) return;
89 #endif
90 
91 	/* already zombie? */
92 	if E_RICK_STTST(E_RICK_STZOMBIE) return;
93 
94 #ifdef ENABLE_SOUND
95 	syssnd_play(WAV_DIE, 1);
96 #endif
97 
98 	E_RICK_STSET(E_RICK_STZOMBIE);
99 	offsy = -0x0400;
100 	offsx = (E_RICK_ENT.x > 0x80 ? -3 : +3);
101 	ylow = 0;
102 	E_RICK_ENT.front = TRUE;
103 }
104 
105 
106 /*
107  * Action sub-function for e_rick when zombie
108  *
109  * ASM 17DC
110  */
111 static void
e_rick_z_action(void)112 e_rick_z_action(void)
113 {
114 	U32 i;
115 
116 	/* sprite */
117 	E_RICK_ENT.sprite = (E_RICK_ENT.x & 0x04) ? 0x1A : 0x19;
118 
119 	/* x */
120 	E_RICK_ENT.x += offsx;
121 
122 	/* y */
123 	i = (E_RICK_ENT.y << 8) + offsy + ylow;
124 	E_RICK_ENT.y = i >> 8;
125 	offsy += 0x80;
126 	ylow = i;
127 
128 	/* dead when out of screen */
129 	if (E_RICK_ENT.y < 0 || E_RICK_ENT.y > 0x0140)
130 		E_RICK_STSET(E_RICK_STDEAD);
131 }
132 
133 
134 /*
135  * Action sub-function for e_rick.
136  *
137  * ASM 13BE
138  */
139 void
e_rick_action2(void)140 e_rick_action2(void)
141 {
142 	U8 env0, env1;
143 	S16 x, y;
144 	U32 i;
145 
146 	E_RICK_STRST(E_RICK_STSTOP|E_RICK_STSHOOT);
147 
148 	/* if zombie, run dedicated function and return */
149 	if E_RICK_STTST(E_RICK_STZOMBIE) {
150 		e_rick_z_action();
151 		return;
152 	}
153 
154 	/* climbing? */
155 	if E_RICK_STTST(E_RICK_STCLIMB)
156 		goto climbing;
157 
158 	/*
159 	* NOT CLIMBING
160 	*/
161 	E_RICK_STRST(E_RICK_STJUMP);
162 	/* calc y */
163 	i = (E_RICK_ENT.y << 8) + offsy + ylow;
164 	y = i >> 8;
165 	/* test environment */
166 	u_envtest(E_RICK_ENT.x, y, E_RICK_STTST(E_RICK_STCRAWL), &env0, &env1);
167 	/* stand up, if possible */
168 	if (E_RICK_STTST(E_RICK_STCRAWL) && !env0)
169 		E_RICK_STRST(E_RICK_STCRAWL);
170 	/* can move vertically? */
171 	if (env1 & (offsy < 0 ?
172 					MAP_EFLG_VERT|MAP_EFLG_SOLID|MAP_EFLG_SPAD :
173 					MAP_EFLG_VERT|MAP_EFLG_SOLID|MAP_EFLG_SPAD|MAP_EFLG_WAYUP))
174 		goto vert_not;
175 
176 	/*
177 	* VERTICAL MOVE
178 	*/
179 	E_RICK_STSET(E_RICK_STJUMP);
180 	/* killed? */
181 	if (env1 & MAP_EFLG_LETHAL) {
182 		e_rick_gozombie();
183 		return;
184 	}
185 	/* save */
186 	E_RICK_ENT.y = y;
187 	ylow = i;
188 	/* climb? */
189 	if ((env1 & MAP_EFLG_CLIMB) &&
190 			(control_status & (CONTROL_UP|CONTROL_DOWN))) {
191 		offsy = 0x0100;
192 		E_RICK_STSET(E_RICK_STCLIMB);
193 		return;
194 	}
195 	/* fall */
196 	offsy += 0x0080;
197 	if (offsy > 0x0800) {
198 		offsy = 0x0800;
199 		ylow = 0;
200 	}
201 
202 	/*
203 	* HORIZONTAL MOVE
204 	*/
205 	horiz:
206 	/* should move? */
207 	if (!(control_status & (CONTROL_LEFT|CONTROL_RIGHT))) {
208 		seq = 2; /* no: reset seq and return */
209 		return;
210 	}
211 	if (control_status & CONTROL_LEFT) {  /* move left */
212 		x = E_RICK_ENT.x - 2;
213 		game_dir = LEFT;
214 		if (x < 0) {  /* prev submap */
215 			game_chsm = TRUE;
216 			E_RICK_ENT.x = 0xe2;
217 			return;
218 		}
219 	} else {  /* move right */
220 		x = E_RICK_ENT.x + 2;
221 		game_dir = RIGHT;
222 		if (x >= 0xe8) {  /* next submap */
223 			game_chsm = TRUE;
224 			E_RICK_ENT.x = 0x04;
225 			return;
226 		}
227 	}
228 
229 	/* still within this map: test environment */
230 	u_envtest(x, E_RICK_ENT.y, E_RICK_STTST(E_RICK_STCRAWL), &env0, &env1);
231 
232 	/* save x-position if it is possible to move */
233 	if (!(env1 & (MAP_EFLG_SOLID|MAP_EFLG_SPAD|MAP_EFLG_WAYUP))) {
234 		E_RICK_ENT.x = x;
235 		if (env1 & MAP_EFLG_LETHAL) e_rick_gozombie();
236 	}
237 
238 	/* end */
239 	return;
240 
241   /*
242    * NO VERTICAL MOVE
243    */
244  vert_not:
245   if (offsy < 0) {
246     /* not climbing + trying to go _up_ not possible -> hit the roof */
247     E_RICK_STSET(E_RICK_STJUMP);  /* fall back to the ground */
248     E_RICK_ENT.y &= 0xF8;
249     offsy = 0;
250     ylow = 0;
251     goto horiz;
252   }
253   /* else: not climbing + trying to go _down_ not possible -> standing */
254   /* align to ground */
255   E_RICK_ENT.y &= 0xF8;
256   E_RICK_ENT.y |= 0x03;
257   ylow = 0;
258 
259   /* standing on a super pad? */
260   if ((env1 & MAP_EFLG_SPAD) && offsy >= 0X0200) {
261     offsy = (control_status & CONTROL_UP) ? 0xf800 : 0x00fe - offsy;
262 #ifdef ENABLE_SOUND
263 	syssnd_play(WAV_PAD, 1);
264 #endif
265     goto horiz;
266   }
267 
268   offsy = 0x0100;  /* reset*/
269 
270   /* standing. firing ? */
271   if (scrawl || !(control_status & CONTROL_FIRE))
272     goto firing_not;
273 
274   /*
275    * FIRING
276    */
277 	if (control_status & (CONTROL_LEFT|CONTROL_RIGHT)) {  /* stop */
278 		if (control_status & CONTROL_RIGHT)
279 		{
280 			game_dir = RIGHT;
281 			e_rick_stop_x = E_RICK_ENT.x + 0x17;
282 		} else {
283 			game_dir = LEFT;
284 			e_rick_stop_x = E_RICK_ENT.x;
285 		}
286 		e_rick_stop_y = E_RICK_ENT.y + 0x000E;
287 		E_RICK_STSET(E_RICK_STSTOP);
288 		return;
289 	}
290 
291   if (control_status == (CONTROL_FIRE|CONTROL_UP)) {  /* bullet */
292     E_RICK_STSET(E_RICK_STSHOOT);
293     /* not an automatic gun: shoot once only */
294     if (trigger)
295       return;
296     else
297       trigger = TRUE;
298     /* already a bullet in the air ... that's enough */
299     if (E_BULLET_ENT.n)
300       return;
301     /* else use a bullet, if any available */
302     if (!game_bullets)
303       return;
304 #ifdef ENABLE_CHEATS
305     if (!game_cheat1)
306       game_bullets--;
307 #endif
308     /* initialize bullet */
309     e_bullet_init(E_RICK_ENT.x, E_RICK_ENT.y);
310     return;
311   }
312 
313   trigger = FALSE; /* not shooting means trigger is released */
314   seq = 0; /* reset */
315 
316   if (control_status == (CONTROL_FIRE|CONTROL_DOWN)) {  /* bomb */
317     /* already a bomb ticking ... that's enough */
318     if (E_BOMB_ENT.n)
319       return;
320     /* else use a bomb, if any available */
321     if (!game_bombs)
322       return;
323 #ifdef ENABLE_CHEATS
324     if (!game_cheat1)
325       game_bombs--;
326 #endif
327     /* initialize bomb */
328     e_bomb_init(E_RICK_ENT.x, E_RICK_ENT.y);
329     return;
330   }
331 
332   return;
333 
334   /*
335    * NOT FIRING
336    */
337  firing_not:
338   if (control_status & CONTROL_UP) {  /* jump or climb */
339     if (env1 & MAP_EFLG_CLIMB) {  /* climb */
340       E_RICK_STSET(E_RICK_STCLIMB);
341       return;
342     }
343     offsy = -0x0580;  /* jump */
344     ylow = 0;
345 #ifdef ENABLE_SOUND
346     syssnd_play(WAV_JUMP, 1);
347 #endif
348     goto horiz;
349   }
350   if (control_status & CONTROL_DOWN) {  /* crawl or climb */
351     if ((env1 & MAP_EFLG_VERT) &&  /* can go down */
352 	!(control_status & (CONTROL_LEFT|CONTROL_RIGHT)) &&  /* + not moving horizontaly */
353 	(E_RICK_ENT.x & 0x1f) < 0x0a) {  /* + aligned -> climb */
354       E_RICK_ENT.x &= 0xf0;
355       E_RICK_ENT.x |= 0x04;
356       E_RICK_STSET(E_RICK_STCLIMB);
357     }
358     else {  /* crawl */
359       E_RICK_STSET(E_RICK_STCRAWL);
360       goto horiz;
361     }
362 
363   }
364   goto horiz;
365 
366 	/*
367 	* CLIMBING
368 	*/
369 	climbing:
370 		/* should move? */
371 		if (!(control_status & (CONTROL_UP|CONTROL_DOWN|CONTROL_LEFT|CONTROL_RIGHT))) {
372 			seq = 0; /* no: reset seq and return */
373 			return;
374 		}
375 
376 		if (control_status & (CONTROL_UP|CONTROL_DOWN)) {
377 			/* up-down: calc new y and test environment */
378 			y = E_RICK_ENT.y + ((control_status & CONTROL_UP) ? -0x02 : 0x02);
379 			u_envtest(E_RICK_ENT.x, y, E_RICK_STTST(E_RICK_STCRAWL), &env0, &env1);
380 			if (env1 & (MAP_EFLG_SOLID|MAP_EFLG_SPAD|MAP_EFLG_WAYUP) &&
381 					!(control_status & CONTROL_UP)) {
382 				/* FIXME what? */
383 				E_RICK_STRST(E_RICK_STCLIMB);
384 				return;
385 			}
386 			if (!(env1 & (MAP_EFLG_SOLID|MAP_EFLG_SPAD|MAP_EFLG_WAYUP)) ||
387 					(env1 & MAP_EFLG_WAYUP)) {
388 				/* ok to move, save */
389 				E_RICK_ENT.y = y;
390 				if (env1 & MAP_EFLG_LETHAL) {
391 					e_rick_gozombie();
392 					return;
393 				}
394 				if (!(env1 & (MAP_EFLG_VERT|MAP_EFLG_CLIMB))) {
395 					/* reached end of climb zone */
396 					offsy = (control_status & CONTROL_UP) ? -0x0300 : 0x0100;
397 #ifdef ENABLE_SOUND
398 					if (control_status & CONTROL_UP)
399 						syssnd_play(WAV_JUMP, 1);
400 #endif
401 					E_RICK_STRST(E_RICK_STCLIMB);
402 					return;
403 				}
404 			}
405 		}
406   if (control_status & (CONTROL_LEFT|CONTROL_RIGHT)) {
407     /* left-right: calc new x and test environment */
408     if (control_status & CONTROL_LEFT) {
409       x = E_RICK_ENT.x - 0x02;
410       if (x < 0) {  /* (i.e. negative) prev submap */
411 	game_chsm = TRUE;
412 	/*6dbd = 0x00;*/
413 	E_RICK_ENT.x = 0xe2;
414 	return;
415       }
416     }
417     else {
418       x = E_RICK_ENT.x + 0x02;
419       if (x >= 0xe8) {  /* next submap */
420 	game_chsm = TRUE;
421 	/*6dbd = 0x01;*/
422 	E_RICK_ENT.x = 0x04;
423 	return;
424       }
425     }
426     u_envtest(x, E_RICK_ENT.y, E_RICK_STTST(E_RICK_STCRAWL), &env0, &env1);
427     if (env1 & (MAP_EFLG_SOLID|MAP_EFLG_SPAD)) return;
428     E_RICK_ENT.x = x;
429     if (env1 & MAP_EFLG_LETHAL) {
430       e_rick_gozombie();
431       return;
432     }
433 
434     if (env1 & (MAP_EFLG_VERT|MAP_EFLG_CLIMB)) return;
435     E_RICK_STRST(E_RICK_STCLIMB);
436     if (control_status & CONTROL_UP)
437       offsy = -0x0300;
438   }
439 }
440 
441 
442 /*
443  * Action function for e_rick
444  *
445  * ASM 12CA
446  */
e_rick_action(UNUSED (U8 e))447 void e_rick_action(UNUSED(U8 e))
448 {
449 	static U8 stopped = FALSE; /* is this the most elegant way? */
450 
451 	e_rick_action2();
452 
453 	scrawl = E_RICK_STTST(E_RICK_STCRAWL);
454 
455 	if E_RICK_STTST(E_RICK_STZOMBIE)
456 		return;
457 
458 	/*
459 	 * set sprite
460 	 */
461 
462 	if E_RICK_STTST(E_RICK_STSTOP) {
463 		E_RICK_ENT.sprite = (game_dir ? 0x17 : 0x0B);
464 #ifdef ENABLE_SOUND
465 		if (!stopped)
466 		{
467 			syssnd_play(WAV_STICK, 1);
468 			stopped = TRUE;
469 		}
470 #endif
471 		return;
472 	}
473 
474 	stopped = FALSE;
475 
476 	if E_RICK_STTST(E_RICK_STSHOOT) {
477 		E_RICK_ENT.sprite = (game_dir ? 0x16 : 0x0A);
478 		return;
479 	}
480 
481 	if E_RICK_STTST(E_RICK_STCLIMB) {
482 		E_RICK_ENT.sprite = (((E_RICK_ENT.x ^ E_RICK_ENT.y) & 0x04) ? 0x18 : 0x0c);
483 #ifdef ENABLE_SOUND
484 		seq = (seq + 1) & 0x03;
485 		if (seq == 0) syssnd_play(WAV_WALK, 1);
486 #endif
487 		return;
488 	}
489 
490 	if E_RICK_STTST(E_RICK_STCRAWL)
491 	{
492 		E_RICK_ENT.sprite = (game_dir ? 0x13 : 0x07);
493 		if (E_RICK_ENT.x & 0x04) E_RICK_ENT.sprite++;
494 #ifdef ENABLE_SOUND
495 		seq = (seq + 1) & 0x03;
496 		if (seq == 0) syssnd_play(WAV_CRAWL, 1);
497 #endif
498 		return;
499 	}
500 
501 	if E_RICK_STTST(E_RICK_STJUMP)
502 	{
503 		E_RICK_ENT.sprite = (game_dir ? 0x15 : 0x06);
504 		return;
505 	}
506 
507 	seq++;
508 
509 	if (seq >= 0x14)
510 	{
511 #ifdef ENABLE_SOUND
512 		syssnd_play(WAV_WALK, 1);
513 #endif
514 		seq = 0x04;
515 	}
516 #ifdef ENABLE_SOUND
517   else
518   if (seq == 0x0C)
519     syssnd_play(WAV_WALK, 1);
520 #endif
521 
522   E_RICK_ENT.sprite = (seq >> 2) + 1 + (game_dir ? 0x0c : 0x00);
523 }
524 
525 
526 /*
527  * Save status
528  *
529  * ASM part of 0x0BBB
530  */
e_rick_save(void)531 void e_rick_save(void)
532 {
533 	save_x = E_RICK_ENT.x;
534 	save_y = E_RICK_ENT.y;
535 	save_crawl = E_RICK_STTST(E_RICK_STCRAWL);
536 	/* FIXME
537 	 * save_C0 = E_RICK_ENT.b0C;
538 	 * plus some 6DBC stuff?
539 	 */
540 }
541 
542 
543 /*
544  * Restore status
545  *
546  * ASM part of 0x0BDC
547  */
e_rick_restore(void)548 void e_rick_restore(void)
549 {
550 	E_RICK_ENT.x = save_x;
551 	E_RICK_ENT.y = save_y;
552 	E_RICK_ENT.front = FALSE;
553 	if (save_crawl)
554 		E_RICK_STSET(E_RICK_STCRAWL);
555 	else
556 		E_RICK_STRST(E_RICK_STCRAWL);
557 	/* FIXME
558 	 * E_RICK_ENT.b0C = save_C0;
559 	 * plus some 6DBC stuff?
560 	 */
561 }
562 
563 
564 
565 
566 /* eof */
567