Subversion Repositories Games.Rick Dangerous

Rev

Rev 1 | Rev 9 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1 pmbaty 1
/*
2
 * src/game.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 <stdlib.h>
15
 
16
#include "system.h"
17
#include "game.h"
18
 
19
#include "draw.h"
20
#include "maps.h"
21
#include "ents.h"
22
#include "e_rick.h"
23
#include "e_sbonus.h"
24
#include "e_them.h"
25
#include "screens.h"
26
#include "rects.h"
27
#include "scroller.h"
28
#include "control.h"
29
 
30
 
31
/*
32
 * local typedefs
33
 */
34
typedef enum
35
{
36
   INIT_GAME, INIT_BUFFER,
37
   INTRO_MAIN, INTRO_MAP,
38
   PAUSE_PRESSED1, PAUSE_PRESSED1B, PAUSED, PAUSE_PRESSED2,
39
   PLAY0, PLAY1, PLAY2, PLAY3,
40
   CHAIN_SUBMAP, CHAIN_MAP, CHAIN_END,
41
   SCROLL_UP, SCROLL_DOWN,
42
   RESTART, GAMEOVER, GETNAME, EXIT
43
} game_state_t;
44
 
45
 
46
/*
47
 * global vars
48
 */
49
U8 game_period = 0;
50
U8 game_waitevt = FALSE;
51
rect_t *game_rects = NULL;
52
 
53
U8 game_lives = 0;
54
U8 game_bombs = 0;
55
U8 game_bullets = 0;
56
U32 game_score = 0;
57
 
58
U16 game_map = 0;
59
U16 game_submap = 0;
60
 
61
U8 game_dir = 0;
62
U8 game_chsm = FALSE;
63
 
64
U8 want_infinitelives = FALSE;
65
 
66
 
67
hscore_t game_hscores[8] =
68
{
69
   { 8000, "DANGERSTU@" },
70
   { 7000, "SIMES@@@@@" },
71
   { 6000, "KEN@T@ZEN@" },
72
   { 5000, "BOBBLE@@@@" },
73
   { 4000, "GREG@LAA@@" },
74
   { 3000, "TELLY@@@@@" },
75
   { 2000, "CHIGLET@@@" },
76
   { 1000, "ANDYSPLEEN" }
77
};
78
 
79
sound_t *WAV_GAMEOVER;
80
sound_t *WAV_SBONUS2;
81
sound_t *WAV_BULLET;
82
sound_t *WAV_BOMBSHHT;
83
sound_t *WAV_EXPLODE;
84
sound_t *WAV_STICK;
85
sound_t *WAV_WALK;
86
sound_t *WAV_CRAWL;
87
sound_t *WAV_JUMP;
88
sound_t *WAV_PAD;
89
sound_t *WAV_BOX;
90
sound_t *WAV_BONUS;
91
sound_t *WAV_SBONUS1;
92
sound_t *WAV_DIE;
93
sound_t *WAV_ENTITY[10];
94
 
95
 
96
/*
97
 * local vars
98
 */
99
static U8 isave_frow;
100
static game_state_t game_state;
101
static sound_t *music_snd;
102
 
103
 
104
/*
105
 * prototypes
106
 */
107
static void frame (void);
108
static void init (void);
109
static void play0 (void);
110
static void play3 (void);
111
static void restart (void);
112
static void isave (void);
113
static void irestore (void);
114
static void loaddata (void);
115
static void freedata (void);
116
 
117
 
118
/*
119
 * Music
120
 */
121
void game_setmusic (char *name, U8 loop)
122
{
123
   U8 channel;
124
 
125
   if (music_snd)
126
      game_stopmusic ();
127
 
128
   music_snd = syssnd_load (name);
129
 
130
   if (music_snd)
131
   {
132
      music_snd->dispose = TRUE; /* music is always "fire and forget" */
133
      channel = syssnd_play(music_snd, loop);
134
   }
135
}
136
 
137
 
138
void game_stopmusic (void)
139
{
140
   syssnd_stopsound (music_snd);
141
   music_snd = NULL;
142
}
143
 
144
 
145
/*
146
 * Main loop
147
 */
