Subversion Repositories Games.Rick Dangerous

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

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