summaryrefslogtreecommitdiff
path: root/apps/plugins/xrick/game.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/xrick/game.c')
-rw-r--r--apps/plugins/xrick/game.c722
1 files changed, 722 insertions, 0 deletions
diff --git a/apps/plugins/xrick/game.c b/apps/plugins/xrick/game.c
new file mode 100644
index 0000000000..ac99c1829e
--- /dev/null
+++ b/apps/plugins/xrick/game.c
@@ -0,0 +1,722 @@
1/*
2 * xrick/game.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/game.h"
17
18#include "xrick/draw.h"
19#include "xrick/maps.h"
20#include "xrick/ents.h"
21#include "xrick/e_rick.h"
22#include "xrick/e_sbonus.h"
23#include "xrick/e_them.h"
24#include "xrick/screens.h"
25#include "xrick/rects.h"
26#include "xrick/scroller.h"
27#include "xrick/control.h"
28#include "xrick/resources.h"
29
30#ifdef ENABLE_DEVTOOLS
31#include "xrick/devtools.h"
32#endif
33
34
35/*
36 * local typedefs
37 */
38typedef enum {
39#ifdef ENABLE_DEVTOOLS
40 DEVTOOLS,
41#endif
42 XRICK,
43 INIT_GAME, INIT_BUFFER,
44 INTRO_MAIN, INTRO_MAP,
45 PAUSE_PRESSED1, PAUSE_PRESSED1B, PAUSED, PAUSE_PRESSED2,
46 PLAY0, PLAY1, PLAY2, PLAY3,
47 CHAIN_SUBMAP, CHAIN_MAP, CHAIN_END,
48 SCROLL_UP, SCROLL_DOWN,
49 RESTART, GAMEOVER, GETNAME, EXIT
50} game_state_t;
51
52
53/*
54 * global vars
55 */
56U8 game_period = 0;
57bool game_waitevt = false;
58const rect_t *game_rects = NULL;
59
60U8 game_lives = 0;
61U8 game_bombs = 0;
62U8 game_bullets = 0;
63U32 game_score = 0;
64
65U16 game_map = 0;
66U16 game_submap = 0;
67
68U8 game_dir = RIGHT;
69bool game_chsm = false;
70
71bool game_cheat1 = false;
72bool game_cheat2 = false;
73bool game_cheat3 = false;
74
75
76/*
77 * local vars
78 */
79static U8 isave_frow;
80static game_state_t game_state;
81#ifdef ENABLE_SOUND
82static sound_t *currentMusic = NULL;
83#endif
84
85
86/*
87 * prototypes
88 */
89static void frame(void);
90static void init(void);
91static void play0(void);
92static void play3(void);
93static void restart(void);
94static void isave(void);
95static void irestore(void);
96
97
98/*
99 * Cheats
100 */
101#ifdef ENABLE_CHEATS
102void
103game_toggleCheat(cheat_t cheat)
104{
105 if (game_state != INTRO_MAIN && game_state != INTRO_MAP &&
106 game_state != GAMEOVER && game_state != GETNAME &&
107#ifdef ENABLE_DEVTOOLS
108 game_state != DEVTOOLS &&
109#endif
110 game_state != XRICK && game_state != EXIT)
111 {
112 switch (cheat)
113 {
114 case Cheat_UNLIMITED_ALL:
115 {
116 game_cheat1 = !game_cheat1;
117 game_lives = 6;
118 game_bombs = 6;
119 game_bullets = 6;
120 break;
121 }
122 case Cheat_NEVER_DIE:
123 {
124 game_cheat2 = !game_cheat2;
125 break;
126 }
127 case Cheat_EXPOSE:
128 {
129 game_cheat3 = !game_cheat3;
130 break;
131 }
132 }
133 draw_infos();
134 /* FIXME this should probably only raise a flag ... */
135 /* plus we only need to update INFORECT not the whole screen */
136 sysvid_update(&draw_SCREENRECT);
137 }
138}
139#endif
140
141#ifdef ENABLE_SOUND
142/*
143 * Music
144 */
145void
146game_setmusic(sound_t * newMusic, S8 loop)
147{
148 if (!newMusic)
149 {
150 return;
151 }
152
153 if (currentMusic)
154 {
155 game_stopmusic();
156 }
157
158 syssnd_play(newMusic, loop);
159
160 currentMusic = newMusic;
161}
162
163void
164game_stopmusic(void)
165{
166 syssnd_stop(currentMusic);
167 currentMusic = NULL;
168}
169#endif /*ENABLE_SOUND */
170
171/*
172 * Main loop
173 */
174void
175game_run(void)
176{
177 U32 currentTime,
178#ifdef ENABLE_SOUND
179 lastSoundTime = 0,
180#endif
181 lastFrameTime = 0;
182
183 if (!resources_load())
184 {
185 resources_unload();
186 return;
187 }
188
189 if (!sys_cacheData())
190 {
191 sys_uncacheData();
192 return;
193 }
194
195 game_period = sysarg_args_period ? sysarg_args_period : GAME_PERIOD;
196 game_state = XRICK;
197
198 /* main loop */
199 while (game_state != EXIT)
200 {
201 currentTime = sys_gettime();
202
203 if (currentTime - lastFrameTime >= game_period)
204 {
205 /* frame */
206 frame();
207
208 /* video */
209 /*DEBUG*//*game_rects=&draw_SCREENRECT;*//*DEBUG*/
210 sysvid_update(game_rects);
211
212 /* reset rectangles list */
213 rects_free(ent_rects);
214 ent_rects = NULL;
215 draw_STATUSRECT.next = NULL; /* FIXME freerects should handle this */
216
217 /* events */
218 if (game_waitevt)
219 {
220 sysevt_wait(); /* wait for an event */
221 }
222 else
223 {
224 sysevt_poll(); /* process events (non-blocking) */
225 }
226
227 lastFrameTime = currentTime;
228 }
229
230#ifdef ENABLE_SOUND
231 if (currentTime - lastSoundTime >= syssnd_period)
232 {
233 /* sound */
234 syssnd_update();
235
236 lastSoundTime = currentTime;
237 }
238#endif /* ENABLE_SOUND */
239
240 sys_yield();
241 }
242
243#ifdef ENABLE_SOUND
244 syssnd_stopAll();
245#endif
246
247 sys_uncacheData();
248
249 resources_unload();
250}
251
252/*
253 * Prepare frame
254 *
255 * This function loops forever: use 'return' when a frame is ready.
256 * When returning, game_rects must contain every parts of the buffer
257 * that have been modified.
258 */
259static void
260frame(void)
261{
262 while (1) {
263
264 switch (game_state) {
265
266
267
268#ifdef ENABLE_DEVTOOLS
269 case DEVTOOLS:
270 switch (devtools_run()) {
271 case SCREEN_RUNNING:
272 return;
273 case SCREEN_DONE:
274 game_state = INIT_GAME;
275 break;
276 case SCREEN_EXIT:
277 game_state = EXIT;
278 return;
279 }
280 break;
281#endif
282
283
284
285 case XRICK:
286 switch(screen_xrick()) {
287 case SCREEN_RUNNING:
288 return;
289 case SCREEN_DONE:
290#ifdef ENABLE_DEVTOOLS
291 game_state = DEVTOOLS;
292#else
293 game_state = INIT_GAME;
294#endif
295 break;
296 case SCREEN_EXIT:
297 game_state = EXIT;
298 return;
299 }
300 break;
301
302
303
304 case INIT_GAME:
305 init();
306 game_state = INTRO_MAIN;
307 break;
308
309
310
311 case INTRO_MAIN:
312 switch (screen_introMain()) {
313 case SCREEN_RUNNING:
314 return;
315 case SCREEN_DONE:
316 game_state = INTRO_MAP;
317 break;
318 case SCREEN_EXIT:
319 game_state = EXIT;
320 return;
321 }
322 break;
323
324
325
326 case INTRO_MAP:
327 switch (screen_introMap()) {
328 case SCREEN_RUNNING:
329 return;
330 case SCREEN_DONE:
331 game_waitevt = false;
332 game_state = INIT_BUFFER;
333 break;
334 case SCREEN_EXIT:
335 game_state = EXIT;
336 return;
337 }
338 break;
339
340
341
342 case INIT_BUFFER:
343 sysvid_clear(); /* clear buffer */
344 draw_map(); /* draw the map onto the buffer */
345 draw_drawStatus(); /* draw the status bar onto the buffer */
346#ifdef ENABLE_CHEATS
347 draw_infos(); /* draw the info bar onto the buffer */
348#endif
349 game_rects = &draw_SCREENRECT; /* request full buffer refresh */
350 game_state = PLAY0;
351 return;
352
353
354
355 case PAUSE_PRESSED1:
356 screen_pause(true);
357 game_state = PAUSE_PRESSED1B;
358 break;
359
360
361
362 case PAUSE_PRESSED1B:
363 if (control_test(Control_PAUSE))
364 return;
365 game_state = PAUSED;
366 break;
367
368
369
370 case PAUSED:
371 if (control_test(Control_PAUSE))
372 game_state = PAUSE_PRESSED2;
373 if (control_test(Control_EXIT))
374 game_state = EXIT;
375 return;
376
377
378
379 case PAUSE_PRESSED2:
380 if (!(control_test(Control_PAUSE))) {
381 game_waitevt = false;
382 screen_pause(false);
383#ifdef ENABLE_SOUND
384 syssnd_pauseAll(false);
385#endif
386 game_state = PLAY2;
387 }
388 return;
389
390
391
392 case PLAY0:
393 play0();
394 break;
395
396
397
398 case PLAY1:
399 if (control_test(Control_PAUSE)) {
400#ifdef ENABLE_SOUND
401 syssnd_pauseAll(true);
402#endif
403 game_waitevt = true;
404 game_state = PAUSE_PRESSED1;
405 }
406 else if (!control_active) {
407#ifdef ENABLE_SOUND
408 syssnd_pauseAll(true);
409#endif
410 game_waitevt = true;
411 screen_pause(true);
412 game_state = PAUSED;
413 }
414 else
415 game_state = PLAY2;
416 break;
417
418
419
420 case PLAY2:
421 if (e_rick_state_test(E_RICK_STDEAD)) { /* rick is dead */
422 if (game_cheat1 || --game_lives) {
423 game_state = RESTART;
424 } else {
425 game_state = GAMEOVER;
426 }
427 }
428 else if (game_chsm) /* request to chain to next submap */
429 game_state = CHAIN_SUBMAP;
430 else
431 game_state = PLAY3;
432 break;
433
434
435
436 case PLAY3:
437 play3();
438 return;
439
440
441
442 case CHAIN_SUBMAP:
443 if (map_chain())
444 game_state = CHAIN_END;
445 else {
446 game_bullets = 0x06;
447 game_bombs = 0x06;
448 game_map++;
449
450 if (game_map == map_nbr_maps - 1) {
451 /* reached end of game */
452 /* FIXME @292?*/
453 }
454
455 game_state = CHAIN_MAP;
456 }
457 break;
458
459
460
461 case CHAIN_MAP: /* CHAIN MAP */
462 switch (screen_introMap()) {
463 case SCREEN_RUNNING:
464 return;
465 case SCREEN_DONE:
466 if (game_map >= map_nbr_maps - 1) { /* reached end of game */
467 sysarg_args_map = 0;
468 sysarg_args_submap = 0;
469 game_state = GAMEOVER;
470 }
471 else { /* initialize game */
472 ent_ents[1].x = map_maps[game_map].x;
473 ent_ents[1].y = map_maps[game_map].y;
474 map_frow = (U8)map_maps[game_map].row;
475 game_submap = map_maps[game_map].submap;
476 game_state = CHAIN_END;
477 }
478 break;
479 case SCREEN_EXIT:
480 game_state = EXIT;
481 return;
482 }
483 break;
484
485
486
487 case CHAIN_END:
488 map_init(); /* initialize the map */
489 isave(); /* save data in case of a restart */
490 ent_clprev(); /* cleanup entities */
491 draw_map(); /* draw the map onto the buffer */
492 draw_drawStatus(); /* draw the status bar onto the buffer */
493 game_rects = &draw_SCREENRECT; /* request full screen refresh */
494 game_state = PLAY0;
495 return;
496
497
498
499 case SCROLL_UP:
500 switch (scroll_up()) {
501 case SCROLL_RUNNING:
502 return;
503 case SCROLL_DONE:
504 game_state = PLAY0;
505 break;
506 }
507 break;
508
509
510
511 case SCROLL_DOWN:
512 switch (scroll_down()) {
513 case SCROLL_RUNNING:
514 return;
515 case SCROLL_DONE:
516 game_state = PLAY0;
517 break;
518 }
519 break;
520
521
522
523 case RESTART:
524 restart();
525 game_state = PLAY0;
526 return;
527
528
529
530 case GAMEOVER:
531 switch (screen_gameover()) {
532 case SCREEN_RUNNING:
533 return;
534 case SCREEN_DONE:
535 game_state = GETNAME;
536 break;
537 case SCREEN_EXIT:
538 game_state = EXIT;
539 break;
540 }
541 break;
542
543
544
545 case GETNAME:
546 switch (screen_getname()) {
547 case SCREEN_RUNNING:
548 return;
549 case SCREEN_DONE:
550 game_state = INIT_GAME;
551 return;
552 case SCREEN_EXIT:
553 game_state = EXIT;
554 break;
555 }
556 break;
557
558
559
560 case EXIT:
561 return;
562
563 }
564 }
565}
566
567
568/*
569 * Initialize the game
570 */
571static void
572init(void)
573{
574 U8 i;
575
576 e_rick_state_clear(0xff);
577
578 game_lives = 6;
579 game_bombs = 6;
580 game_bullets = 6;
581 game_score = 0;
582
583 game_map = sysarg_args_map;
584
585 if (sysarg_args_submap == 0)
586 {
587 game_submap = map_maps[game_map].submap;
588 map_frow = (U8)map_maps[game_map].row;
589 }
590 else
591 {
592 /* dirty hack to determine frow */
593 game_submap = sysarg_args_submap;
594 i = 0;
595 while (i < map_nbr_connect &&
596 (map_connect[i].submap != game_submap ||
597 map_connect[i].dir != RIGHT))
598 {
599 i++;
600 }
601 map_frow = map_connect[i].rowin - 0x10;
602 ent_ents[1].y = 0x10 << 3;
603 }
604
605 ent_ents[1].x = map_maps[game_map].x;
606 ent_ents[1].y = map_maps[game_map].y;
607 ent_ents[1].w = 0x18;
608 ent_ents[1].h = 0x15;
609 ent_ents[1].n = 0x01;
610 ent_ents[1].sprite = 0x01;
611 ent_ents[1].front = false;
612 ent_ents[ENT_ENTSNUM].n = 0xFF;
613
614 map_resetMarks();
615
616 map_init();
617 isave();
618}
619
620
621/*
622 * play0
623 *
624 */
625static void
626play0(void)
627{
628 if (control_test(Control_END)) { /* request to end the game */
629 game_state = GAMEOVER;
630 return;
631 }
632
633 if (control_test(Control_EXIT)) { /* request to exit the game */
634 game_state = EXIT;
635 return;
636 }
637
638 ent_action(); /* run entities */
639 e_them_rndseed++; /* (0270) */
640
641 game_state = PLAY1;
642}
643
644
645/*
646 * play3
647 *
648 */
649static void
650play3(void)
651{
652 draw_clearStatus(); /* clear the status bar */
653 ent_draw(); /* draw all entities onto the buffer */
654 /* sound */
655 draw_drawStatus(); /* draw the status bar onto the buffer*/
656
657 game_rects = &draw_STATUSRECT; /* refresh status bar too */
658 draw_STATUSRECT.next = ent_rects; /* take care to cleanup draw_STATUSRECT->next later! */
659
660 if (!e_rick_state_test(E_RICK_STZOMBIE)) { /* need to scroll ? */
661 if (ent_ents[1].y >= 0xCC) {
662 game_state = SCROLL_UP;
663 return;
664 }
665 if (ent_ents[1].y <= 0x60) {
666 game_state = SCROLL_DOWN;
667 return;
668 }
669 }
670
671 game_state = PLAY0;
672}
673
674
675/*
676 * restart
677 *
678 */
679static void
680restart(void)
681{
682 e_rick_state_clear(E_RICK_STDEAD|E_RICK_STZOMBIE);
683
684 game_bullets = 6;
685 game_bombs = 6;
686
687 ent_ents[1].n = 1;
688
689 irestore();
690 map_init();
691 isave();
692 ent_clprev();
693 draw_map();
694 draw_drawStatus();
695 game_rects = &draw_SCREENRECT;
696}
697
698
699/*
700 * isave (0bbb)
701 *
702 */
703static void
704isave(void)
705{
706 e_rick_save();
707 isave_frow = map_frow;
708}
709
710
711/*
712 * irestore (0bdc)
713 *
714 */
715static void
716irestore(void)
717{
718 e_rick_restore();
719 map_frow = isave_frow;
720}
721
722/* eof */