148
void game_run (void)
149
{
150
   U32 tm, tmx;
151
 
152
   loaddata (); /* load cached data */
153
 
154
   tm = sys_gettime ();
155
   game_state = INIT_GAME;
156
 
157
   /* main loop */
158
   while (game_state != EXIT)
159
   {
160
      if (game_state != INTRO_MAP)
161
         game_period = sysarg_args_period ? sysarg_args_period : GAME_PERIOD;
162
      else
163
         game_period = (sysarg_args_period ? sysarg_args_period : GAME_PERIOD) / 2;
164
 
165
      /* timer */
166
      tmx = tm; tm = sys_gettime (); tmx = tm - tmx;
167
      if (tmx < game_period)
168
         sys_sleep (game_period - tmx);
169
 
170
      /* video */
171
      /*DEBUG*//*game_rects=&draw_SCREENRECT;*//*DEBUG*/
172
      sysvid_paint (game_rects);
173
      draw_STATUSRECT.next = NULL; /* FIXME freerects should handle this */
174
 
175
      /* sound */
176
      /*snd_mix ();*/
177
 
178
      /* events */
179
      if (game_waitevt)
180
         sysevt_wait (); /* wait for an event */
181
      else
182
         sysevt_poll (); /* process events (non-blocking) */
183
 
184
      /* frame */
185
      frame ();
186
   }
187
 
188
   freedata (); /* free cached data */
189
}
190
 
191
 
192
/*
193
 * Prepare frame
194
 *
195
 * This function loops forever: use 'return' when a frame is ready.
196
 * When returning, game_rects must contain every parts of the buffer
197
 * that have been modified.
198
 */
