summaryrefslogtreecommitdiff
path: root/apps/plugins/mazezam.c
diff options
context:
space:
mode:
authorRobert Kukla <roolku@rockbox.org>2008-04-10 23:28:19 +0000
committerRobert Kukla <roolku@rockbox.org>2008-04-10 23:28:19 +0000
commit7147e4791eb9d7822d522966f11ad532cb0b49ed (patch)
tree8ea1e6f20a4fffded79a870898a843ac1e2094bc /apps/plugins/mazezam.c
parent9074a282a539741cf22c1a73891a774a8a0ccdc6 (diff)
FS#8861 - More Rockbox friendly MazezaM (by Malcolm Tyrrell)
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@17068 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/plugins/mazezam.c')
-rw-r--r--apps/plugins/mazezam.c1426
1 files changed, 569 insertions, 857 deletions
diff --git a/apps/plugins/mazezam.c b/apps/plugins/mazezam.c
index dac73473ce..43d6cd7e3d 100644
--- a/apps/plugins/mazezam.c
+++ b/apps/plugins/mazezam.c
@@ -5,9 +5,8 @@
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
- * ### line of auto-generated stuff I don't understand ###
*
- * Copyright (C) 2006 Malcolm Tyrrell
+ * Copyright (C) 2006, 2008 Malcolm Tyrrell
*
* MazezaM - a Rockbox version of my ZX Spectrum game from 2002
*
@@ -21,193 +20,60 @@
#include "plugin.h"
#include "configfile.h"
#include "helper.h"
+#include "pluginlib_actions.h"
+#include "playback_control.h"
/* Include standard plugin macro */
PLUGIN_HEADER
static struct plugin_api* rb;
-MEM_FUNCTION_WRAPPERS(rb);
-
-#if CONFIG_KEYPAD == RECORDER_PAD
-#define MAZEZAM_UP BUTTON_UP
-#define MAZEZAM_DOWN BUTTON_DOWN
-#define MAZEZAM_LEFT BUTTON_LEFT
-#define MAZEZAM_RIGHT BUTTON_RIGHT
-#define MAZEZAM_SELECT BUTTON_PLAY
-
-#define MAZEZAM_RETRY BUTTON_F1
-#define MAZEZAM_RETRY_KEYNAME "[F1]"
-#define MAZEZAM_QUIT BUTTON_OFF
-#define MAZEZAM_QUIT_KEYNAME "[OFF]"
-
-#elif CONFIG_KEYPAD == ARCHOS_AV300_PAD
-#define MAZEZAM_UP BUTTON_UP
-#define MAZEZAM_DOWN BUTTON_DOWN
-#define MAZEZAM_LEFT BUTTON_LEFT
-#define MAZEZAM_RIGHT BUTTON_RIGHT
-#define MAZEZAM_SELECT BUTTON_SELECT
-
-#define MAZEZAM_RETRY BUTTON_F1
-#define MAZEZAM_RETRY_KEYNAME "[F1]"
-#define MAZEZAM_QUIT BUTTON_OFF
-#define MAZEZAM_QUIT_KEYNAME "[OFF]"
-
-#elif CONFIG_KEYPAD == ONDIO_PAD
-#define MAZEZAM_UP BUTTON_UP
-#define MAZEZAM_DOWN BUTTON_DOWN
-#define MAZEZAM_LEFT BUTTON_LEFT
-#define MAZEZAM_RIGHT BUTTON_RIGHT
-#define MAZEZAM_SELECT BUTTON_RIGHT
-
-#define MAZEZAM_RETRY BUTTON_MENU
-#define MAZEZAM_RETRY_KEYNAME "[MENU]"
-#define MAZEZAM_QUIT BUTTON_OFF
-#define MAZEZAM_QUIT_KEYNAME "[OFF]"
-
-#elif (CONFIG_KEYPAD == IAUDIO_X5M5_PAD)
-#define MAZEZAM_UP BUTTON_UP
-#define MAZEZAM_DOWN BUTTON_DOWN
-#define MAZEZAM_LEFT BUTTON_LEFT
-#define MAZEZAM_RIGHT BUTTON_RIGHT
-#define MAZEZAM_SELECT BUTTON_SELECT
-
-#define MAZEZAM_RETRY BUTTON_REC
-#define MAZEZAM_RETRY_KEYNAME "[REC]"
-#define MAZEZAM_QUIT BUTTON_POWER
-#define MAZEZAM_QUIT_KEYNAME "[POWER]"
-
-#elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \
- (CONFIG_KEYPAD == IPOD_3G_PAD) || \
- (CONFIG_KEYPAD == IPOD_1G2G_PAD)
-#define MAZEZAM_UP BUTTON_MENU
-#define MAZEZAM_DOWN BUTTON_PLAY
-#define MAZEZAM_LEFT BUTTON_LEFT
-#define MAZEZAM_RIGHT BUTTON_RIGHT
-#define MAZEZAM_SELECT BUTTON_SELECT
-
-#define MAZEZAM_RETRY BUTTON_SELECT
-#define MAZEZAM_RETRY_KEYNAME "[SELECT]"
-#define MAZEZAM_QUIT (BUTTON_SELECT | BUTTON_REPEAT)
-#define MAZEZAM_QUIT_KEYNAME "[SELECT] (held)"
-
-#elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
- (CONFIG_KEYPAD == IRIVER_H300_PAD)
-#define MAZEZAM_UP BUTTON_UP
-#define MAZEZAM_DOWN BUTTON_DOWN
-#define MAZEZAM_LEFT BUTTON_LEFT
-#define MAZEZAM_RIGHT BUTTON_RIGHT
-#define MAZEZAM_SELECT BUTTON_SELECT
-
-#define MAZEZAM_RETRY BUTTON_ON
-#define MAZEZAM_RETRY_KEYNAME "[ON]"
-#define MAZEZAM_QUIT BUTTON_OFF
-#define MAZEZAM_QUIT_KEYNAME "[OFF]"
-
-#elif (CONFIG_KEYPAD == GIGABEAT_PAD)
-#define MAZEZAM_UP BUTTON_UP
-#define MAZEZAM_DOWN BUTTON_DOWN
-#define MAZEZAM_LEFT BUTTON_LEFT
-#define MAZEZAM_RIGHT BUTTON_RIGHT
-#define MAZEZAM_SELECT BUTTON_SELECT
-
-#define MAZEZAM_RETRY BUTTON_A
-#define MAZEZAM_RETRY_KEYNAME "[A]"
-#define MAZEZAM_QUIT BUTTON_POWER
-#define MAZEZAM_QUIT_KEYNAME "[POWER]"
-
-#elif (CONFIG_KEYPAD == SANSA_E200_PAD) || \
-(CONFIG_KEYPAD == SANSA_C200_PAD)
-#define MAZEZAM_UP BUTTON_UP
-#define MAZEZAM_DOWN BUTTON_DOWN
-#define MAZEZAM_LEFT BUTTON_LEFT
-#define MAZEZAM_RIGHT BUTTON_RIGHT
-#define MAZEZAM_SELECT BUTTON_SELECT
-
-#define MAZEZAM_RETRY BUTTON_REC
-#define MAZEZAM_RETRY_KEYNAME "[REC]"
-#define MAZEZAM_QUIT BUTTON_POWER
-#define MAZEZAM_QUIT_KEYNAME "[POWER]"
-
-#elif (CONFIG_KEYPAD == IRIVER_H10_PAD)
-#define MAZEZAM_UP BUTTON_SCROLL_UP
-#define MAZEZAM_DOWN BUTTON_SCROLL_DOWN
-#define MAZEZAM_LEFT BUTTON_LEFT
-#define MAZEZAM_RIGHT BUTTON_RIGHT
-#define MAZEZAM_SELECT BUTTON_PLAY
-
-#define MAZEZAM_RETRY BUTTON_PLAY
-#define MAZEZAM_RETRY_KEYNAME "[PLAY]"
-#define MAZEZAM_QUIT BUTTON_POWER
-#define MAZEZAM_QUIT_KEYNAME "[POWER]"
-
-#elif (CONFIG_KEYPAD == GIGABEAT_S_PAD)
-#define MAZEZAM_UP BUTTON_UP
-#define MAZEZAM_DOWN BUTTON_DOWN
-#define MAZEZAM_LEFT BUTTON_LEFT
-#define MAZEZAM_RIGHT BUTTON_RIGHT
-#define MAZEZAM_SELECT BUTTON_SELECT
-
-#define MAZEZAM_RETRY BUTTON_PLAY
-#define MAZEZAM_RETRY_KEYNAME "[PLAY]"
-#define MAZEZAM_QUIT BUTTON_BACK
-#define MAZEZAM_QUIT_KEYNAME "[BACK]"
-
-#elif (CONFIG_KEYPAD == MROBE100_PAD)
-#define MAZEZAM_UP BUTTON_UP
-#define MAZEZAM_DOWN BUTTON_DOWN
-#define MAZEZAM_LEFT BUTTON_LEFT
-#define MAZEZAM_RIGHT BUTTON_RIGHT
-#define MAZEZAM_SELECT BUTTON_SELECT
-
-#define MAZEZAM_RETRY BUTTON_DISPLAY
-#define MAZEZAM_RETRY_KEYNAME "[DISPLAY]"
-#define MAZEZAM_QUIT BUTTON_POWER
-#define MAZEZAM_QUIT_KEYNAME "[POWER]"
-
-#elif CONFIG_KEYPAD == IAUDIO_M3_PAD
-#define MAZEZAM_UP BUTTON_RC_VOL_UP
-#define MAZEZAM_DOWN BUTTON_RC_VOL_DOWN
-#define MAZEZAM_LEFT BUTTON_RC_REW
-#define MAZEZAM_RIGHT BUTTON_RC_FF
-#define MAZEZAM_SELECT BUTTON_RC_PLAY
-
-#define MAZEZAM_RETRY BUTTON_RC_MODE
-#define MAZEZAM_RETRY_KEYNAME "[MODE]"
-#define MAZEZAM_QUIT BUTTON_RC_REC
-#define MAZEZAM_QUIT_KEYNAME "[REC]"
-
-#elif (CONFIG_KEYPAD == COWOND2_PAD)
-#define MAZEZAM_UP BUTTON_UP
-#define MAZEZAM_DOWN BUTTON_DOWN
-#define MAZEZAM_LEFT BUTTON_LEFT
-#define MAZEZAM_RIGHT BUTTON_RIGHT
-#define MAZEZAM_SELECT BUTTON_SELECT
-
-#define MAZEZAM_RETRY BUTTON_SELECT
-#define MAZEZAM_RETRY_KEYNAME "[PLAY]"
-#define MAZEZAM_QUIT BUTTON_POWER
-#define MAZEZAM_QUIT_KEYNAME "[POWER]"
+/* The plugin actions of interest. */
+const struct button_mapping *plugin_contexts[]
+= {generic_directions, generic_actions};
-#else
-#error No keymap defined!
-#endif
+MEM_FUNCTION_WRAPPERS(rb);
-/* The gap for the border around the heading in text pages. In fact, 2 is
- * really the only acceptable value.
- */
-#define MAZEZAM_MENU_BORDER 2
-#define MAZEZAM_EXTRA_LIFE 2 /* get an extra life every _ levels */
-#define MAZEZAM_START_LIVES 3 /* how many lives at game start */
+/* Use the standard plugin buttons rather than a hard-to-maintain list of
+ * MazezaM specific buttons. */
+#define MAZEZAM_UP PLA_UP
+#define MAZEZAM_UP_REPEAT PLA_UP_REPEAT
+#define MAZEZAM_DOWN PLA_DOWN
+#define MAZEZAM_DOWN_REPEAT PLA_DOWN_REPEAT
+#define MAZEZAM_LEFT PLA_LEFT
+#define MAZEZAM_LEFT_REPEAT PLA_LEFT_REPEAT
+#define MAZEZAM_RIGHT PLA_RIGHT
+#define MAZEZAM_RIGHT_REPEAT PLA_RIGHT_REPEAT
+#define MAZEZAM_MENU PLA_QUIT
+
+/* All the text is here */
+#define MAZEZAM_TEXT_GAME_OVER "Game Over"
+#define MAZEZAM_TEXT_LIVES "Level %d, Lives %d"
+#define MAZEZAM_TEXT_CHECKPOINT "Checkpoint reached"
+#define MAZEZAM_TEXT_WELLDONE_TITLE "You have escaped!"
+#define MAZEZAM_TEXT_WELLDONE_OPTION "Goodbye"
+#define MAZEZAM_TEXT_MAZEZAM_MENU "MazezaM Menu"
+#define MAZEZAM_TEXT_RETRY_LEVEL "Retry level"
+#define MAZEZAM_TEXT_AUDIO_PLAYBACK "Audio playback"
+#define MAZEZAM_TEXT_QUIT "Quit"
+#define MAZEZAM_TEXT_BACK "Return"
+#define MAZEZAM_TEXT_MAIN_MENU "MazezaM"
+#define MAZEZAM_TEXT_CONTINUE "Play from checkpoint"
+#define MAZEZAM_TEXT_PLAY_GAME "Play game"
+#define MAZEZAM_TEXT_PLAY_NEW_GAME "Play new game"
+
+#define MAZEZAM_START_LIVES 3 /* how many lives at game start */
+#define MAZEZAM_FIRST_CHECKPOINT 3 /* The level at the first checkpoint */
+#define MAZEZAM_CHECKPOINT_INTERVAL 4 /* A checkpoint every _ levels */
#ifdef HAVE_LCD_COLOR
-#define MAZEZAM_HEADING_COLOR LCD_RGBPACK(255,255, 0) /* Yellow */
-#define MAZEZAM_BORDER_COLOR LCD_RGBPACK( 0, 0,255) /* Blue */
-#define MAZEZAM_TEXT_COLOR LCD_RGBPACK(255,255,255) /* White */
-#define MAZEZAM_BG_COLOR LCD_RGBPACK( 0, 0, 0) /* Black */
-#define MAZEZAM_WALL_COLOR LCD_RGBPACK(100,100,100) /* Dark gray */
-#define MAZEZAM_PLAYER_COLOR LCD_RGBPACK(255,255,255) /* White */
-#define MAZEZAM_GATE_COLOR LCD_RGBPACK(100,100,100) /* Dark gray */
+#define MAZEZAM_HEADING_COLOR LCD_RGBPACK(255,255, 0) /* Yellow */
+#define MAZEZAM_BORDER_COLOR LCD_RGBPACK( 0, 0,255) /* Blue */
+#define MAZEZAM_COLOR LCD_RGBPACK(255,255,255) /* White */
+#define MAZEZAM_BG_COLOR LCD_RGBPACK( 0, 0, 0) /* Black */
+#define MAZEZAM_WALL_COLOR LCD_RGBPACK(100,100,100) /* Dark gray */
+#define MAZEZAM_PLAYER_COLOR LCD_RGBPACK(255,255,255) /* White */
+#define MAZEZAM_GATE_COLOR LCD_RGBPACK(100,100,100) /* Dark gray */
/* the rows are coloured sequentially */
#define MAZEZAM_NUM_CHUNK_COLORS 8
@@ -226,7 +92,7 @@ static const unsigned chunk_colors[MAZEZAM_NUM_CHUNK_COLORS] = {
#define MAZEZAM_HEADING_GRAY LCD_BLACK
#define MAZEZAM_BORDER_GRAY LCD_DARKGRAY
-#define MAZEZAM_TEXT_GRAY LCD_BLACK
+#define MAZEZAM_GRAY LCD_BLACK
#define MAZEZAM_BG_GRAY LCD_WHITE
#define MAZEZAM_WALL_GRAY LCD_DARKGRAY
#define MAZEZAM_PLAYER_GRAY LCD_BLACK
@@ -245,69 +111,16 @@ static const unsigned chunk_gray_shade[MAZEZAM_NUM_CHUNK_GRAYS] = {
};
#endif
-#define MAZEZAM_GAMEOVER_TEXT "Game Over"
-#define MAZEZAM_GAMEOVER_DELAY (3 * HZ) / 2
-#define MAZEZAM_LEVEL_LIVES_TEXT "Level %d, Lives %d"
-#define MAZEZAM_LEVEL_LIVES_DELAY HZ
-#define MAZEZAM_WELLDONE_DELAY 4 * HZ
-
-/* The maximum number of lines that a text page can display.
- * This must be 4 or less if the Archos recorder is to be
- * supported.
- */
-#define MAZEZAM_TEXT_MAXLINES 4
-
-/* A structure for holding text pages */
-struct textpage {
- /* Ensure 1 < num_lines <= MAZEZAM_TEXT_MAXLINES */
- short num_lines;
- char *line[MAZEZAM_TEXT_MAXLINES]; /* text of lines */
-};
-
-/* The text page for the welcome screen */
-static const struct textpage title_page = {
- 4,
- {"MazezaM", "play game", "instructions", "quit"}
-};
-
-/* The number of help screens */
-#define MAZEZAM_NUM_HELP_PAGES 4
-
-/* The instruction screens */
-static const struct textpage help_page[] = {
- {4,{"Instructions","10 mazezams","bar your way","to freedom"}},
- {4,{"Instructions","Push the rows","left and right","to escape"}},
- {4,{"Instructions","Press " MAZEZAM_RETRY_KEYNAME " to","retry a level",
- "(lose 1 life)"}},
- {4,{"Instructions","Press " MAZEZAM_QUIT_KEYNAME,"to quit","the game"}}
-};
-
-/* the text of the screen that asks for a quit confirmation */
-static const struct textpage confirm_page = {
- 4,
- {"Quit","Are you sure?","yes","no"}
-};
-
-/* the text of the screen at the end of the game */
-static const struct textpage welldone_page = {
- 3,
- {"Well Done","You have","escaped",""}
-};
-
-/* the text of the screen asking if the user wants to
- * resume or start a new game.
- */
-static const struct textpage resume_page = {
- 3,
- {"Checkpoint", "continue", "new game"}
-};
+#define MAZEZAM_DELAY_CHECKPOINT HZ
+#define MAZEZAM_DELAY_LIVES HZ
+#define MAZEZAM_DELAY_GAME_OVER (3 * HZ) / 2
/* maximum height of a level */
#define MAZEZAM_MAX_LINES 11
/* maximum number of chunks on a line */
#define MAZEZAM_MAX_CHUNKS 5
-/* A structure for holding levels */
+/* A structure for storing level data in unparsed form */
struct mazezam_level {
short height; /* the number of lines */
short width; /* the width */
@@ -316,9 +129,7 @@ struct mazezam_level {
char *line[MAZEZAM_MAX_LINES]; /* the chunk data in string form */
};
-/* The number of levels. Note that the instruction screens reference this
- * number
- */
+/* The number of levels. */
#define MAZEZAM_NUM_LEVELS 10
/* The levels. In theory, they could be stored in a file so this data
@@ -331,33 +142,29 @@ struct mazezam_level {
* http://webpages.dcu.ie/~tyrrelma/MazezaM.
*/
static const struct mazezam_level level_data[MAZEZAM_NUM_LEVELS] = {
- {2,7,0,0,{" $ $"," $ $$",NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
- NULL}},
- {3,8,2,1,{" $ $$$"," $ $ $"," $ $ $",NULL,NULL,NULL,NULL,NULL,NULL,
- NULL,NULL}},
+ {2,7,0,0,{" $ $"," $ $$"}},
+ {3,8,2,1,{" $ $$$"," $ $ $"," $ $ $"}},
{4,14,1,3,{" $$$$$ $$ $$"," $$ $$ $$","$$ $ $$ $$$",
- " $$$$$$$$ $",NULL,NULL,NULL,NULL,NULL,NULL,NULL}},
- {6,7,4,2,{" $"," $$$$"," $$$ $$"," $ $ $"," $ $$","$ $$",
- NULL,NULL,NULL,NULL,NULL}},
+ " $$$$$$$$ $"}},
+ {6,7,4,2,{" $"," $$$$"," $$$ $$"," $ $ $"," $ $$","$ $$"}},
{6,13,0,0,{" $$$$$","$ $$$$$ $$$"," $ $$$ $$$$",
- "$ $ $$$$$$$"," $$$ $ $$","$ $ $ $$ $",NULL,NULL,
- NULL,NULL,NULL}},
+ "$ $ $$$$$$$"," $$$ $ $$","$ $ $ $$ $"}},
{11,5,10,0,{" $"," $ $$"," $$","$ $"," $ $"," $$$","$ $",
" $ $"," $ $","$ $$"," $"}},
{7,16,0,6,{" $$$$$$$"," $$$$ $$$$ $ $","$$ $$ $$$$$$ $ $",
"$ $ $"," $$$$$$$$$$$$$$"," $ $$ $ $$$",
- " $ $$$ $$",NULL,NULL,NULL,NULL}},
+ " $ $$$ $$"}},
{4,15,2,0,{" $$$$ $$$$ $$"," $ $$ $$ $ $$"," $ $$ $$$$ $$",
- " $ $$ $$$$ $",NULL,NULL,NULL,NULL,NULL,NULL,NULL}},
+ " $ $$ $$$$ $"}},
{7,9,6,2,{" $ $$$$"," $ $ $$"," $ $$$$ $","$ $$ $"," $ $$$",
- " $$$$$$"," $",NULL,NULL,NULL,NULL}},
+ " $$$$$$"," $"}},
{10,14,8,0,{" $"," $$$$$$$$$$ $"," $$$ $$",
" $ $$$$$$$$ $"," $$$ $$$ $$$"," $$$ $ $$$",
" $ $$$$$$$ $$"," $ $ $ $$$"," $$$$$$$$$$$$",
- "",NULL}}
+ ""}}
};
-/* This is the data structure the game uses for managing levels */
+/* This data structure which holds information about the rows */
struct chunk_data {
/* the number of chunks on a line */
short l_num[MAZEZAM_MAX_LINES];
@@ -367,39 +174,38 @@ struct chunk_data {
short c_inset[MAZEZAM_MAX_LINES][MAZEZAM_MAX_CHUNKS];
};
-/* The state and exit code of the level loop */
-enum level_state {
- LEVEL_STATE_LOOPING,
- LEVEL_STATE_COMPLETED,
- LEVEL_STATE_FAILED,
- LEVEL_STATE_QUIT,
- LEVEL_STATE_PARSE_ERROR,
- LEVEL_STATE_USB_CONNECTED,
+/* Parsed level data */
+struct level_info {
+ short width;
+ short height;
+ short entrance;
+ short exit;
+ struct chunk_data cd;
};
-/* The state and exit code of the text screens. I use the
- * same enum for all of them, even though there are some
- * differences.
- */
-enum text_state {
- TEXT_STATE_LOOPING,
- TEXT_STATE_QUIT,
- TEXT_STATE_OKAY,
- TEXT_STATE_USB_CONNECTED,
- TEXT_STATE_PARSE_ERROR,
- TEXT_STATE_BACK,
-};
+/* The state variable used to hold the state of the plugin */
+static enum {
+ STATE_QUIT, /* The player wants to quit */
+ STATE_USB_CONNECTED, /* A USB cable has been inserted */
+ STATE_PARSE_ERROR, /* There's a parse error in the levels */
+ STATE_WELLDONE, /* The player has finished the game */
-/* The state and exit code of the game loop */
-enum game_state {
- GAME_STATE_LOOPING,
- GAME_STATE_QUIT,
- GAME_STATE_OKAY,
- GAME_STATE_USB_CONNECTED,
- GAME_STATE_OVER,
- GAME_STATE_COMPLETED,
- GAME_STATE_PARSE_ERROR,
-};
+ STATE_IN_APPLICATION,
+
+ STATE_MAIN_MENU /* The player is at the main menu */
+ = STATE_IN_APPLICATION,
+ STATE_GAME_OVER, /* The player is out of lives */
+
+ STATE_IN_GAME,
+
+ STATE_COMPLETED /* A level has been completed */
+ = STATE_IN_GAME,
+
+ STATE_FAILED, /* The player wants to retry the level */
+ STATE_GAME_MENU, /* The player wan't to access the in-game menu */
+
+ STATE_IN_LEVEL,
+} state;
/* The various constants needed for configuration files.
* See apps/plugins/lib/configfile.*
@@ -417,87 +223,73 @@ struct resume_data {
int level; /* level at which to restart the game */
};
-/* Display a screen of text. line[0] is the heading.
- * line[highlight] will be highlighted, unless highlight == 0
- */
-static void display_text_page(struct textpage text, int highlight)
-{
- int w[text.num_lines], h[text.num_lines];
- int hsum,i,vgap,vnext;
-
- rb->lcd_clear_display();
-
- /* find out how big the text is so we can determine the positioning */
- hsum = 0;
- for(i = 0; i < text.num_lines; i++) {
- rb->lcd_getstringsize(text.line[i], w+i, h+i);
- hsum += h[i];
- }
+#if LCD_DEPTH > 1
+/* Store the display settings so they are reintroduced during menus */
+static struct {
+ fb_data* backdrop;
+ unsigned foreground;
+ unsigned background;
+} lcd_settings;
+#endif
- vgap = (LCD_HEIGHT-hsum)/(text.num_lines+1);
+/*****************************************************************************
+* Store the LCD settings
+******************************************************************************/
+static void store_lcd_settings(void)
+{
+ /* Store the old settings */
+#if LCD_DEPTH > 1
+ lcd_settings.backdrop = rb->lcd_get_backdrop();
+ lcd_settings.foreground = rb->lcd_get_foreground();
+ lcd_settings.background = rb->lcd_get_background();
+#endif
+}
- /* The Heading */
+/*****************************************************************************
+* Restore the LCD settings to their defaults
+******************************************************************************/
+static void restore_lcd_settings(void) {
+ /* Turn on backlight timeout (revert to settings) */
+ backlight_use_settings(rb); /* backlight control in lib/helper.c */
-#ifdef HAVE_LCD_COLOR
- rb->lcd_set_foreground(MAZEZAM_BORDER_COLOR);
-#elif LCD_DEPTH > 1
- rb->lcd_set_foreground(MAZEZAM_BORDER_GRAY);
-#endif
- rb->lcd_drawrect((LCD_WIDTH-w[0])/2-MAZEZAM_MENU_BORDER,
- vgap-MAZEZAM_MENU_BORDER, w[0] + 2*MAZEZAM_MENU_BORDER,
- h[0] + 2*MAZEZAM_MENU_BORDER);
- rb->lcd_drawrect((LCD_WIDTH-w[0])/2-MAZEZAM_MENU_BORDER*2,
- vgap-MAZEZAM_MENU_BORDER*2, w[0] + 4*MAZEZAM_MENU_BORDER,
- h[0] + 4*MAZEZAM_MENU_BORDER);
- rb->lcd_drawline(0,vgap + h[0]/2,(LCD_WIDTH-w[0])/2-MAZEZAM_MENU_BORDER*2,
- vgap + h[0]/2);
- rb->lcd_drawline((LCD_WIDTH-w[0])/2+w[0]+MAZEZAM_MENU_BORDER*2,
- vgap + h[0]/2,LCD_WIDTH-1,vgap + h[0]/2);
-#ifdef HAVE_LCD_COLOR
- rb->lcd_set_foreground(MAZEZAM_HEADING_COLOR);
-#elif LCD_DEPTH > 1
- rb->lcd_set_foreground(MAZEZAM_HEADING_GRAY);
+ /* Restore the old settings */
+#if LCD_DEPTH > 1
+ rb->lcd_set_foreground(lcd_settings.foreground);
+ rb->lcd_set_background(lcd_settings.background);
+ rb->lcd_set_backdrop(lcd_settings.backdrop);
#endif
- rb->lcd_putsxy((LCD_WIDTH-w[0])/2,vgap,text.line[0]);
-
- vnext = vgap*2 + h[0];
+}
- /* The other lines */
+/*****************************************************************************
+* Adjust the LCD settings to suit MazezaM levels
+******************************************************************************/
+static void plugin_lcd_settings(void) {
+ /* Turn off backlight timeout */
+ backlight_force_on(rb); /* backlight control in lib/helper.c */
+ /* Set the new settings */
#ifdef HAVE_LCD_COLOR
- rb->lcd_set_foreground(MAZEZAM_TEXT_COLOR);
+ rb->lcd_set_background(MAZEZAM_BG_COLOR);
+ rb->lcd_set_backdrop(NULL);
#elif LCD_DEPTH > 1
- rb->lcd_set_foreground(MAZEZAM_TEXT_GRAY);
+ rb->lcd_set_background(MAZEZAM_BG_GRAY);
+ rb->lcd_set_backdrop(NULL);
#endif
- for (i = 1; i<text.num_lines; i++) {
- rb->lcd_putsxy((LCD_WIDTH-w[i])/2,vnext,text.line[i]);
-
- /* add underlining if i is the highlighted line */
- if (i == highlight) {
- rb->lcd_drawline((LCD_WIDTH-w[i])/2, vnext + h[i] + 1,
- (LCD_WIDTH-w[i])/2 + w[i], vnext + h[i] + 1);
- }
-
- vnext += vgap + h[i];
- }
-
- rb->lcd_update();
}
-
-/* Parse the level data from the level_data structure. This could be
- * replaced by a file read. Returns true if the level parsed correctly.
- */
-static bool parse_level(short level, struct chunk_data *cd,
- short *width, short *height, short *entrance, short *exit)
+/*****************************************************************************
+* Parse the level data from the level_data structure. This could be
+* replaced by a file read. Returns true if the level parsed correctly.
+******************************************************************************/
+static bool parse_level(short level, struct level_info* li)
{
int i,j;
char c,clast;
- *width = level_data[level].width;
- *height = level_data[level].height;
- *entrance = level_data[level].entrance;
- *exit = level_data[level].exit;
+ li->width = level_data[level].width;
+ li->height = level_data[level].height;
+ li->entrance = level_data[level].entrance;
+ li->exit = level_data[level].exit;
/* for each line in the level */
for (i = 0; i<level_data[level].height; i++) {
@@ -505,19 +297,19 @@ static bool parse_level(short level, struct chunk_data *cd,
return false;
else {
j = 0;
- cd->l_num[i] = 0;
+ li->cd.l_num[i] = 0;
clast = ' '; /* the character we last considered */
while ((c = level_data[level].line[i][j]) != '\0') {
if (c != ' ') {
if (clast == ' ') {
- cd->l_num[i] += 1;
- if (cd->l_num[i] > MAZEZAM_MAX_CHUNKS)
+ li->cd.l_num[i] += 1;
+ if (li->cd.l_num[i] > MAZEZAM_MAX_CHUNKS)
return false;
- cd->c_inset[i][cd->l_num[i] - 1] = j;
- cd->c_width[i][cd->l_num[i] - 1] = 1;
+ li->cd.c_inset[i][li->cd.l_num[i] - 1] = j;
+ li->cd.c_width[i][li->cd.l_num[i] - 1] = 1;
}
else
- cd->c_width[i][cd->l_num[i] - 1] += 1;
+ li->cd.c_width[i][li->cd.l_num[i] - 1] += 1;
}
clast = c;
j++;
@@ -527,42 +319,18 @@ static bool parse_level(short level, struct chunk_data *cd,
return true;
}
-/* Draw the level */
-static void draw_level(
- struct chunk_data *cd, /* the data about the chunks */
- short *shift, /* an array of the horizontal offset of the lines */
+/*****************************************************************************
+* Draw the walls of a level
+******************************************************************************/
+static void draw_walls(
+ short size,
+ short xOff,
+ short yOff,
short width,
short height,
short entrance,
- short exit,
- short x, /* player's x and y coords */
- short y)
+ short exit)
{
- /* The number of pixels the side of a square should be */
- short size = (LCD_WIDTH/(width+2)) < (LCD_HEIGHT/height) ?
- (LCD_WIDTH/(width+2)) : (LCD_HEIGHT/height);
- /* The x and y position (in pixels) of the top left corner of the
- * level
- */
- short xOff = (LCD_WIDTH - (size*width))/2;
- short yOff = (LCD_HEIGHT - (size*height))/2;
- /* For drawing the player, taken from the sokoban plugin */
- short max = size - 1;
- short middle = max / 2;
- short ldelta = (middle + 1) / 2;
- short i,j;
- short third = size / 3;
- short twothirds = (2 * size) / 3;
-#ifndef HAVE_LCD_COLOR
- /* We #def these out to supress a compiler warning */
- short k;
-#if LCD_DEPTH <= 1
- short l;
-#endif
-#endif
-
- rb->lcd_clear_display();
-
#ifdef HAVE_LCD_COLOR
rb->lcd_set_foreground(MAZEZAM_WALL_COLOR);
#elif LCD_DEPTH > 1
@@ -585,59 +353,96 @@ static void draw_level(
rb->lcd_fillrect(xOff+(size*width),yOff+(size*exit)+size-1,
LCD_WIDTH-xOff+(size*width),
LCD_HEIGHT-yOff-(size*exit)-size+1);
+}
- /* draw the chunks */
- for (i = 0; i<height; i++) {
+/*****************************************************************************
+* Draw chunk row i
+******************************************************************************/
+static void draw_row(
+ short size,
+ short xOff,
+ short yOff,
+ short width,
+ short i, /* the row number */
+ struct chunk_data *cd, /* the data about the chunks */
+ short *shift /* an array of the horizontal offset of the lines */
+)
+{
+ /* The assignment below is just a hack to make supress a warning on
+ * non color targets */
+ short j = width;
+#ifndef HAVE_LCD_COLOR
+ /* We #def these out to supress a compiler warning */
+ short k;
+#if LCD_DEPTH <= 1
+ short l;
+#endif
+#endif
#ifdef HAVE_LCD_COLOR
- /* adding width to i should have a fixed, but randomising effect on
- * the choice of the colours of the top line of chunks
- */
- rb->lcd_set_foreground(chunk_colors[(i+width) %
- MAZEZAM_NUM_CHUNK_COLORS]);
+ /* adding width to i should have a fixed, but randomising effect on
+ * the choice of the colours of the top line of chunks
+ */
+ rb->lcd_set_foreground(chunk_colors[(i+width) %
+ MAZEZAM_NUM_CHUNK_COLORS]);
#endif
- for (j = 0; j<cd->l_num[i]; j++) {
+ for (j = 0; j<cd->l_num[i]; j++) {
#ifdef HAVE_LCD_COLOR
- rb->lcd_fillrect(xOff+size*shift[i]+size*cd->c_inset[i][j],
- yOff+size*i, cd->c_width[i][j]*size,size);
+ rb->lcd_fillrect(xOff+size*shift[i]+size*cd->c_inset[i][j],
+ yOff+size*i, cd->c_width[i][j]*size,size);
#elif LCD_DEPTH > 1
- rb->lcd_set_foreground(MAZEZAM_CHUNK_EDGE_GRAY);
- rb->lcd_drawrect(xOff+size*shift[i]+size*cd->c_inset[i][j],
- yOff+size*i, cd->c_width[i][j]*size,size);
-
- /* draw shade */
- rb->lcd_set_foreground(chunk_gray_shade[(i+width) %
- MAZEZAM_NUM_CHUNK_GRAYS]);
- rb->lcd_drawline(xOff+size*shift[i]+size*cd->c_inset[i][j]+1,
- yOff+size*i+size-2,
- xOff+size*shift[i]+size*cd->c_inset[i][j]+
- cd->c_width[i][j]*size-3,
- yOff+size*i+size-2);
- rb->lcd_drawline(xOff+size*shift[i]+size*cd->c_inset[i][j]+
- cd->c_width[i][j]*size-2,
- yOff+size*i,
+ rb->lcd_set_foreground(MAZEZAM_CHUNK_EDGE_GRAY);
+ rb->lcd_drawrect(xOff+size*shift[i]+size*cd->c_inset[i][j],
+ yOff+size*i, cd->c_width[i][j]*size,size);
+
+ /* draw shade */
+ rb->lcd_set_foreground(chunk_gray_shade[(i+width) %
+ MAZEZAM_NUM_CHUNK_GRAYS]);
+ rb->lcd_drawline(xOff+size*shift[i]+size*cd->c_inset[i][j]+1,
+ yOff+size*i+size-2,
+ xOff+size*shift[i]+size*cd->c_inset[i][j]+
+ cd->c_width[i][j]*size-3,
+ yOff+size*i+size-2);
+ rb->lcd_drawline(xOff+size*shift[i]+size*cd->c_inset[i][j]+
+ cd->c_width[i][j]*size-2,
+ yOff+size*i,
+ xOff+size*shift[i]+size*cd->c_inset[i][j]+
+ cd->c_width[i][j]*size-2,
+ yOff+size*i+size-2);
+
+ /* draw fill */
+ rb->lcd_set_foreground(chunk_gray[(i+width) %
+ MAZEZAM_NUM_CHUNK_GRAYS]);
+ for (k = yOff+size*i+2; k < yOff+size*i+size-2; k += 2)
+ rb->lcd_drawline(xOff+size*shift[i]+size*cd->c_inset[i][j]+2,k,
xOff+size*shift[i]+size*cd->c_inset[i][j]+
- cd->c_width[i][j]*size-2,
- yOff+size*i+size-2);
-
- /* draw fill */
- rb->lcd_set_foreground(chunk_gray[(i+width) %
- MAZEZAM_NUM_CHUNK_GRAYS]);
- for (k = yOff+size*i+2; k < yOff+size*i+size-2; k += 2)
- rb->lcd_drawline(xOff+size*shift[i]+size*cd->c_inset[i][j]+2,k,
- xOff+size*shift[i]+size*cd->c_inset[i][j]+
- cd->c_width[i][j]*size-3,k);
+ cd->c_width[i][j]*size-3,k);
#else
- rb->lcd_drawrect(xOff+size*shift[i]+size*cd->c_inset[i][j],
- yOff+size*i, cd->c_width[i][j]*size,size);
- for (k = xOff+size*shift[i]+size*cd->c_inset[i][j]+2;
- k < xOff+size*shift[i]+size*cd->c_inset[i][j]+
- cd->c_width[i][j]*size;
- k += 2 + (i & 1))
- for (l = yOff+size*i+2; l < yOff+size*i+size; l += 2 + (i & 1))
- rb->lcd_drawpixel(k, l);
+ rb->lcd_drawrect(xOff+size*shift[i]+size*cd->c_inset[i][j],
+ yOff+size*i, cd->c_width[i][j]*size,size);
+ for (k = xOff+size*shift[i]+size*cd->c_inset[i][j]+2;
+ k < xOff+size*shift[i]+size*cd->c_inset[i][j]+
+ cd->c_width[i][j]*size;
+ k += 2 + (i & 1))
+ for (l = yOff+size*i+2; l < yOff+size*i+size; l += 2 + (i & 1))
+ rb->lcd_drawpixel(k, l);
#endif
- }
}
+}
+
+/*****************************************************************************
+* Draw the player
+******************************************************************************/
+static void draw_player(
+ short size,
+ short xOff,
+ short yOff,
+ short x,
+ short y)
+{
+ /* For drawing the player, taken from the sokoban plugin */
+ short max = size - 1;
+ short middle = max / 2;
+ short ldelta = (middle + 1) / 2;
/* draw the player (mostly copied from the sokoban plugin) */
#ifdef HAVE_LCD_COLOR
@@ -653,421 +458,359 @@ static void draw_level(
xOff+size*x+middle-ldelta, yOff+size*y+max);
rb->lcd_drawline(xOff+size*x+middle, yOff+size*y+max-ldelta,
xOff+size*x+middle+ldelta, yOff+size*y+max);
+}
- /* draw the gate, if the player has moved into the level */
- if (x >= 0) {
+/*****************************************************************************
+* Draw the gate
+******************************************************************************/
+static void draw_gate(
+ short size,
+ short xOff,
+ short yOff,
+ short entrance)
+{
+ short third = size / 3;
+ short twothirds = (2 * size) / 3;
#ifdef HAVE_LCD_COLOR
- rb->lcd_set_foreground(MAZEZAM_GATE_COLOR);
+ rb->lcd_set_foreground(MAZEZAM_GATE_COLOR);
#elif LCD_DEPTH > 1
- rb->lcd_set_foreground(MAZEZAM_GATE_GRAY);
+ rb->lcd_set_foreground(MAZEZAM_GATE_GRAY);
#endif
- rb->lcd_drawline(xOff-size,yOff+entrance*size+third,
- xOff-1,yOff+entrance*size+third);
- rb->lcd_drawline(xOff-size,yOff+entrance*size+twothirds,
- xOff-1,yOff+entrance*size+twothirds);
- rb->lcd_drawline(xOff-size+third,yOff+entrance*size,
- xOff-size+third,yOff+entrance*size+size-1);
- rb->lcd_drawline(xOff-size+twothirds,yOff+entrance*size,
- xOff-size+twothirds,yOff+entrance*size+size-1);
- }
+ rb->lcd_drawline(xOff-size,yOff+entrance*size+third,
+ xOff-1,yOff+entrance*size+third);
+ rb->lcd_drawline(xOff-size,yOff+entrance*size+twothirds,
+ xOff-1,yOff+entrance*size+twothirds);
+ rb->lcd_drawline(xOff-size+third,yOff+entrance*size,
+ xOff-size+third,yOff+entrance*size+size-1);
+ rb->lcd_drawline(xOff-size+twothirds,yOff+entrance*size,
+ xOff-size+twothirds,yOff+entrance*size+size-1);
}
-/* Manage the congratulations screen */
-static enum text_state welldone_screen(void)
+/*****************************************************************************
+* Draw the level
+******************************************************************************/
+static void draw_level(
+ struct level_info* li,
+ short *shift, /* an array of the horizontal offset of the lines */
+ short x, /* player's x and y coords */
+ short y)
{
- int button = BUTTON_NONE;
- enum text_state state = TEXT_STATE_LOOPING;
-
- display_text_page(welldone_page, 0);
-
- while (state == TEXT_STATE_LOOPING) {
- button = rb->button_get(true);
-
- switch (button) {
- case MAZEZAM_QUIT:
- state = TEXT_STATE_QUIT;
- break;
+ /* First we calculate the draw info */
+ /* The number of pixels the side of a square should be */
+ short size = (LCD_WIDTH/(li->width+2)) < (LCD_HEIGHT/li->height) ?
+ (LCD_WIDTH/(li->width+2)) : (LCD_HEIGHT/li->height);
+ /* The x and y position (in pixels) of the top left corner of the
+ * level
+ */
+ short xOff = (LCD_WIDTH - (size*li->width))/2;
+ short yOff = (LCD_HEIGHT - (size*li->height))/2;
+ short i;
+
+ rb->lcd_clear_display();
- case MAZEZAM_SELECT:
-#if CONFIG_KEYPAD != ONDIO_PAD
- case MAZEZAM_RIGHT:
-#endif
- state = TEXT_STATE_OKAY;
- break;
+ draw_walls(size,xOff,yOff,li->width, li->height, li->entrance, li->exit);
- default:
- if (rb->default_event_handler(button) == SYS_USB_CONNECTED)
- state = TEXT_STATE_USB_CONNECTED;
- break;
- }
+ /* draw the chunks */
+ for (i = 0; i<li->height; i++) {
+ draw_row(size,xOff,yOff,li->width,i,&(li->cd),shift);
}
- return state;
+ draw_player(size,xOff,yOff,x,y);
+
+ /* if the player has moved into the level, draw the gate */
+ if (x >= 0)
+ draw_gate(size,xOff,yOff,li->entrance);
}
-/* Manage the quit confimation screen */
-static enum text_state quitconfirm_loop(void)
+/*****************************************************************************
+* Manage the congratulations screen
+******************************************************************************/
+static void welldone_screen(void)
{
- int button = BUTTON_NONE;
- enum text_state state = TEXT_STATE_LOOPING;
- short select = 2;
-
- display_text_page(confirm_page, select + 1);
-
- /* Wait for a button release. This is useful when a repeated button
- * press is used for quit.
- */
- while ((rb->button_get(true) & BUTTON_REL) != BUTTON_REL);
-
- while (state == TEXT_STATE_LOOPING) {
- display_text_page(confirm_page, select + 1);
+ int start_selection = 0;
- button = rb->button_get(true);
+ MENUITEM_STRINGLIST(menu,MAZEZAM_TEXT_WELLDONE_TITLE,NULL,
+ MAZEZAM_TEXT_WELLDONE_OPTION);
- switch (button) {
- case MAZEZAM_QUIT:
- state = TEXT_STATE_QUIT;
- break;
-
- case MAZEZAM_UP:
- case MAZEZAM_DOWN:
- select = (2 - select) + 1;
- break;
-
- case MAZEZAM_SELECT:
-#if CONFIG_KEYPAD != ONDIO_PAD
- case MAZEZAM_RIGHT:
-#endif
- if (select == 1)
- state = TEXT_STATE_QUIT;
- else
- state = TEXT_STATE_OKAY;
- break;
-
- default:
- if (rb->default_event_handler(button) == SYS_USB_CONNECTED)
- state = TEXT_STATE_USB_CONNECTED;
- break;
- }
+ switch(rb->do_menu(&menu, &start_selection, NULL, true)){
+ case MENU_ATTACHED_USB:
+ state = STATE_USB_CONNECTED;
+ break;
}
-
- return state;
}
-/* Manage the playing of a level */
-static enum level_state level_loop(short level, short lives)
+/*****************************************************************************
+* Manage the playing of a level
+******************************************************************************/
+static void level_loop(struct level_info* li, short* shift, short *x, short *y)
{
- struct chunk_data cd;
- short shift[MAZEZAM_MAX_LINES]; /* amount each line has been shifted */
- short width;
- short height;
- short entrance;
- short exit;
- short i;
- short x,y;
+ int i;
int button;
- enum level_state state = LEVEL_STATE_LOOPING;
bool blocked; /* is there a chunk in the way of the player? */
- if (!(parse_level(level,&cd,&width,&height,&entrance,&exit)))
- return LEVEL_STATE_PARSE_ERROR;
-
- for (i = 0; i < height; i++)
- shift[i] = 0;
-
- x = -1;
- y = entrance;
-
- draw_level(&cd, shift, width, height, entrance, exit, x, y);
-
-#ifdef HAVE_REMOTE_LCD
- /* Splash text seems to use the remote display by
- * default. I suppose I better keep it tidy!
- */
- rb->lcd_remote_clear_display();
-#endif
- rb->splash(MAZEZAM_LEVEL_LIVES_DELAY, MAZEZAM_LEVEL_LIVES_TEXT,
- level+1, lives);
-
- /* ensure keys pressed during the splash screen are ignored */
- rb->button_clear_queue();
-
- while (state == LEVEL_STATE_LOOPING) {
- draw_level(&cd, shift, width, height, entrance, exit, x, y);
+ while (state >= STATE_IN_LEVEL) {
+ draw_level(li, shift, *x, *y);
rb->lcd_update();
- button = rb->button_get(true);
+ button = pluginlib_getaction(rb, TIMEOUT_BLOCK, plugin_contexts, 2);
blocked = false;
switch (button) {
case MAZEZAM_UP:
- case MAZEZAM_UP | BUTTON_REPEAT:
- if ((y > 0) && (x >= 0) && (x < width)) {
- for (i = 0; i < cd.l_num[y-1]; i++)
+ case MAZEZAM_UP_REPEAT:
+ if ((*y > 0) && (*x >= 0) && (*x < li->width)) {
+ for (i = 0; i < li->cd.l_num[*y-1]; i++)
blocked = blocked ||
- ((x>=shift[y-1]+cd.c_inset[y-1][i]) &&
- (x<shift[y-1]+cd.c_inset[y-1][i]+
- cd.c_width[y-1][i]));
- if (!blocked) y -= 1;
+ ((*x>=shift[*y-1]+li->cd.c_inset[*y-1][i]) &&
+ (*x<shift[*y-1]+li->cd.c_inset[*y-1][i]+
+ li->cd.c_width[*y-1][i]));
+ if (!blocked) *y -= 1;
}
break;
+
+
case MAZEZAM_DOWN:
- case MAZEZAM_DOWN | BUTTON_REPEAT:
- if ((y < height-1) && (x >= 0) && (x < width)) {
- for (i = 0; i < cd.l_num[y+1]; i++)
+ case MAZEZAM_DOWN_REPEAT:
+ if ((*y < li->height-1) && (*x >= 0) && (*x < li->width)) {
+ for (i = 0; i < li->cd.l_num[*y+1]; i++)
blocked = blocked ||
- ((x>=shift[y+1]+cd.c_inset[y+1][i]) &&
- (x<shift[y+1]+cd.c_inset[y+1][i]+
- cd.c_width[y+1][i]));
- if (!blocked) y += 1;
+ ((*x>=shift[*y+1]+li->cd.c_inset[*y+1][i]) &&
+ (*x<shift[*y+1]+li->cd.c_inset[*y+1][i]+
+ li->cd.c_width[*y+1][i]));
+ if (!blocked) *y += 1;
}
break;
case MAZEZAM_LEFT:
- case MAZEZAM_LEFT | BUTTON_REPEAT:
- if (x > 0) {
- for (i = 0; i < cd.l_num[y]; i++)
+ case MAZEZAM_LEFT_REPEAT:
+ if (*x > 0) {
+ for (i = 0; i < li->cd.l_num[*y]; i++)
blocked = blocked ||
- (x == shift[y]+cd.c_inset[y][i]+
- cd.c_width[y][i]);
- if (!blocked) x -= 1;
- else if (shift[y] + cd.c_inset[y][0] > 0) {
- x -= 1;
- shift[y] -= 1;
+ (*x == shift[*y]+li->cd.c_inset[*y][i]+
+ li->cd.c_width[*y][i]);
+ if (!blocked) *x -= 1;
+ else if (shift[*y] + li->cd.c_inset[*y][0] > 0) {
+ *x -= 1;
+ shift[*y] -= 1;
}
}
break;
case MAZEZAM_RIGHT:
- case MAZEZAM_RIGHT | BUTTON_REPEAT:
- if (x < width-1) {
- for (i = 0; i < cd.l_num[y]; i++)
- blocked = blocked || (x+1 == shift[y]+cd.c_inset[y][i]);
- if (!blocked) x += 1;
- else if (shift[y] + cd.c_inset[y][cd.l_num[y]-1] +
- cd.c_width[y][cd.l_num[y]-1] < width) {
- x += 1;
- shift[y] += 1;
+ case MAZEZAM_RIGHT_REPEAT:
+ if (*x < li->width-1) {
+ for (i = 0; i < li->cd.l_num[*y]; i++)
+ blocked = blocked ||
+ (*x+1 == shift[*y]+li->cd.c_inset[*y][i]);
+ if (!blocked) *x += 1;
+ else if (shift[*y]
+ + li->cd.c_inset[*y][li->cd.l_num[*y]-1]
+ + li->cd.c_width[*y][li->cd.l_num[*y]-1]
+ < li->width) {
+ *x += 1;
+ shift[*y] += 1;
}
}
- else if (x == width) state = LEVEL_STATE_COMPLETED;
- else if (y == exit) x += 1;
- break;
-
- case MAZEZAM_RETRY:
- state = LEVEL_STATE_FAILED;
+ else if (*x == li->width) state = STATE_COMPLETED;
+ else if (*y == li->exit) *x += 1;
break;
- case MAZEZAM_QUIT:
- switch (quitconfirm_loop()) {
- case TEXT_STATE_QUIT:
- state = LEVEL_STATE_QUIT;
- break;
-
- case TEXT_STATE_USB_CONNECTED:
- state = LEVEL_STATE_USB_CONNECTED;
- break;
-
- default:
- break;
- }
+ case MAZEZAM_MENU:
+ state = STATE_GAME_MENU;
break;
default:
if (rb->default_event_handler(button) == SYS_USB_CONNECTED)
- state = LEVEL_STATE_USB_CONNECTED;
+ state = STATE_USB_CONNECTED;
break;
}
}
-
- return state;
}
-/* The loop which manages a full game of MazezaM */
-static enum game_state game_loop(struct resume_data *r)
+/*****************************************************************************
+* Manage the in game menu
+******************************************************************************/
+static void in_game_menu(void)
{
- enum game_state state = GAME_STATE_LOOPING;
- int level = r->level;
- int lives = MAZEZAM_START_LIVES;
-
- rb->lcd_clear_display();
-
- while (state == GAME_STATE_LOOPING)
- {
- switch (level_loop(level,lives)) {
- case LEVEL_STATE_COMPLETED:
- level += 1;
- if (!((level - r->level) % MAZEZAM_EXTRA_LIFE))
- lives += 1;
- break;
-
- case LEVEL_STATE_QUIT:
- state = GAME_STATE_QUIT;
- break;
-
- case LEVEL_STATE_FAILED:
- lives -= 1;
- break;
-
- case LEVEL_STATE_PARSE_ERROR:
- state = GAME_STATE_PARSE_ERROR;
- break;
-
- case LEVEL_STATE_USB_CONNECTED:
- state = GAME_STATE_USB_CONNECTED;
- break;
-
- default:
- break;
- }
- if (lives == 0)
- state = GAME_STATE_OVER;
- else if (level == MAZEZAM_NUM_LEVELS)
- state = GAME_STATE_COMPLETED;
- }
-
- switch (state) {
- case GAME_STATE_OVER:
-#ifdef HAVE_REMOTE_LCD
- /* Splash text seems to use the remote display by
- * default. I suppose I better keep it tidy!
- */
- rb->lcd_remote_clear_display();
-#endif
- rb->splash(MAZEZAM_GAMEOVER_DELAY, MAZEZAM_GAMEOVER_TEXT);
+ /* The initial option is retry level */
+ int start_selection = 1;
+
+ MENUITEM_STRINGLIST(menu,MAZEZAM_TEXT_MAZEZAM_MENU, NULL,
+ MAZEZAM_TEXT_BACK,
+ MAZEZAM_TEXT_RETRY_LEVEL,
+ MAZEZAM_TEXT_AUDIO_PLAYBACK,
+ MAZEZAM_TEXT_QUIT);
+
+ /* Don't show the status bar */
+ switch(rb->do_menu(&menu, &start_selection, NULL, false)){
+ case 1: /* retry */
+ state = STATE_FAILED;
break;
- case GAME_STATE_COMPLETED:
- switch (welldone_screen()) {
- case TEXT_STATE_QUIT:
- state = GAME_STATE_QUIT;
- break;
+ case 2: /* Audio playback */
+ playback_control(rb);
+ state = STATE_IN_LEVEL;
+ break;
- case TEXT_STATE_USB_CONNECTED:
- state = GAME_STATE_USB_CONNECTED;
- break;
+ case 3: /* quit */
+ state = STATE_QUIT;
+ break;
- default:
- state = GAME_STATE_OKAY;
- break;
- }
+ case MENU_ATTACHED_USB:
+ state = STATE_USB_CONNECTED;
break;
- default:
+ default: /* Back */
+ state = STATE_IN_LEVEL;
break;
}
+}
- /* This particular resume game logic is designed to make
- * players prove they can solve a level more than once
- */
- if (level > r->level + 1)
- r->level += 1;
-
- return state;
+/*****************************************************************************
+* Is the level a checkpoint
+******************************************************************************/
+static bool at_checkpoint(int level)
+{
+ if (level <= MAZEZAM_FIRST_CHECKPOINT)
+ return level == MAZEZAM_FIRST_CHECKPOINT;
+ else {
+ level = level - MAZEZAM_FIRST_CHECKPOINT;
+ return level % MAZEZAM_CHECKPOINT_INTERVAL == 0;
+ }
}
-/* Manage the instruction screen */
-static enum text_state instruction_loop(void)
+/*****************************************************************************
+* Set up and play a level
+* new_level should be true if this is the first time we've encountered
+* this level
+******************************************************************************/
+static void play_level(short level, short lives, bool new_level)
{
- int button;
- enum text_state state = TEXT_STATE_LOOPING;
- int page = 0;
+ struct level_info li;
+ short shift[MAZEZAM_MAX_LINES]; /* amount each line has been shifted */
+ short x,y;
+ int i;
- while (state == TEXT_STATE_LOOPING) {
- display_text_page(help_page[page], 0);
- button = rb->button_get(true);
+ state = STATE_IN_LEVEL;
- switch (button) {
- case MAZEZAM_LEFT:
- page -= 1;
- break;
+ if (!(parse_level(level,&li)))
+ state = STATE_PARSE_ERROR;
- case MAZEZAM_SELECT:
-#if CONFIG_KEYPAD != ONDIO_PAD
- case MAZEZAM_RIGHT:
-#endif
- page += 1;
- break;
+ for (i = 0; i < li.height; i++)
+ shift[i] = 0;
- case MAZEZAM_QUIT:
- state = TEXT_STATE_QUIT;
- break;
+ x = -1;
+ y = li.entrance;
- default:
- if (rb->default_event_handler(button) == SYS_USB_CONNECTED)
- state = TEXT_STATE_USB_CONNECTED;
- break;
+ plugin_lcd_settings();
+ rb->lcd_clear_display();
- }
+ draw_level(&li, shift, x, y);
- if ((page < 0) || (page >= MAZEZAM_NUM_HELP_PAGES))
- state = TEXT_STATE_OKAY;
+ /* If we've just reached a checkpoint, then alert the player */
+ if (new_level && at_checkpoint(level)) {
+ rb->splash(MAZEZAM_DELAY_CHECKPOINT, MAZEZAM_TEXT_CHECKPOINT);
+ /* Clear the splash */
+ draw_level(&li, shift, x, y);
}
- return state;
-}
+#ifdef HAVE_REMOTE_LCD
+ /* Splash text seems to use the remote display by
+ * default. I suppose I better keep it tidy!
+ */
+ rb->lcd_remote_clear_display();
+#endif
+ rb->splash(MAZEZAM_DELAY_LIVES, MAZEZAM_TEXT_LIVES,
+ level+1, lives);
-/* Manage the text screen that offers the user the option of
- * resuming or starting a new game
- */
-static enum text_state resume_game_loop (struct resume_data *r)
-{
- int button = BUTTON_NONE;
- enum text_state state = TEXT_STATE_LOOPING;
- short select = 0;
+ /* ensure keys pressed during the splash screen are ignored */
+ rb->button_clear_queue();
- /* if the resume level is 0, don't bother asking */
- if (r->level == 0) return TEXT_STATE_OKAY;
+ /* this little loop just ensures we return to the game if the player
+ * doesn't perform an interesting action during the in game menu */
+ while (state >= STATE_IN_LEVEL) {
+ level_loop(&li, shift, &x, &y);
- display_text_page(resume_page, select + 1);
+ if (state == STATE_GAME_MENU) {
+ restore_lcd_settings();
+ in_game_menu();
+ plugin_lcd_settings();
+ }
+ }
+ restore_lcd_settings();
+}
- while (state == TEXT_STATE_LOOPING) {
- display_text_page(resume_page, select + 1);
+/*****************************************************************************
+* Update the resume data based on the level reached
+******************************************************************************/
+static void update_resume_data(struct resume_data *r, int level)
+{
+ if (at_checkpoint(level))
+ r->level = level;
+}
- button = rb->button_get(true);
+/*****************************************************************************
+* The loop which manages a full game of MazezaM.
+******************************************************************************/
+static void game_loop(struct resume_data *r)
+{
+ int level = r->level;
+ int lives = MAZEZAM_START_LIVES;
+ /* We want to know when a player reaches a level for the first time,
+ * so we keep a second copy of the level. */
+ int old_level = level;
- switch (button) {
- case MAZEZAM_QUIT:
- state = TEXT_STATE_QUIT;
- break;
+ state = STATE_IN_GAME;
- case MAZEZAM_LEFT:
- state = TEXT_STATE_BACK;
- break;
+ while (state >= STATE_IN_GAME)
+ {
+ play_level(level, lives, old_level < level);
+ old_level = level;
- case MAZEZAM_UP:
- case MAZEZAM_DOWN:
- select = 1 - select;
+ switch (state) {
+ case STATE_COMPLETED:
+ level += 1;
+ if (level == MAZEZAM_NUM_LEVELS)
+ state = STATE_WELLDONE;
break;
- case MAZEZAM_SELECT:
-#if CONFIG_KEYPAD != ONDIO_PAD
- case MAZEZAM_RIGHT:
-#endif
- if (select == 1) {
- /* The player wants to play a new game. I could ask
- * for confirmation here, but the only penalty is
- * playing through some already completed levels,
- * so I don't think it's necessary
- */
- r->level = 0;
- }
- state = TEXT_STATE_OKAY;
+ case STATE_FAILED:
+ lives -= 1;
+ if (lives == 0)
+ state = STATE_GAME_OVER;
break;
default:
- if (rb->default_event_handler(button) == SYS_USB_CONNECTED)
- state = TEXT_STATE_USB_CONNECTED;
break;
}
+
+ update_resume_data(r,level);
}
- return state;
+ switch (state) {
+ case STATE_GAME_OVER:
+#ifdef HAVE_REMOTE_LCD
+ /* Splash text seems to use the remote display by
+ * default. I suppose I better keep it tidy!
+ */
+ rb->lcd_remote_clear_display();
+#endif
+ rb->splash(MAZEZAM_DELAY_GAME_OVER, MAZEZAM_TEXT_GAME_OVER);
+ break;
+
+ case STATE_WELLDONE:
+ welldone_screen();
+ break;
+
+ default:
+ break;
+ }
}
-/* Load the resume data from the config file. The data is
- * stored in both r and old.
- */
+/*****************************************************************************
+* Load the resume data from the config file. The data is
+* stored in both r and old.
+******************************************************************************/
static void resume_load_data (struct resume_data *r, struct resume_data *old)
{
struct configdata config[] = {
@@ -1075,8 +818,8 @@ static void resume_load_data (struct resume_data *r, struct resume_data *old)
MAZEZAM_CONFIG_LEVELS_NAME,NULL,NULL}
};
- if (configfile_load(MAZEZAM_CONFIG_FILENAME,config,MAZEZAM_CONFIG_NUM_ITEMS,
- MAZEZAM_CONFIG_VERSION) < 0)
+ if (configfile_load(MAZEZAM_CONFIG_FILENAME,config,
+ MAZEZAM_CONFIG_NUM_ITEMS, MAZEZAM_CONFIG_VERSION) < 0)
r->level = 0;
/* an extra precaution */
else if ((r->level < 0) || (MAZEZAM_NUM_LEVELS <= r->level))
@@ -1085,7 +828,9 @@ static void resume_load_data (struct resume_data *r, struct resume_data *old)
old->level = r->level;
}
-/* Save the resume data in the config file, but only if necessary */
+/*****************************************************************************
+* Save the resume data in the config file, but only if necessary
+******************************************************************************/
static void resume_save_data (struct resume_data *r, struct resume_data *old)
{
struct configdata config[] = {
@@ -1097,99 +842,74 @@ static void resume_save_data (struct resume_data *r, struct resume_data *old)
* changed.
*/
if (old->level != r->level)
- configfile_save(MAZEZAM_CONFIG_FILENAME,config,MAZEZAM_CONFIG_NUM_ITEMS,
- MAZEZAM_CONFIG_MINVERSION);
+ configfile_save(MAZEZAM_CONFIG_FILENAME,config,
+ MAZEZAM_CONFIG_NUM_ITEMS, MAZEZAM_CONFIG_MINVERSION);
}
-/* The loop which manages the welcome screen and menu */
-static enum text_state welcome_loop(void)
+/*****************************************************************************
+* Offer a main menu with no continue option
+******************************************************************************/
+static int main_menu_without_continue(int* start_selection)
{
- int button;
- short select = 0;
- enum text_state state = TEXT_STATE_LOOPING;
+ MENUITEM_STRINGLIST(menu,MAZEZAM_TEXT_MAIN_MENU,NULL,
+ MAZEZAM_TEXT_PLAY_GAME,
+ MAZEZAM_TEXT_QUIT);
+ return rb->do_menu(&menu, start_selection, NULL, false);
+}
+
+/*****************************************************************************
+* Offer a main menu with a continue option
+******************************************************************************/
+static int main_menu_with_continue(int* start_selection)
+{
+ MENUITEM_STRINGLIST(menu,MAZEZAM_TEXT_MAIN_MENU,NULL,
+ MAZEZAM_TEXT_CONTINUE,
+ MAZEZAM_TEXT_PLAY_NEW_GAME,
+ MAZEZAM_TEXT_QUIT);
+ return rb->do_menu(&menu, start_selection, NULL, false);
+}
+
+/*****************************************************************************
+* Manages the main menu
+******************************************************************************/
+static void main_menu(void)
+{
+ /* The initial option is "play game" */
+ int start_selection = 0;
+ int choice = 0;
struct resume_data r_data, old_data;
/* Load data */
resume_load_data(&r_data, &old_data);
- while (state == TEXT_STATE_LOOPING) {
- display_text_page(title_page, select + 1);
- button = rb->button_get(true);
-
- switch (button) {
- case MAZEZAM_QUIT:
- state = TEXT_STATE_QUIT;
- break;
-
- case MAZEZAM_UP:
- select = (select + (title_page.num_lines - 2)) %
- (title_page.num_lines - 1);
- break;
-
- case MAZEZAM_DOWN:
- select = (select + 1) % (title_page.num_lines - 1);
- break;
-
- case MAZEZAM_SELECT:
-#if CONFIG_KEYPAD != ONDIO_PAD
- case MAZEZAM_RIGHT:
-#endif
- if (select == 0) { /* play game */
- switch (resume_game_loop(&r_data)) {
- case TEXT_STATE_QUIT:
- state = TEXT_STATE_QUIT;
- break;
-
- case TEXT_STATE_USB_CONNECTED:
- state = TEXT_STATE_USB_CONNECTED;
- break;
-
- case TEXT_STATE_BACK:
- break;
-
- default: { /* Ouch! This nesting is too deep! */
- switch (game_loop(&r_data)) {
- case GAME_STATE_QUIT:
- state = TEXT_STATE_QUIT;
- break;
-
- case GAME_STATE_USB_CONNECTED:
- state = TEXT_STATE_USB_CONNECTED;
- break;
-
- case GAME_STATE_PARSE_ERROR:
- state = TEXT_STATE_PARSE_ERROR;
- break;
-
- default:
- break;
- }
- break;
- }
- }
+ while (state >= STATE_IN_APPLICATION) {
+ if (r_data.level == 0)
+ choice = main_menu_without_continue(&start_selection);
+ else
+ choice = main_menu_with_continue(&start_selection);
+
+ switch(choice) {
+ case 0: /* Continue */
+ state = STATE_IN_GAME;
+ game_loop(&r_data);
+ break;
+
+ case 1: /* Quit or Play new game */
+ if (r_data.level == 0)
+ state = STATE_QUIT;
+ else { /* Play new game */
+ r_data.level = 0;
+ state = STATE_IN_GAME;
+ game_loop(&r_data);
}
- else if (select == 1) { /* Instructions */
- switch (instruction_loop()) {
- case TEXT_STATE_QUIT:
- state = TEXT_STATE_QUIT;
- break;
-
- case TEXT_STATE_USB_CONNECTED:
- state = TEXT_STATE_USB_CONNECTED;
- break;
-
- default:
- break;
- }
- }
- else /* Quit */
- state = TEXT_STATE_QUIT;
+ break;
+ case MENU_ATTACHED_USB:
+ state = STATE_USB_CONNECTED;
break;
- default:
- if (rb->default_event_handler(button) == SYS_USB_CONNECTED)
- state = TEXT_STATE_USB_CONNECTED;
+ default: /* Quit */
+ state = STATE_QUIT;
break;
}
}
@@ -1198,49 +918,41 @@ static enum text_state welcome_loop(void)
* Currently, I do so.
*/
resume_save_data(&r_data, &old_data);
-
- return state;
}
-/* Plugin entry point */
+/*****************************************************************************
+* Plugin entry point
+******************************************************************************/
enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
{
- enum plugin_status state;
+ enum plugin_status plugin_state;
/* Usual plugin stuff */
(void)parameter;
rb = api;
- /* Turn off backlight timeout */
- backlight_force_on(rb); /* backlight control in lib/helper.c */
-
-#ifdef HAVE_LCD_COLOR
- rb->lcd_set_background(MAZEZAM_BG_COLOR);
- rb->lcd_set_backdrop(NULL);
-#elif LCD_DEPTH > 1
- rb->lcd_set_background(MAZEZAM_BG_GRAY);
-#endif
- rb->lcd_setfont(FONT_SYSFIXED);
/* initialise the config file module */
configfile_init(rb);
- switch (welcome_loop()) {
- case TEXT_STATE_USB_CONNECTED:
- state = PLUGIN_USB_CONNECTED;
+ store_lcd_settings();
+
+ state = STATE_MAIN_MENU;
+ main_menu();
+
+ switch (state) {
+ case STATE_USB_CONNECTED:
+ plugin_state = PLUGIN_USB_CONNECTED;
break;
- case TEXT_STATE_PARSE_ERROR:
- state = PLUGIN_ERROR;
+ case STATE_PARSE_ERROR:
+ plugin_state = PLUGIN_ERROR;
break;
default:
- state = PLUGIN_OK;
+ plugin_state = PLUGIN_OK;
break;
}
- /* Turn on backlight timeout (revert to settings) */
- backlight_use_settings(rb); /* backlight control in lib/helper.c */
-
- return state;
+ return plugin_state;
}