Subversion Repositories Games.Rick Dangerous

Rev

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