199
static void frame (void)
200
{
201
   while (1)
202
   {
203
 
204
      switch (game_state)
205
      {
206
 
207
 
208
      case INIT_GAME:
209
         init ();
210
         game_state = INTRO_MAIN;
211
         break;
212
 
213
 
214
 
215
      case INTRO_MAIN:
216
         switch (screen_introMain ())
217
         {
218
         case SCREEN_RUNNING:
219
            return;
220
         case SCREEN_DONE:
221
            game_state = INTRO_MAP;
222
            break;
223
         case SCREEN_EXIT:
224
            game_state = EXIT;
225
            return;
226
         }
227
      break;
228
 
229
 
230
 
231
      case INTRO_MAP:
232
         switch (screen_introMap ())
233
         {
234
         case SCREEN_RUNNING:
235
            return;
236
         case SCREEN_DONE:
237
            game_waitevt = FALSE;
238
            game_state = INIT_BUFFER;
239
            break;
240
         case SCREEN_EXIT:
241
            game_state = EXIT;
242
            return;
243
         }
244
      break;
245
 
246
 
247
 
248
      case INIT_BUFFER:
249
         syssnd_pause (FALSE, TRUE); // reset sounds
250
         sysvid_clear (); /* clear buffer */
251
         draw_map (); /* draw the map onto the buffer */
252
         draw_drawStatus (); /* draw the status bar onto the buffer */
253
         game_rects = &draw_SCREENRECT; /* request full buffer refresh */
254
         game_state = PLAY0;
255
         return;
256
 
257
 
258
 
259
      case PAUSE_PRESSED1:
260
         screen_pause (TRUE);
261
         game_state = PAUSE_PRESSED1B;
262
         break;
263
 
264
 
265
 
266
      case PAUSE_PRESSED1B:
267
         if (control_status & CONTROL_PAUSE)
268
            return;
269
         game_state = PAUSED;
270
         break;
271
 
272
 
273
 
274
      case PAUSED:
275
         if (control_status & CONTROL_PAUSE)
276
            game_state = PAUSE_PRESSED2;
277
         if (control_status & CONTROL_EXIT)
278
            game_state = EXIT;
279
         return;
280
 
281
 
282
 
283
      case PAUSE_PRESSED2:
284
         if (!(control_status & CONTROL_PAUSE))
285
         {
286
            game_waitevt = FALSE;
287
            screen_pause (FALSE);
288
            syssnd_pause (FALSE, FALSE);
289
            game_state = PLAY2;
290
         }
291
      return;
292
 
293
 
294
 
295
      case PLAY0:
296
         play0 ();
297
         break;
298
 
299
 
300
 
301
      case PLAY1:
302
         if (control_status & CONTROL_PAUSE)
303
         {
304
            syssnd_pause (TRUE, FALSE);
305
            game_waitevt = TRUE;
306
            game_state = PAUSE_PRESSED1;
307
         }
308
         else
309
            game_state = PLAY2;
310
         break;
311
 
312
 
313
 
314
      case PLAY2:
315
         if (E_RICK_STTST (E_RICK_STDEAD))
316
         {
317
            /* rick is dead */
318
            if (--game_lives)
319
            {
320
               game_state = RESTART;
321
               if (want_infinitelives)
322
                  game_lives = 6;
323
            }
324
            else
325
               game_state = GAMEOVER;
326
         }
327
         else if (game_chsm)
328
            game_state = CHAIN_SUBMAP; // request to chain to next submap
329
         else
330
            game_state = PLAY3;
331
         break;
332
 
333
 
334
 
335
      case PLAY3:
336
         play3 ();
337
         return;
338
 
339
 
340
 
341
      case CHAIN_SUBMAP:
342
         if (map_chain ())
343
            game_state = CHAIN_END;
344
         else
345
         {
346
            game_bullets = 0x06;
347
            game_bombs = 0x06;
348
            game_map++;
349
 
350
            if (game_map == 0x04)
351
            {
352
               /* reached end of game */
353
               /* FIXME @292?*/
354
            }
355
 
356
            game_state = CHAIN_MAP;
357
         }
358
         break;
359
 
360
 
361
 
362
      case CHAIN_MAP:/* CHAIN MAP */
363
         switch (screen_introMap ())
364
         {
365
         case SCREEN_RUNNING:
366
            return;
367
         case SCREEN_DONE:
368
            if (game_map >= 0x04)
369
            {
370
               /* reached end of game */
371
               sysarg_args_map = 0;
372
               sysarg_args_submap = 0;
373
               game_state = GAMEOVER;
374
            }
375
            else
376
            {
377
               /* initialize game */
378
               ent_ents[1].x = map_maps[game_map].x;
379
               ent_ents[1].y = map_maps[game_map].y;
380
               map_frow = (U8) map_maps[game_map].row;
381
               game_submap = map_maps[game_map].submap;
382
               game_state = CHAIN_END;
383
            }
384
            break;
385
               case SCREEN_EXIT:
386
            game_state = EXIT;
387
            return;
388
         }
389
         break;
390
 
391
 
392
 
393
      case CHAIN_END:
394
         syssnd_pause (FALSE, TRUE); // reset sounds
395
         map_init (); /* initialize the map */
396
         isave (); /* save data in case of a restart */
397
         ent_clprev (); /* cleanup entities */
398
         draw_map (); /* draw the map onto the buffer */
399
         draw_drawStatus (); /* draw the status bar onto the buffer */
7 pmbaty 400
         draw_STATUSRECT.next = NULL;
1 pmbaty 401
         game_state = PLAY3;
7 pmbaty 402
         frame (); // Pierre-Marie Baty -- patch by Jason Andersen: skip refreshing the screen for 2 pumps
403
         frame (); // to allow the sprites to settle into the appropriate frame
404
         game_rects = &draw_SCREENRECT;  /* request full screen refresh */
1 pmbaty 405
         return;
406
 
407
 
408
 
409
      case SCROLL_UP:
410
         switch (scroll_up ())
411
         {
412
         case SCROLL_RUNNING:
413
            return;
414
         case SCROLL_DONE:
415
            game_state = PLAY0;
416
            break;
417
         }
418
         break;
419
 
420
 
421
 
422
      case SCROLL_DOWN:
423
         switch (scroll_down ())
424
         {
425
         case SCROLL_RUNNING:
426
            return;
427
         case SCROLL_DONE:
428
            game_state = PLAY0;
429
            break;
430
         }
431
         break;
432
 
433
 
434
 
435
      case RESTART:
436
         restart ();
437
         game_state = PLAY0;
438
         return;
439
 
440
 
441
 
442
      case GAMEOVER:
443
         switch (screen_gameover ())
444
         {
445
         case SCREEN_RUNNING:
446
            return;
447
         case SCREEN_DONE:
448
            game_state = GETNAME;
449
            break;
450
         case SCREEN_EXIT:
451
            game_state = EXIT;
452
            break;
453
         }
454
         break;
455
 
456
 
457
 
458
      case GETNAME:
459
         switch (screen_getname ()) {
460
         case SCREEN_RUNNING:
461
            return;
462
         case SCREEN_DONE:
463
            game_state = INIT_GAME;
464
            return;
465
         case SCREEN_EXIT:
466
            game_state = EXIT;
467
            break;
468
         }
469
         break;
470
 
471
 
472
 
473
      case EXIT:
474
         return;
475
 
476
      }
477
   }
478
}
479
 
