forked from len0rd/rockbox
added xrick game
original xrick code by 'BigOrno' at: http://www.bigorno.net/xrick/ Rockbox port, plus bugfixes at: https://github.com/pierluigi-vicinanza/xrick Further changes: * Additonal fixes from g#3026 * Port to modern plugin API * Add Pluginlib keymap fallback * Support all >1bpp screens * Fix build warnings in miniz * Better error message when resources are missing Change-Id: Id83928bc2539901b0221692f65cbca41389c58e7
This commit is contained in:
parent
6f1e67e5e3
commit
102c374248
88 changed files with 16514 additions and 62 deletions
722
apps/plugins/xrick/game.c
Normal file
722
apps/plugins/xrick/game.c
Normal file
|
|
@ -0,0 +1,722 @@
|
|||
/*
|
||||
* xrick/game.c
|
||||
*
|
||||
* Copyright (C) 1998-2002 BigOrno (bigorno@bigorno.net).
|
||||
* Copyright (C) 2008-2014 Pierluigi Vicinanza.
|
||||
* All rights reserved.
|
||||
*
|
||||
* The use and distribution terms for this software are contained in the file
|
||||
* named README, which can be found in the root of this distribution. By
|
||||
* using this software in any fashion, you are agreeing to be bound by the
|
||||
* terms of this license.
|
||||
*
|
||||
* You must not remove this notice, or any other, from this software.
|
||||
*/
|
||||
|
||||
#include "xrick/game.h"
|
||||
|
||||
#include "xrick/draw.h"
|
||||
#include "xrick/maps.h"
|
||||
#include "xrick/ents.h"
|
||||
#include "xrick/e_rick.h"
|
||||
#include "xrick/e_sbonus.h"
|
||||
#include "xrick/e_them.h"
|
||||
#include "xrick/screens.h"
|
||||
#include "xrick/rects.h"
|
||||
#include "xrick/scroller.h"
|
||||
#include "xrick/control.h"
|
||||
#include "xrick/resources.h"
|
||||
|
||||
#ifdef ENABLE_DEVTOOLS
|
||||
#include "xrick/devtools.h"
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* local typedefs
|
||||
*/
|
||||
typedef enum {
|
||||
#ifdef ENABLE_DEVTOOLS
|
||||
DEVTOOLS,
|
||||
#endif
|
||||
XRICK,
|
||||
INIT_GAME, INIT_BUFFER,
|
||||
INTRO_MAIN, INTRO_MAP,
|
||||
PAUSE_PRESSED1, PAUSE_PRESSED1B, PAUSED, PAUSE_PRESSED2,
|
||||
PLAY0, PLAY1, PLAY2, PLAY3,
|
||||
CHAIN_SUBMAP, CHAIN_MAP, CHAIN_END,
|
||||
SCROLL_UP, SCROLL_DOWN,
|
||||
RESTART, GAMEOVER, GETNAME, EXIT
|
||||
} game_state_t;
|
||||
|
||||
|
||||
/*
|
||||
* global vars
|
||||
*/
|
||||
U8 game_period = 0;
|
||||
bool game_waitevt = false;
|
||||
const rect_t *game_rects = NULL;
|
||||
|
||||
U8 game_lives = 0;
|
||||
U8 game_bombs = 0;
|
||||
U8 game_bullets = 0;
|
||||
U32 game_score = 0;
|
||||
|
||||
U16 game_map = 0;
|
||||
U16 game_submap = 0;
|
||||
|
||||
U8 game_dir = RIGHT;
|
||||
bool game_chsm = false;
|
||||
|
||||
bool game_cheat1 = false;
|
||||
bool game_cheat2 = false;
|
||||
bool game_cheat3 = false;
|
||||
|
||||
|
||||
/*
|
||||
* local vars
|
||||
*/
|
||||
static U8 isave_frow;
|
||||
static game_state_t game_state;
|
||||
#ifdef ENABLE_SOUND
|
||||
static sound_t *currentMusic = NULL;
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* prototypes
|
||||
*/
|
||||
static void frame(void);
|
||||
static void init(void);
|
||||
static void play0(void);
|
||||
static void play3(void);
|
||||
static void restart(void);
|
||||
static void isave(void);
|
||||
static void irestore(void);
|
||||
|
||||
|
||||
/*
|
||||
* Cheats
|
||||
*/
|
||||
#ifdef ENABLE_CHEATS
|
||||
void
|
||||
game_toggleCheat(cheat_t cheat)
|
||||
{
|
||||
if (game_state != INTRO_MAIN && game_state != INTRO_MAP &&
|
||||
game_state != GAMEOVER && game_state != GETNAME &&
|
||||
#ifdef ENABLE_DEVTOOLS
|
||||
game_state != DEVTOOLS &&
|
||||
#endif
|
||||
game_state != XRICK && game_state != EXIT)
|
||||
{
|
||||
switch (cheat)
|
||||
{
|
||||
case Cheat_UNLIMITED_ALL:
|
||||
{
|
||||
game_cheat1 = !game_cheat1;
|
||||
game_lives = 6;
|
||||
game_bombs = 6;
|
||||
game_bullets = 6;
|
||||
break;
|
||||
}
|
||||
case Cheat_NEVER_DIE:
|
||||
{
|
||||
game_cheat2 = !game_cheat2;
|
||||
break;
|
||||
}
|
||||
case Cheat_EXPOSE:
|
||||
{
|
||||
game_cheat3 = !game_cheat3;
|
||||
break;
|
||||
}
|
||||
}
|
||||
draw_infos();
|
||||
/* FIXME this should probably only raise a flag ... */
|
||||
/* plus we only need to update INFORECT not the whole screen */
|
||||
sysvid_update(&draw_SCREENRECT);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_SOUND
|
||||
/*
|
||||
* Music
|
||||
*/
|
||||
void
|
||||
game_setmusic(sound_t * newMusic, S8 loop)
|
||||
{
|
||||
if (!newMusic)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (currentMusic)
|
||||
{
|
||||
game_stopmusic();
|
||||
}
|
||||
|
||||
syssnd_play(newMusic, loop);
|
||||
|
||||
currentMusic = newMusic;
|
||||
}
|
||||
|
||||
void
|
||||
game_stopmusic(void)
|
||||
{
|
||||
syssnd_stop(currentMusic);
|
||||
currentMusic = NULL;
|
||||
}
|
||||
#endif /*ENABLE_SOUND */
|
||||
|
||||
/*
|
||||
* Main loop
|
||||
*/
|
||||
void
|
||||
game_run(void)
|
||||
{
|
||||
U32 currentTime,
|
||||
#ifdef ENABLE_SOUND
|
||||
lastSoundTime = 0,
|
||||
#endif
|
||||
lastFrameTime = 0;
|
||||
|
||||
if (!resources_load())
|
||||
{
|
||||
resources_unload();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!sys_cacheData())
|
||||
{
|
||||
sys_uncacheData();
|
||||
return;
|
||||
}
|
||||
|
||||
game_period = sysarg_args_period ? sysarg_args_period : GAME_PERIOD;
|
||||
game_state = XRICK;
|
||||
|
||||
/* main loop */
|
||||
while (game_state != EXIT)
|
||||
{
|
||||
currentTime = sys_gettime();
|
||||
|
||||
if (currentTime - lastFrameTime >= game_period)
|
||||
{
|
||||
/* frame */
|
||||
frame();
|
||||
|
||||
/* video */
|
||||
/*DEBUG*//*game_rects=&draw_SCREENRECT;*//*DEBUG*/
|
||||
sysvid_update(game_rects);
|
||||
|
||||
/* reset rectangles list */
|
||||
rects_free(ent_rects);
|
||||
ent_rects = NULL;
|
||||
draw_STATUSRECT.next = NULL; /* FIXME freerects should handle this */
|
||||
|
||||
/* events */
|
||||
if (game_waitevt)
|
||||
{
|
||||
sysevt_wait(); /* wait for an event */
|
||||
}
|
||||
else
|
||||
{
|
||||
sysevt_poll(); /* process events (non-blocking) */
|
||||
}
|
||||
|
||||
lastFrameTime = currentTime;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_SOUND
|
||||
if (currentTime - lastSoundTime >= syssnd_period)
|
||||
{
|
||||
/* sound */
|
||||
syssnd_update();
|
||||
|
||||
lastSoundTime = currentTime;
|
||||
}
|
||||
#endif /* ENABLE_SOUND */
|
||||
|
||||
sys_yield();
|
||||
}
|
||||
|
||||
#ifdef ENABLE_SOUND
|
||||
syssnd_stopAll();
|
||||
#endif
|
||||
|
||||
sys_uncacheData();
|
||||
|
||||
resources_unload();
|
||||
}
|
||||
|
||||
/*
|
||||
* Prepare frame
|
||||
*
|
||||
* This function loops forever: use 'return' when a frame is ready.
|
||||
* When returning, game_rects must contain every parts of the buffer
|
||||
* that have been modified.
|
||||
*/
|
||||
static void
|
||||
frame(void)
|
||||
{
|
||||
while (1) {
|
||||
|
||||
switch (game_state) {
|
||||
|
||||
|
||||
|
||||
#ifdef ENABLE_DEVTOOLS
|
||||
case DEVTOOLS:
|
||||
switch (devtools_run()) {
|
||||
case SCREEN_RUNNING:
|
||||
return;
|
||||
case SCREEN_DONE:
|
||||
game_state = INIT_GAME;
|
||||
break;
|
||||
case SCREEN_EXIT:
|
||||
game_state = EXIT;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
case XRICK:
|
||||
switch(screen_xrick()) {
|
||||
case SCREEN_RUNNING:
|
||||
return;
|
||||
case SCREEN_DONE:
|
||||
#ifdef ENABLE_DEVTOOLS
|
||||
game_state = DEVTOOLS;
|
||||
#else
|
||||
game_state = INIT_GAME;
|
||||
#endif
|
||||
break;
|
||||
case SCREEN_EXIT:
|
||||
game_state = EXIT;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
|
||||
case INIT_GAME:
|
||||
init();
|
||||
game_state = INTRO_MAIN;
|
||||
break;
|
||||
|
||||
|
||||
|
||||
case INTRO_MAIN:
|
||||
switch (screen_introMain()) {
|
||||
case SCREEN_RUNNING:
|
||||
return;
|
||||
case SCREEN_DONE:
|
||||
game_state = INTRO_MAP;
|
||||
break;
|
||||
case SCREEN_EXIT:
|
||||
game_state = EXIT;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
|
||||
case INTRO_MAP:
|
||||
switch (screen_introMap()) {
|
||||
case SCREEN_RUNNING:
|
||||
return;
|
||||
case SCREEN_DONE:
|
||||
game_waitevt = false;
|
||||
game_state = INIT_BUFFER;
|
||||
break;
|
||||
case SCREEN_EXIT:
|
||||
game_state = EXIT;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
|
||||
case INIT_BUFFER:
|
||||
sysvid_clear(); /* clear buffer */
|
||||
draw_map(); /* draw the map onto the buffer */
|
||||
draw_drawStatus(); /* draw the status bar onto the buffer */
|
||||
#ifdef ENABLE_CHEATS
|
||||
draw_infos(); /* draw the info bar onto the buffer */
|
||||
#endif
|
||||
game_rects = &draw_SCREENRECT; /* request full buffer refresh */
|
||||
game_state = PLAY0;
|
||||
return;
|
||||
|
||||
|
||||
|
||||
case PAUSE_PRESSED1:
|
||||
screen_pause(true);
|
||||
game_state = PAUSE_PRESSED1B;
|
||||
break;
|
||||
|
||||
|
||||
|
||||
case PAUSE_PRESSED1B:
|
||||
if (control_test(Control_PAUSE))
|
||||
return;
|
||||
game_state = PAUSED;
|
||||
break;
|
||||
|
||||
|
||||
|
||||
case PAUSED:
|
||||
if (control_test(Control_PAUSE))
|
||||
game_state = PAUSE_PRESSED2;
|
||||
if (control_test(Control_EXIT))
|
||||
game_state = EXIT;
|
||||
return;
|
||||
|
||||
|
||||
|
||||
case PAUSE_PRESSED2:
|
||||
if (!(control_test(Control_PAUSE))) {
|
||||
game_waitevt = false;
|
||||
screen_pause(false);
|
||||
#ifdef ENABLE_SOUND
|
||||
syssnd_pauseAll(false);
|
||||
#endif
|
||||
game_state = PLAY2;
|
||||
}
|
||||
return;
|
||||
|
||||
|
||||
|
||||
case PLAY0:
|
||||
play0();
|
||||
break;
|
||||
|
||||
|
||||
|
||||
case PLAY1:
|
||||
if (control_test(Control_PAUSE)) {
|
||||
#ifdef ENABLE_SOUND
|
||||
syssnd_pauseAll(true);
|
||||
#endif
|
||||
game_waitevt = true;
|
||||
game_state = PAUSE_PRESSED1;
|
||||
}
|
||||
else if (!control_active) {
|
||||
#ifdef ENABLE_SOUND
|
||||
syssnd_pauseAll(true);
|
||||
#endif
|
||||
game_waitevt = true;
|
||||
screen_pause(true);
|
||||
game_state = PAUSED;
|
||||
}
|
||||
else
|
||||
game_state = PLAY2;
|
||||
break;
|
||||
|
||||
|
||||
|
||||
case PLAY2:
|
||||
if (e_rick_state_test(E_RICK_STDEAD)) { /* rick is dead */
|
||||
if (game_cheat1 || --game_lives) {
|
||||
game_state = RESTART;
|
||||
} else {
|
||||
game_state = GAMEOVER;
|
||||
}
|
||||
}
|
||||
else if (game_chsm) /* request to chain to next submap */
|
||||
game_state = CHAIN_SUBMAP;
|
||||
else
|
||||
game_state = PLAY3;
|
||||
break;
|
||||
|
||||
|
||||
|
||||
case PLAY3:
|
||||
play3();
|
||||
return;
|
||||
|
||||
|
||||
|
||||
case CHAIN_SUBMAP:
|
||||
if (map_chain())
|
||||
game_state = CHAIN_END;
|
||||
else {
|
||||
game_bullets = 0x06;
|
||||
game_bombs = 0x06;
|
||||
game_map++;
|
||||
|
||||
if (game_map == map_nbr_maps - 1) {
|
||||
/* reached end of game */
|
||||
/* FIXME @292?*/
|
||||
}
|
||||
|
||||
game_state = CHAIN_MAP;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
|
||||
case CHAIN_MAP: /* CHAIN MAP */
|
||||
switch (screen_introMap()) {
|
||||
case SCREEN_RUNNING:
|
||||
return;
|
||||
case SCREEN_DONE:
|
||||
if (game_map >= map_nbr_maps - 1) { /* reached end of game */
|
||||
sysarg_args_map = 0;
|
||||
sysarg_args_submap = 0;
|
||||
game_state = GAMEOVER;
|
||||
}
|
||||
else { /* initialize game */
|
||||
ent_ents[1].x = map_maps[game_map].x;
|
||||
ent_ents[1].y = map_maps[game_map].y;
|
||||
map_frow = (U8)map_maps[game_map].row;
|
||||
game_submap = map_maps[game_map].submap;
|
||||
game_state = CHAIN_END;
|
||||
}
|
||||
break;
|
||||
case SCREEN_EXIT:
|
||||
game_state = EXIT;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
|
||||
case CHAIN_END:
|
||||
map_init(); /* initialize the map */
|
||||
isave(); /* save data in case of a restart */
|
||||
ent_clprev(); /* cleanup entities */
|
||||
draw_map(); /* draw the map onto the buffer */
|
||||
draw_drawStatus(); /* draw the status bar onto the buffer */
|
||||
game_rects = &draw_SCREENRECT; /* request full screen refresh */
|
||||
game_state = PLAY0;
|
||||
return;
|
||||
|
||||
|
||||
|
||||
case SCROLL_UP:
|
||||
switch (scroll_up()) {
|
||||
case SCROLL_RUNNING:
|
||||
return;
|
||||
case SCROLL_DONE:
|
||||
game_state = PLAY0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
|
||||
case SCROLL_DOWN:
|
||||
switch (scroll_down()) {
|
||||
case SCROLL_RUNNING:
|
||||
return;
|
||||
case SCROLL_DONE:
|
||||
game_state = PLAY0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
|
||||
case RESTART:
|
||||
restart();
|
||||
game_state = PLAY0;
|
||||
return;
|
||||
|
||||
|
||||
|
||||
case GAMEOVER:
|
||||
switch (screen_gameover()) {
|
||||
case SCREEN_RUNNING:
|
||||
return;
|
||||
case SCREEN_DONE:
|
||||
game_state = GETNAME;
|
||||
break;
|
||||
case SCREEN_EXIT:
|
||||
game_state = EXIT;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
|
||||
case GETNAME:
|
||||
switch (screen_getname()) {
|
||||
case SCREEN_RUNNING:
|
||||
return;
|
||||
case SCREEN_DONE:
|
||||
game_state = INIT_GAME;
|
||||
return;
|
||||
case SCREEN_EXIT:
|
||||
game_state = EXIT;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
|
||||
case EXIT:
|
||||
return;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Initialize the game
|
||||
*/
|
||||
static void
|
||||
init(void)
|
||||
{
|
||||
U8 i;
|
||||
|
||||
e_rick_state_clear(0xff);
|
||||
|
||||
game_lives = 6;
|
||||
game_bombs = 6;
|
||||
game_bullets = 6;
|
||||
game_score = 0;
|
||||
|
||||
game_map = sysarg_args_map;
|
||||
|
||||
if (sysarg_args_submap == 0)
|
||||
{
|
||||
game_submap = map_maps[game_map].submap;
|
||||
map_frow = (U8)map_maps[game_map].row;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* dirty hack to determine frow */
|
||||
game_submap = sysarg_args_submap;
|
||||
i = 0;
|
||||
while (i < map_nbr_connect &&
|
||||
(map_connect[i].submap != game_submap ||
|
||||
map_connect[i].dir != RIGHT))
|
||||
{
|
||||
i++;
|
||||
}
|
||||
map_frow = map_connect[i].rowin - 0x10;
|
||||
ent_ents[1].y = 0x10 << 3;
|
||||
}
|
||||
|
||||
ent_ents[1].x = map_maps[game_map].x;
|
||||
ent_ents[1].y = map_maps[game_map].y;
|
||||
ent_ents[1].w = 0x18;
|
||||
ent_ents[1].h = 0x15;
|
||||
ent_ents[1].n = 0x01;
|
||||
ent_ents[1].sprite = 0x01;
|
||||
ent_ents[1].front = false;
|
||||
ent_ents[ENT_ENTSNUM].n = 0xFF;
|
||||
|
||||
map_resetMarks();
|
||||
|
||||
map_init();
|
||||
isave();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* play0
|
||||
*
|
||||
*/
|
||||
static void
|
||||
play0(void)
|
||||
{
|
||||
if (control_test(Control_END)) { /* request to end the game */
|
||||
game_state = GAMEOVER;
|
||||
return;
|
||||
}
|
||||
|
||||
if (control_test(Control_EXIT)) { /* request to exit the game */
|
||||
game_state = EXIT;
|
||||
return;
|
||||
}
|
||||
|
||||
ent_action(); /* run entities */
|
||||
e_them_rndseed++; /* (0270) */
|
||||
|
||||
game_state = PLAY1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* play3
|
||||
*
|
||||
*/
|
||||
static void
|
||||
play3(void)
|
||||
{
|
||||
draw_clearStatus(); /* clear the status bar */
|
||||
ent_draw(); /* draw all entities onto the buffer */
|
||||
/* sound */
|
||||
draw_drawStatus(); /* draw the status bar onto the buffer*/
|
||||
|
||||
game_rects = &draw_STATUSRECT; /* refresh status bar too */
|
||||
draw_STATUSRECT.next = ent_rects; /* take care to cleanup draw_STATUSRECT->next later! */
|
||||
|
||||
if (!e_rick_state_test(E_RICK_STZOMBIE)) { /* need to scroll ? */
|
||||
if (ent_ents[1].y >= 0xCC) {
|
||||
game_state = SCROLL_UP;
|
||||
return;
|
||||
}
|
||||
if (ent_ents[1].y <= 0x60) {
|
||||
game_state = SCROLL_DOWN;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
game_state = PLAY0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* restart
|
||||
*
|
||||
*/
|
||||
static void
|
||||
restart(void)
|
||||
{
|
||||
e_rick_state_clear(E_RICK_STDEAD|E_RICK_STZOMBIE);
|
||||
|
||||
game_bullets = 6;
|
||||
game_bombs = 6;
|
||||
|
||||
ent_ents[1].n = 1;
|
||||
|
||||
irestore();
|
||||
map_init();
|
||||
isave();
|
||||
ent_clprev();
|
||||
draw_map();
|
||||
draw_drawStatus();
|
||||
game_rects = &draw_SCREENRECT;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* isave (0bbb)
|
||||
*
|
||||
*/
|
||||
static void
|
||||
isave(void)
|
||||
{
|
||||
e_rick_save();
|
||||
isave_frow = map_frow;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* irestore (0bdc)
|
||||
*
|
||||
*/
|
||||
static void
|
||||
irestore(void)
|
||||
{
|
||||
e_rick_restore();
|
||||
map_frow = isave_frow;
|
||||
}
|
||||
|
||||
/* eof */
|
||||
Loading…
Add table
Add a link
Reference in a new issue