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