480
 
481
/*
482
 * Initialize the game
483
 */
484
static void init (void)
485
{
486
   U8 i;
487
 
488
   E_RICK_STRST (0xff);
489
 
490
   game_lives = 6;
491
   game_bombs = 6;
492
   game_bullets = 6;
493
   game_score = 0;
494
 
495
   game_map = sysarg_args_map;
496
 
497
   if (sysarg_args_submap == 0)
498
   {
499
      game_submap = map_maps[game_map].submap;
500
      map_frow = (U8)map_maps[game_map].row;
501
   }
502
   else
503
   {
504
      /* dirty hack to determine frow */
505
      game_submap = sysarg_args_submap;
506
      i = 0;
507
      while (i < MAP_NBR_CONNECT && (map_connect[i].submap != game_submap || map_connect[i].dir != RIGHT))
508
         i++;
509
      map_frow = map_connect[i].rowin - 0x10;
510
      ent_ents[1].y = 0x10 << 3;
511
   }
512
 
513
   ent_ents[1].x = map_maps[game_map].x;
514
   ent_ents[1].y = map_maps[game_map].y;
515
   ent_ents[1].w = 0x18;
516
   ent_ents[1].h = 0x15;
517
   ent_ents[1].n = 0x01;
518
   ent_ents[1].sprite = 0x01;
519
   ent_ents[1].front = FALSE;
520
   ent_ents[ENT_ENTSNUM].n = 0xFF;
521
 
522
   map_resetMarks ();
523
   map_init ();
524
   isave ();
525
}
526
 
527
 
528
/*
529
 * play0
530
 *
531
 */
532
static void play0 (void)
533
{
534
   if (control_status & CONTROL_END)
535
   {
536
      /* request to end the game */
537
      game_state = GAMEOVER;
538
      return;
539
   }
540
 
541
   if (control_last == CONTROL_EXIT)
542
   {
543
      /* request to exit the game */
544
      game_state = EXIT;
545
      return;
546
   }
547
 
548
   ent_action (); /* run entities */
549
   e_them_rndseed++; /* (0270) */
550
 
551
   game_state = PLAY1;
552
}
553
 
554
 
555
/*
556
 * play3
557
 *
558
 */
559
static void play3 (void)
560
{
561
   static rect_t *r;
562
 
563
   ent_draw (); /* draw all entities onto the buffer */
564
 
565
   /* sound */
566
   draw_drawStatus (); /* draw the status bar onto the buffer*/
567
 
568
   r = &draw_STATUSRECT;
569
   r->next = ent_rects; /* refresh status bar too */
570
   game_rects = r; /* take care to cleanup draw_STATUSRECT->next later! */
571
 
572
   if (!E_RICK_STTST (E_RICK_STZOMBIE))
573
   {
574
      /* need to scroll ? */
575
      if (ent_ents[1].y >= 0xCC)
576
      {
577
         game_state = SCROLL_UP;
578
         return;
579
      }
580
      if (ent_ents[1].y <= 0x60)
581
      {
582
         game_state = SCROLL_DOWN;
583
         return;
584
      }
585
   }
586
 
587
   game_state = PLAY0;
588
}
589
 
590
 
591
/*
592
 * restart
593
 *
594
 */
595
static void restart (void)
596
{
597
   E_RICK_STRST (E_RICK_STDEAD | E_RICK_STZOMBIE);
598
 
599
   game_bullets = 6;
600
   game_bombs = 6;
601
 
602
   ent_ents[1].n = 1;
603
 
604
   irestore ();
605
   map_init ();
606
   isave ();
607
   ent_clprev ();
608
   draw_map ();
609
   draw_drawStatus ();
610
   game_rects = &draw_SCREENRECT;
611
}
612
 
