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