613
 
614
/*
615
 * isave (0bbb)
616
 *
617
 */
618
static void isave (void)
619
{
620
   e_rick_save ();
621
   isave_frow = map_frow;
622
}
623
 
624
 
625
/*
626
 * irestore (0bdc)
627
 *
628
 */
629
static void irestore (void)
630
{
631
   e_rick_restore ();
632
   map_frow = isave_frow;
633
}
634
 
635
 
636
/*
637
 *
638
 */
639
static void loaddata (void)
640
{
641
   /*
642
    * Cache sounds
643
    *
644
    * tune[0-5].wav not cached
645
    */
646
   WAV_GAMEOVER = syssnd_load ("sounds/gameover.wav");
647
   WAV_SBONUS2 = syssnd_load ("sounds/sbonus2.wav");
648
   WAV_BULLET = syssnd_load ("sounds/bullet.wav");
649
   WAV_BOMBSHHT = syssnd_load ("sounds/bombshht.wav");
650
   WAV_EXPLODE = syssnd_load ("sounds/explode.wav");
651
   WAV_STICK = syssnd_load ("sounds/stick.wav");
652
   WAV_WALK = syssnd_load ("sounds/walk.wav");
653
   WAV_CRAWL = syssnd_load ("sounds/crawl.wav");
654
   WAV_JUMP = syssnd_load ("sounds/jump.wav");
655
   WAV_PAD = syssnd_load ("sounds/pad.wav");
656
   WAV_BOX = syssnd_load ("sounds/box.wav");
657
   WAV_BONUS = syssnd_load ("sounds/bonus.wav");
658
   WAV_SBONUS1 = syssnd_load ("sounds/sbonus1.wav");
659
   WAV_DIE = syssnd_load ("sounds/die.wav");
660
   WAV_ENTITY[0] = syssnd_load ("sounds/ent0.wav");
661
   WAV_ENTITY[1] = syssnd_load ("sounds/ent1.wav");
662
   WAV_ENTITY[2] = syssnd_load ("sounds/ent2.wav");
663
   WAV_ENTITY[3] = syssnd_load ("sounds/ent3.wav");
664
   WAV_ENTITY[4] = syssnd_load ("sounds/ent4.wav");
665
   WAV_ENTITY[5] = syssnd_load ("sounds/ent5.wav");
666
   WAV_ENTITY[6] = syssnd_load ("sounds/ent6.wav");
667
   WAV_ENTITY[7] = syssnd_load ("sounds/ent7.wav");
668
   WAV_ENTITY[8] = syssnd_load ("sounds/ent8.wav");
669
}
670
 
671
 
672
/*
673
 *
674
 */
675
static void freedata (void)
676
{
677
   syssnd_stopall ();
678
   syssnd_free (WAV_GAMEOVER);
679
   syssnd_free (WAV_SBONUS2);
680
   syssnd_free (WAV_BULLET);
681
   syssnd_free (WAV_BOMBSHHT);
682
   syssnd_free (WAV_EXPLODE);
683
   syssnd_free (WAV_STICK);
684
   syssnd_free (WAV_WALK);
685
   syssnd_free (WAV_CRAWL);
686
   syssnd_free (WAV_JUMP);
687
   syssnd_free (WAV_PAD);
688
   syssnd_free (WAV_BOX);
689
   syssnd_free (WAV_BONUS);
690
   syssnd_free (WAV_SBONUS1);
691
   syssnd_free (WAV_DIE);
692
   syssnd_free (WAV_ENTITY[0]);
693
   syssnd_free (WAV_ENTITY[1]);
694
   syssnd_free (WAV_ENTITY[2]);
695
   syssnd_free (WAV_ENTITY[3]);
696
   syssnd_free (WAV_ENTITY[4]);
697
   syssnd_free (WAV_ENTITY[5]);
698
   syssnd_free (WAV_ENTITY[6]);
699
   syssnd_free (WAV_ENTITY[7]);
700
   syssnd_free (WAV_ENTITY[8]);
701
}