diff options
author | Björn Stenberg <bjorn@haxx.se> | 2003-06-29 16:33:04 +0000 |
---|---|---|
committer | Björn Stenberg <bjorn@haxx.se> | 2003-06-29 16:33:04 +0000 |
commit | ba371fb595affd68c823926b85718d1d613dc7d3 (patch) | |
tree | cfda303d0603d623cdb12f3928905d3ae02f1d87 | |
parent | 9bcbe3fd723d23a709873a0855f27b86bc5c96f1 (diff) | |
download | rockbox-ba371fb595affd68c823926b85718d1d613dc7d3.tar.gz rockbox-ba371fb595affd68c823926b85718d1d613dc7d3.zip |
Added plugin loader. Moved games, demos and the text viewer to loadable plugins. Copy your *.rock files to /.rockbox/rocks/
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@3769 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r-- | apps/Makefile | 8 | ||||
-rw-r--r-- | apps/demo_menu.c | 37 | ||||
-rw-r--r-- | apps/games_menu.c | 29 | ||||
-rw-r--r-- | apps/lang/english.lang | 76 | ||||
-rw-r--r-- | apps/player/icons.h | 3 | ||||
-rw-r--r-- | apps/plugin.c | 221 | ||||
-rw-r--r-- | apps/plugin.h | 161 | ||||
-rw-r--r-- | apps/plugins/Makefile | 45 | ||||
-rw-r--r-- | apps/plugins/bounce.c (renamed from apps/recorder/bounce.c) | 96 | ||||
-rw-r--r-- | apps/plugins/cube.c (renamed from apps/recorder/cube.c) | 63 | ||||
-rw-r--r-- | apps/plugins/helloworld.c | 48 | ||||
-rw-r--r-- | apps/plugins/oscillograph.c (renamed from apps/recorder/oscillograph.c) | 82 | ||||
-rw-r--r-- | apps/plugins/plugin.lds | 26 | ||||
-rw-r--r-- | apps/plugins/snow.c (renamed from apps/recorder/snow.c) | 46 | ||||
-rw-r--r-- | apps/plugins/sokoban.c | 868 | ||||
-rw-r--r-- | apps/plugins/viewer.c (renamed from apps/viewer.c) | 71 | ||||
-rw-r--r-- | apps/plugins/wormlet.c (renamed from apps/recorder/wormlet.c) | 427 | ||||
-rw-r--r-- | apps/recorder/icons.c | 1 | ||||
-rw-r--r-- | apps/recorder/icons.h | 1 | ||||
-rw-r--r-- | apps/recorder/sokoban.c | 891 | ||||
-rw-r--r-- | apps/recorder/sokoban.h | 28 | ||||
-rw-r--r-- | apps/recorder/tetris.c | 438 | ||||
-rw-r--r-- | apps/recorder/wormlet.h | 28 | ||||
-rw-r--r-- | apps/screens.c | 1 | ||||
-rw-r--r-- | apps/tree.c | 19 | ||||
-rw-r--r-- | apps/tree.h | 1 | ||||
-rw-r--r-- | apps/viewer.h | 24 | ||||
-rw-r--r-- | firmware/app.lds | 15 | ||||
-rw-r--r-- | firmware/drivers/lcd-player-charset.c | 4 |
29 files changed, 1869 insertions, 1889 deletions
diff --git a/apps/Makefile b/apps/Makefile index 3e5fbdc2dd..9614050cda 100644 --- a/apps/Makefile +++ b/apps/Makefile @@ -20,7 +20,7 @@ DOCSDIR := ../docs INCLUDES= -I$(FIRMWARE)/include -I$(FIRMWARE)/export -I. -I$(OBJDIR) -CFLAGS = -O -W -Wall -m1 -nostdlib -ffreestanding -Wstrict-prototypes -fomit-frame-pointer -fschedule-insns $(INCLUDES) $(TARGET) $(DEFINES) -DAPPSVERSION=\"$(VERSION)\" $(EXTRA_DEFINES) -DMEM=${MEM} +CFLAGS = -O -W -Wall -m1 -nostdlib -ffreestanding -Wstrict-prototypes -fomit-frame-pointer -fschedule-insns $(INCLUDES) $(TARGET) $(DEFINES) -DAPPSVERSION=\"$(VERSION)\" $(EXTRA_DEFINES) -DMEM=${MEM} -DPLUGIN=1 AFLAGS += -small -relax # Check if this is a kind of Recorder @@ -71,7 +71,10 @@ ifndef TOOLSDIR TOOLSDIR=../tools endif -all : $(OBJDIR)/$(OUTNAME) +all : $(OBJDIR)/$(OUTNAME) rocks + +rocks: + $(MAKE) -C plugins TARGET=$(TARGET) DEBUG=$(DEBUG) OBJDIR=$(OBJDIR) VERSION=$(VERSION) EXTRA_DEFINES="$(EXTRA_DEFINES)" $(OBJDIR)/librockbox.a: make -C $(FIRMWARE) TARGET=$(TARGET) DEBUG=$(DEBUG) OBJDIR=$(OBJDIR) @@ -117,6 +120,7 @@ clean: $(OBJDIR)/lang.o $(OBJDIR)/build.lang $(OBJDIR)/lang.[ch] \ $(OBJDIR)/credits.raw $(LINKFILE) -$(RM) -r $(OBJDIR)/$(DEPS) + $(MAKE) -C plugins clean DEPS:=.deps DEPDIRS:=$(DEPS) diff --git a/apps/demo_menu.c b/apps/demo_menu.c index f6934e49be..be8e44522c 100644 --- a/apps/demo_menu.c +++ b/apps/demo_menu.c @@ -24,19 +24,38 @@ #include <stdio.h> #include <stdbool.h> -#include "lcd.h" #include "menu.h" #include "demo_menu.h" -#include "button.h" -#include "kernel.h" -#include "sprintf.h" - #include "lang.h" +#include "plugin.h" + +static bool bounce(void) +{ + if (plugin_load("/.rockbox/rocks/bounce.rock",NULL)==PLUGIN_USB_CONNECTED) + return true; + return false; +} + +static bool snow(void) +{ + if (plugin_load("/.rockbox/rocks/snow.rock",NULL) == PLUGIN_USB_CONNECTED) + return true; + return false; +} + +static bool cube(void) +{ + if (plugin_load("/.rockbox/rocks/cube.rock",NULL) == PLUGIN_USB_CONNECTED) + return true; + return false; +} -extern bool bounce(void); -extern bool snow(void); -extern bool cube(void); -extern bool oscillograph(void); +static bool oscillograph(void) +{ + if (plugin_load("/.rockbox/rocks/oscillograph.rock",NULL)==PLUGIN_USB_CONNECTED) + return true; + return false; +} bool demo_menu(void) { diff --git a/apps/games_menu.c b/apps/games_menu.c index 0c37203f4e..780c4b7415 100644 --- a/apps/games_menu.c +++ b/apps/games_menu.c @@ -25,18 +25,31 @@ #include <stdio.h> #include <stdbool.h> -#include "lcd.h" #include "menu.h" #include "games_menu.h" -#include "button.h" -#include "kernel.h" -#include "sprintf.h" - -#include "sokoban.h" -#include "wormlet.h" #include "lang.h" +#include "plugin.h" -extern bool tetris(void); +static bool tetris(void) +{ + if (plugin_load("/.rockbox/rocks/tetris.rock",NULL)==PLUGIN_USB_CONNECTED) + return true; + return false; +} + +static bool sokoban(void) +{ + if (plugin_load("/.rockbox/rocks/sokoban.rock",NULL)==PLUGIN_USB_CONNECTED) + return true; + return false; +} + +static bool wormlet(void) +{ + if (plugin_load("/.rockbox/rocks/wormlet.rock",NULL)==PLUGIN_USB_CONNECTED) + return true; + return false; +} bool games_menu(void) { diff --git a/apps/lang/english.lang b/apps/lang/english.lang index 12249ee048..1d7b3088a6 100644 --- a/apps/lang/english.lang +++ b/apps/lang/english.lang @@ -677,37 +677,37 @@ new: id: LANG_SOKOBAN_LEVEL desc: must be smaller than 6 characters -eng: "Level" +eng: "" new: id: LANG_SOKOBAN_MOVE desc: must be smaller than 6 characters -eng: "Moves" +eng: "" new: id: LANG_SOKOBAN_WIN desc: displayed when you win -eng: "YOU WIN!!" +eng: "" new: id: LANG_SOKOBAN_QUIT desc: how to quit game -eng: "[OFF] To Stop" +eng: "" new: id: LANG_SOKOBAN_F1 desc: what does F1 do -eng: "[F1] - Level" +eng: "" new: id: LANG_SOKOBAN_F2 desc: what does F2 do -eng: "[F2] Same Level" +eng: "" new: id: LANG_SOKOBAN_F3 desc: what does F3 do -eng: "[F3] + Level" +eng: "" new: # Next ids are for Worlmet Game. @@ -717,37 +717,37 @@ new: id: LANG_WORMLET_LENGTH desc: wormlet game -eng: "Len:%d" +eng: "" new: id: LANG_WORMLET_GROWING desc: wormlet game -eng: "Growing" +eng: "" new: id: LANG_WORMLET_HUNGRY desc: wormlet game -eng: "Hungry" +eng: "" new: id: LANG_WORMLET_WORMED desc: wormlet game -eng: "Wormed" +eng: "" new: id: LANG_WORMLET_ARGH desc: wormlet game -eng: "Argh" +eng: "" new: id: LANG_WORMLET_CRASHED desc: wormlet game -eng: "Crashed" +eng: "" new: id: LANG_WORMLET_HIGHSCORE desc: wormlet game -eng: "Hs: %d" +eng: "" new: # Length restrictions for wormlet config screen strings (LANG_CS_XXX) @@ -756,49 +756,49 @@ new: id: LANG_WORMLET_PLAYERS desc: wormlet game -eng: "%d Players UP/DN" +eng: "" new: id: LANG_WORMLET_WORMS desc: wormlet game -eng: "%d Worms L/R" +eng: "" new: id: LANG_WORMLET_REMOTE_CTRL desc: wormlet game -eng: "Remote Control F1" +eng: "" new: id: LANG_WORMLET_NO_REM_CTRL desc: wormlet game -eng: "No Rem. Control F1" +eng: "" new: id: LANG_WORMLET_2_KEY_CTRL desc: wormlet game -eng: "2 Key Control F1" +eng: "" new: id: LANG_WORMLET_4_KEY_CTRL desc: wormlet game -eng: "4 Key Control F1" +eng: "" new: id: LANG_WORMLET_NO_CONTROL desc: wormlet game -eng: "Out Of Control" +eng: "" new: # Wormlet game ids ended id: LANG_TETRIS_LOSE desc: tetris game -eng: "You Lose!" +eng: "" new: id: LANG_TETRIS_LEVEL desc: tetris game -eng: "Rows - Level" +eng: "" new: id: LANG_POWEROFF_IDLE @@ -1569,3 +1569,33 @@ id: LANG_CANCEL_WITH_ANY_RECORDER desc: Generic recorder string to use to cancel eng: "Any Other = No" new: + +## +## Strings used in the plugin loader: +## + +id: LANG_PLUGIN_CANT_OPEN +desc: Plugin open error message +eng: "Can't open %s" +new: + +id: LANG_READ_FAILED +desc: There was an error reading a file +eng: "Failed reading %s" +new: + +id: LANG_PLUGIN_WRONG_MODEL +desc: The plugin is not compatible with the archos model trying to run it +eng: "Incompatible model" +new: + +id: LANG_PLUGIN_WRONG_VERSION +desc: The plugin is not compatible with the rockbox version trying to run it +eng: "Incompatible version" +new: + +id: LANG_PLUGIN_ERROR +desc: The plugin return an error code +eng: "Plugin returned error" +new: + diff --git a/apps/player/icons.h b/apps/player/icons.h index 1c9c68d66c..c96f821cfa 100644 --- a/apps/player/icons.h +++ b/apps/player/icons.h @@ -26,7 +26,8 @@ enum { Unknown=0x90, - Folder=0x18, Mod_Ajz, Language, File, Wps, Playlist, Text, Config + Plugin = 0x17, + Folder, Mod_Ajz, Language, File, Wps, Playlist, Text, Config, }; #endif diff --git a/apps/plugin.c b/apps/plugin.c new file mode 100644 index 0000000000..6366580a56 --- /dev/null +++ b/apps/plugin.c @@ -0,0 +1,221 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2002 Björn Stenberg + * + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include <stdbool.h> +#include <string.h> +#include <stdio.h> +#include "button.h" +#include "lcd.h" +#include "dir.h" +#include "file.h" +#include "kernel.h" +#include "sprintf.h" +#include "screens.h" +#include "misc.h" +#include "mas.h" +#include "plugin.h" +#include "lang.h" + +#ifdef SIMULATOR +#include <dlfcn.h> +#define PREFIX(_x_) x11_ ## _x_ +#else +#define PREFIX(_x_) _x_ +#endif + +static int plugin_test(int api_version, int model); + +static struct plugin_api rockbox_api = { + PLUGIN_API_VERSION, + + plugin_test, + + /* lcd */ + lcd_clear_display, + lcd_puts, + lcd_puts_scroll, + lcd_stop_scroll, +#ifdef HAVE_LCD_CHARCELLS + lcd_define_pattern, +#else + lcd_putsxy, + lcd_bitmap, + lcd_drawline, + lcd_clearline, + lcd_drawpixel, + lcd_clearpixel, + lcd_setfont, + lcd_clearrect, + lcd_fillrect, + lcd_drawrect, + lcd_invertrect, + lcd_getstringsize, + lcd_update, + lcd_update_rect, +#ifndef SIMULATOR + lcd_roll, +#endif +#endif + + /* button */ + button_get, + button_get_w_tmo, + + /* file */ + PREFIX(open), + PREFIX(close), + read, + lseek, + PREFIX(creat), + write, + remove, + rename, + ftruncate, + PREFIX(filesize), + fprintf, + read_line, + + /* dir */ + PREFIX(opendir), + PREFIX(closedir), + PREFIX(readdir), + + /* kernel */ + PREFIX(sleep), + usb_screen, + ¤t_tick, + + /* strings and memory */ + snprintf, + strcpy, + strlen, + memset, + memcpy, + + /* sound */ +#ifndef SIMULATOR +#ifdef HAVE_MAS3587F + mas_codec_readreg, +#endif +#endif + + /* misc */ + srand, + rand, + splash, +}; + +int plugin_load(char* plugin, void* parameter) +{ + enum plugin_status (*plugin_start)(struct plugin_api* api, void* param); + int rc; + char buf[64]; +#ifdef SIMULATOR + void* pd; + char path[256]; +#else + extern unsigned char pluginbuf[]; + int fd; +#endif + + lcd_clear_display(); +#ifdef HAVE_LCD_BITMAP + lcd_setmargins(0,0); + lcd_update(); +#endif +#ifdef SIMULATOR + snprintf(path, sizeof path, "archos%s", plugin); + pd = dlopen(path, RTLD_NOW); + if (!pd) { + snprintf(buf, sizeof buf, "Can't open %s", plugin); + splash(HZ*2, 0, true, buf); + dlclose(pd); + return -1; + } + + plugin_start = dlsym(pd, "plugin_start"); + if (!plugin_start) { + plugin_start = dlsym(pd, "_plugin_start"); + if (!plugin_start) { + splash(HZ*2, 0, true, "Can't find entry point"); + dlclose(pd); + return -1; + } + } +#else + fd = open(plugin, O_RDONLY); + if (fd < 0) { + snprintf(buf, sizeof buf, str(LANG_PLUGIN_CANT_OPEN), plugin); + splash(HZ*2, 0, true, buf); + return fd; + } + + plugin_start = (void*)&pluginbuf; + rc = read(fd, plugin_start, 0x8000); + close(fd); + if (rc < 0) { + /* read error */ + snprintf(buf, sizeof buf, str(LANG_READ_FAILED), plugin); + splash(HZ*2, 0, true, buf); + return -1; + } + if (rc == 0) { + /* loaded a 0-byte plugin, implying it's not for this model */ + splash(HZ*2, 0, true, str(LANG_PLUGIN_WRONG_MODEL)); + return -1; + } +#endif + + rc = plugin_start(&rockbox_api, parameter); + switch (rc) { + case PLUGIN_OK: + break; + + case PLUGIN_USB_CONNECTED: + return PLUGIN_USB_CONNECTED; + + case PLUGIN_WRONG_API_VERSION: + splash(HZ*2, 0, true, str(LANG_PLUGIN_WRONG_VERSION)); + break; + + case PLUGIN_WRONG_MODEL: + splash(HZ*2, 0, true, str(LANG_PLUGIN_WRONG_MODEL)); + break; + + default: + splash(HZ*2, 0, true, str(LANG_PLUGIN_ERROR)); + break; + } + +#ifdef SIMULATOR + dlclose(pd); +#endif + + return PLUGIN_OK; +} + +int plugin_test(int api_version, int model) +{ + if (api_version != PLUGIN_API_VERSION) + return PLUGIN_WRONG_API_VERSION; + + if (model != MODEL) + return PLUGIN_WRONG_MODEL; + + return PLUGIN_OK; +} diff --git a/apps/plugin.h b/apps/plugin.h new file mode 100644 index 0000000000..3b79edefc6 --- /dev/null +++ b/apps/plugin.h @@ -0,0 +1,161 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2002 Björn Stenberg + * + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#ifndef _PLUGIN_H_ +#define _PLUGIN_H_ + +/* instruct simulator code to not redefine any symbols when compiling plugins. + (the PLUGIN macro is defined in apps/plugins/Makefile) */ +#ifdef PLUGIN +#define NO_REDEFINES_PLEASE +#endif + +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include "config.h" +#include "dir.h" +#include "kernel.h" +#include "button.h" +#include "font.h" +#include "system.h" +#include "lcd.h" + +/* increase this every time the api struct changes */ +#define PLUGIN_API_VERSION 1 + +/* plugin return codes */ +enum plugin_status { + PLUGIN_OK = 0, + PLUGIN_USB_CONNECTED, + + PLUGIN_WRONG_API_VERSION = -1, + PLUGIN_WRONG_MODEL = -2, + PLUGIN_ERROR = -3, +}; + +/* different (incompatible) plugin models */ +enum model { + PLAYER, + RECORDER +}; + +#ifdef HAVE_LCD_CHARCELLS +#define MODEL PLAYER +#else +#define MODEL RECORDER +#endif + +/* compatibility test macro */ +#define TEST_PLUGIN_API(_api_) \ +do { \ + int _rc_ = _api_->plugin_test(PLUGIN_API_VERSION, MODEL); \ + if (_rc_<0) \ + return _rc_; \ +} while(0) + +struct plugin_api { + /* these two fields must always be first, to ensure + TEST_PLUGIN_API will always work */ + int version; + int (*plugin_test)(int api_version, int model); + + /* lcd */ + void (*lcd_clear_display)(void); + void (*lcd_puts)(int x, int y, unsigned char *string); + void (*lcd_puts_scroll)(int x, int y, unsigned char* string); + void (*lcd_stop_scroll)(void); +#ifdef HAVE_LCD_CHARCELLS + void (*lcd_define_pattern)(int which,char *pattern); +#else + void (*lcd_putsxy)(int x, int y, unsigned char *string); + void (*lcd_bitmap)(unsigned char *src, int x, int y, + int nx, int ny, bool clear); + void (*lcd_drawline)(int x1, int y1, int x2, int y2); + void (*lcd_clearline)(int x1, int y1, int x2, int y2); + void (*lcd_drawpixel)(int x, int y); + void (*lcd_clearpixel)(int x, int y); + void (*lcd_setfont)(int font); + void (*lcd_clearrect)(int x, int y, int nx, int ny); + void (*lcd_fillrect)(int x, int y, int nx, int ny); + void (*lcd_drawrect)(int x, int y, int nx, int ny); + void (*lcd_invertrect)(int x, int y, int nx, int ny); + int (*lcd_getstringsize)(unsigned char *str, int *w, int *h); + void (*lcd_update)(void); + void (*lcd_update_rect)(int x, int y, int width, int height); +#ifndef SIMULATOR + void (*lcd_roll)(int pixels); +#endif +#endif + + /* button */ + int (*button_get)(bool block); + int (*button_get_w_tmo)(int ticks); + + /* file */ + int (*open)(const char* pathname, int flags); + int (*close)(int fd); + int (*read)(int fd, void* buf, int count); + int (*lseek)(int fd, int offset, int whence); + int (*creat)(const char *pathname, int mode); + int (*write)(int fd, void* buf, int count); + int (*remove)(const char* pathname); + int (*rename)(const char* path, const char* newname); + int (*ftruncate)(int fd, unsigned int size); + int (*filesize)(int fd); + int (*fprintf)(int fd, const char *fmt, ...); + int (*read_line)(int fd, char* buffer, int buffer_size); + + /* dir */ + DIR* (*opendir)(char* name); + int (*closedir)(DIR* dir); + struct dirent* (*readdir)(DIR* dir); + + /* kernel */ + void (*sleep)(int ticks); + void (*usb_screen)(void); + long* current_tick; + + /* strings and memory */ + int (*snprintf)(char *buf, size_t size, const char *fmt, ...); + char* (*strcpy)(char *dst, const char *src); + size_t (*strlen)(const char *str); + void* (*memset)(void *dst, int c, size_t length); + void* (*memcpy)(void *out, const void *in, size_t n); + + /* sound */ +#ifndef SIMULATOR +#ifdef HAVE_MAS3587F + int (*mas_codec_readreg)(int reg); +#endif +#endif + + /* misc */ + void (*srand)(unsigned int seed); + int (*rand)(void); + void (*splash)(int ticks, int keymask, bool center, char *fmt, ...); +}; + +/* defined by the plugin loader (plugin.c) */ +int plugin_load(char* plugin, void* parameter); + +/* defined by the plugin */ +enum plugin_status plugin_start(struct plugin_api* rockbox, void* parameter) + __attribute__ ((section (".entry"))); + +#endif diff --git a/apps/plugins/Makefile b/apps/plugins/Makefile new file mode 100644 index 0000000000..4c02207016 --- /dev/null +++ b/apps/plugins/Makefile @@ -0,0 +1,45 @@ +# __________ __ ___. +# Open \______ \ ____ ____ | | _\_ |__ _______ ___ +# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / +# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < +# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ +# \/ \/ \/ \/ \/ +# $Id$ +# + +CC = sh-elf-gcc +OC = sh-elf-objcopy + +FIRMWARE = ../../firmware + +INCLUDES = -I$(FIRMWARE)/include -I$(FIRMWARE)/export -I$(FIRMWARE)/common -I$(FIRMWARE)/drivers -I.. +CFLAGS = -O -W -Wall -m1 -nostdlib -ffreestanding -Wstrict-prototypes $(INCLUDES) $(TARGET) $(EXTRA_DEFINES) + +LINKFILE = plugin.lds + +SRC := $(wildcard *.c) +ROCKS := $(SRC:%.c=$(OBJDIR)/%.rock) + +ifndef OBJDIR +no_configure: + @echo "Don't run make here. Run the tools/configure script from your own build" + @echo "directory, then run make there." + @echo + @echo "More help on how to build rockbox can be found here:" + @echo "http://rockbox.haxx.se/docs/how_to_compile.html" +endif + +$(OBJDIR)/%.elf: $(OBJDIR)/%.o $(LINKFILE) + $(CC) -O -nostdlib -o $@ $< -lgcc -T$(LINKFILE) -Wl,-Map,$*.map + +$(OBJDIR)/%.rock : $(OBJDIR)/%.elf + $(OC) -O binary $< $@ + +$(OBJDIR)/%.o: %.c ../plugin.h Makefile + $(CC) $(CFLAGS) -c $< -o $@ + +all: $(ROCKS) + @echo done + +clean: + -rm -f $(ROCKS) diff --git a/apps/recorder/bounce.c b/apps/plugins/bounce.c index ed4885bc39..0c53d49887 100644 --- a/apps/recorder/bounce.c +++ b/apps/plugins/bounce.c @@ -15,26 +15,10 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * - ****************************************************************************/ + **************************************************************************/ +#include "plugin.h" -#include "config.h" -#include "options.h" - -#ifdef USE_DEMOS - -#include "lcd.h" -#include "button.h" -#include "kernel.h" -#include "menu.h" -#include "sprintf.h" -#include "rtc.h" -#include "font.h" -#include "screens.h" - -#ifdef SIMULATOR -#include <stdio.h> -#endif -#include <string.h> +#ifdef HAVE_LCD_BITMAP #define SS_TITLE "Bouncer" #define SS_TITLE_FONT 2 @@ -45,6 +29,7 @@ #define XSPEED 3 #define YADD -4 +static struct plugin_api* rb; static unsigned char table[]={ 26,28,30,33,35,37,39,40,42,43,45,46,46,47,47,47,47,47,46,46,45,43,42,40,39,37,35,33,30,28,26,24,21,19,17,14,12,10,8,7,5,4,2,1,1,0,0,0,0,0,1,1,2,4,5,7,8,10,12,14,17,19,21,23, @@ -186,6 +171,7 @@ struct counter values[]={ {"ydistt", -6}, }; +#ifdef USE_CLOCK static unsigned char yminute[]={ 53,53,52,52,51,50,49,47,46,44,42,40,38,36,34,32,29,27,25,23,21,19,17,16,14,13,12,11,11,10,10,10,11,11,12,13,14,16,17,19,21,23,25,27,29,31,34,36,38,40,42,44,46,47,49,50,51,52,52,53, }; @@ -216,23 +202,24 @@ static void addclock(void) if(pos >= 60) pos -= 60; - lcd_drawline(LCD_WIDTH/2, LCD_HEIGHT/2, xminute[pos], yminute[pos]); + rb->lcd_drawline(LCD_WIDTH/2, LCD_HEIGHT/2, xminute[pos], yminute[pos]); hour = hour*5 + minute/12; pos = 90-hour; if(pos >= 60) pos -= 60; - lcd_drawline(LCD_WIDTH/2, LCD_HEIGHT/2, xhour[pos], yhour[pos]); + rb->lcd_drawline(LCD_WIDTH/2, LCD_HEIGHT/2, xhour[pos], yhour[pos]); /* draw a circle */ for(i=0; i < 60; i+=3) { - lcd_drawline( xminute[i], + rb->lcd_drawline( xminute[i], yminute[i], xminute[(i+1)%60], yminute[(i+1)%60]); } } +#endif static int scrollit(void) { @@ -243,31 +230,33 @@ static int scrollit(void) unsigned int i; int textpos=0; - char rock[]="Rockbox! Pure pleasure. Pure fun. Oooh. What fun! ;-) "; + char* rock="Rockbox! Pure pleasure. Pure fun. Oooh. What fun! ;-) "; int letter; - lcd_clear_display(); + rb->lcd_clear_display(); while(1) { - b = button_get_w_tmo(HZ/10); + b = rb->button_get_w_tmo(HZ/10); if ( b == (BUTTON_OFF|BUTTON_REL) ) return 0; else if ( b == (BUTTON_ON|BUTTON_REL) ) return 1; - lcd_clear_display(); + rb->lcd_clear_display(); for(i=0, yy=y, xx=x; i< LETTERS_ON_SCREEN; i++) { letter = rock[(i+textpos) % (sizeof(rock)-1) ]; - lcd_bitmap((char *)char_gen_12x16[letter-0x20], + rb->lcd_bitmap((char *)char_gen_12x16[letter-0x20], xx, table[yy&63], 11, 16, false); yy += YADD; xx+= LCD_WIDTH/LETTERS_ON_SCREEN; } +#ifdef USE_CLOCK addclock(); - lcd_update(); +#endif + rb->lcd_update(); x-= XSPEED; @@ -292,21 +281,21 @@ static int loopit(void) unsigned int ysanke=0; unsigned int xsanke=0; - char rock[]="ROCKbox"; + char* rock="ROCKbox"; int show=0; int timeout=0; char buffer[30]; - lcd_clear_display(); + rb->lcd_clear_display(); while(1) { - b = button_get_w_tmo(HZ/10); + b = rb->button_get_w_tmo(HZ/10); if ( b == (BUTTON_OFF|BUTTON_REL) ) return 0; if ( b == SYS_USB_CONNECTED) { - usb_screen(); + rb->usb_screen(); return 0; } @@ -318,10 +307,10 @@ static int loopit(void) y+= speed[ysanke&15] + values[NUM_YADD].num; x+= speed[xsanke&15] + values[NUM_XADD].num; - lcd_clear_display(); - + rb->lcd_clear_display(); +#ifdef USE_CLOCK addclock(); - +#endif if(timeout) { switch(b) { case BUTTON_LEFT: @@ -339,18 +328,18 @@ static int loopit(void) show=NUM_LAST-1; break; } - snprintf(buffer, 30, "%s: %d", - values[show].what, values[show].num); - lcd_putsxy(0, 56, buffer); + rb->snprintf(buffer, 30, "%s: %d", + values[show].what, values[show].num); + rb->lcd_putsxy(0, 56, buffer); timeout--; } for(i=0, yy=y, xx=x; i<sizeof(rock)-1; i++, yy+=values[NUM_YDIST].num, xx+=values[NUM_XDIST].num) - lcd_bitmap((char *)char_gen_12x16[rock[i]-0x20], + rb->lcd_bitmap((char *)char_gen_12x16[rock[i]-0x20], xtable[xx%71], table[yy&63], 11, 16, false); - lcd_update(); + rb->lcd_update(); ysanke+= values[NUM_YSANKE].num; xsanke+= values[NUM_XSANKE].num; @@ -358,15 +347,19 @@ static int loopit(void) } -bool bounce(void) +enum plugin_status plugin_start(struct plugin_api* api, void* parameter) { int w, h; char *off = "[Off] to stop"; - int len = strlen(SS_TITLE); + int len; - lcd_setfont(FONT_SYSFIXED); + TEST_PLUGIN_API(api); + (void)(parameter); + rb = api; - lcd_getstringsize(SS_TITLE,&w, &h); + len = rb->strlen(SS_TITLE); + rb->lcd_setfont(FONT_SYSFIXED); + rb->lcd_getstringsize(SS_TITLE,&w, &h); /* Get horizontel centering for text */ len *= w; @@ -380,11 +373,11 @@ bool bounce(void) else h /= 2; - lcd_clear_display(); - lcd_putsxy(LCD_WIDTH/2-len, (LCD_HEIGHT/2)-h, SS_TITLE); + rb->lcd_clear_display(); + rb->lcd_putsxy(LCD_WIDTH/2-len, (LCD_HEIGHT/2)-h, SS_TITLE); len = 1; - lcd_getstringsize(off, &w, &h); + rb->lcd_getstringsize(off, &w, &h); /* Get horizontel centering for text */ len *= w; @@ -398,10 +391,9 @@ bool bounce(void) else h /= 2; - lcd_putsxy(LCD_WIDTH/2-len, LCD_HEIGHT-(2*h), off); - - lcd_update(); - sleep(HZ); + rb->lcd_putsxy(LCD_WIDTH/2-len, LCD_HEIGHT-(2*h), off); + rb->lcd_update(); + rb->sleep(HZ); do { h= loopit(); @@ -409,7 +401,7 @@ bool bounce(void) h = scrollit(); } while(h); - lcd_setfont(FONT_UI); + rb->lcd_setfont(FONT_UI); return false; } diff --git a/apps/recorder/cube.c b/apps/plugins/cube.c index ad3af91c87..996a1a81dd 100644 --- a/apps/recorder/cube.c +++ b/apps/plugins/cube.c @@ -16,22 +16,10 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * -****************************************************************************/ +***************************************************************************/ +#include "plugin.h" -#include "config.h" -#include "options.h" - -#ifdef USE_DEMOS - -#include <stdlib.h> -#include "lcd.h" -#include "config.h" -#include "kernel.h" -#include "menu.h" -#include "button.h" -#include "sprintf.h" -#include "screens.h" -#include "font.h" +#ifdef HAVE_LCD_BITMAP /* Loops that the values are displayed */ #define DISP_TIME 30 @@ -80,6 +68,8 @@ static int sin_table[91] = 10000 }; +static struct plugin_api* rb; + static long sin(int val) { /* Speed improvement through sukzessive lookup */ @@ -214,7 +204,7 @@ static void cube_init(void) static void line(int a, int b) { - lcd_drawline(point2D[a].x, point2D[a].y, point2D[b].x, point2D[b].y); + rb->lcd_drawline(point2D[a].x, point2D[a].y, point2D[b].x, point2D[b].y); } static void cube_draw(void) @@ -234,7 +224,8 @@ static void cube_draw(void) line(3,6); } -bool cube(void) + +enum plugin_status plugin_start(struct plugin_api* api, void* parameter) { int t_disp=0; char buffer[30]; @@ -247,27 +238,31 @@ bool cube(void) int zs=1; bool highspeed=0; bool exit=0; - - lcd_setfont(FONT_SYSFIXED); + + TEST_PLUGIN_API(api); + (void)(parameter); + rb = api; + + rb->lcd_setfont(FONT_SYSFIXED); cube_init(); while(!exit) { if (!highspeed) - sleep(4); + rb->sleep(4); - lcd_clear_display(); + rb->lcd_clear_display(); cube_rotate(xa,ya,za); cube_viewport(); cube_draw(); if (t_disp>0) { t_disp--; - snprintf(buffer, 30, "x:%d y:%d z:%d h:%d",xs,ys,zs,highspeed); - lcd_putsxy(0, 56, buffer); + rb->snprintf(buffer, 30, "x:%d y:%d z:%d h:%d",xs,ys,zs,highspeed); + rb->lcd_putsxy(0, 56, buffer); } - lcd_update(); + rb->lcd_update(); xa+=xs; if (xa>359) @@ -285,7 +280,7 @@ bool cube(void) if (za<0) za+=360; - switch(button_get(false)) + switch(rb->button_get(false)) { case BUTTON_RIGHT: xs+=1; @@ -332,22 +327,12 @@ bool cube(void) break; case SYS_USB_CONNECTED: - usb_screen(); - lcd_setfont(FONT_UI); - return true; + rb->usb_screen(); + return PLUGIN_USB_CONNECTED; } } - lcd_setfont(FONT_UI); - - return false; + return PLUGIN_OK; } -#endif /* USE_DEMOS */ - -/* ----------------------------------------------------------------- - * vim: et sw=4 ts=8 sts=4 tw=78 - */ - - - +#endif diff --git a/apps/plugins/helloworld.c b/apps/plugins/helloworld.c new file mode 100644 index 0000000000..ea347fbf79 --- /dev/null +++ b/apps/plugins/helloworld.c @@ -0,0 +1,48 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2002 Björn Stenberg + * + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include "plugin.h" + +/* welcome to the example rockbox plugin */ + +/* here is a global api struct pointer. while not strictly necessary, + it's nice not to have to pass the api pointer in all function calls + in the plugin */ +static struct plugin_api* rb; + +/* this is the plugin entry point */ +enum plugin_status plugin_start(struct plugin_api* api, void* parameter) +{ + /* this macro should be called as the first thing you do in the plugin. + it test that the api version and model the plugin was compiled for + matches the machine it is running on */ + TEST_PLUGIN_API(api); + + /* if you don't use the parameter, you can do like + this to avoid the compiler warning about it */ + (void)parameter; + + /* if you are using a global api pointer, don't forget to copy it! + otherwise you will get lovely "I04: IllInstr" errors... :-) */ + rb = api; + + /* now go ahead and have fun! */ + rb->splash(HZ*2, 0, true, "Hello world!"); + + return PLUGIN_OK; +} diff --git a/apps/recorder/oscillograph.c b/apps/plugins/oscillograph.c index bf94db168f..a34aa8bfa9 100644 --- a/apps/recorder/oscillograph.c +++ b/apps/plugins/oscillograph.c @@ -16,17 +16,11 @@ * KIND, either express or implied. * ****************************************************************************/ +#include "plugin.h" +#ifdef HAVE_LCD_BITMAP #ifndef SIMULATOR /* don't want this code in the simulator */ -#include <stdlib.h> -#include <sprintf.h> -#include "menu.h" -#include "lcd.h" -#include "button.h" -#include "mas.h" -#include "system.h" - /* The different drawing modes */ #define DRAW_MODE_FILLED 0 #define DRAW_MODE_OUTLINE 1 @@ -47,7 +41,7 @@ static int drawMode = DRAW_MODE_FILLED; * hardware scrolling of the display. The user can change * speed */ -bool oscillograph(void) +enum plugin_status plugin_start(struct plugin_api* rb, void* parameter) { /* stores current volume value left */ int left; @@ -63,22 +57,25 @@ bool oscillograph(void) bool exit = false; + TEST_PLUGIN_API(rb); + (void)parameter; + /* the main loop */ while (!exit) { /* read the volume info from MAS */ - left = mas_codec_readreg(0xC) / (MAX_PEAK / (LCD_WIDTH / 2 - 2)); - right = mas_codec_readreg(0xD) / (MAX_PEAK / (LCD_WIDTH / 2 - 2)); + left = rb->mas_codec_readreg(0xC) / (MAX_PEAK / (LCD_WIDTH / 2 - 2)); + right = rb->mas_codec_readreg(0xD) / (MAX_PEAK / (LCD_WIDTH / 2 - 2)); /* delete current line */ - lcd_clearline(0, y, LCD_WIDTH-1, y); + rb->lcd_clearline(0, y, LCD_WIDTH-1, y); switch (drawMode) { case DRAW_MODE_FILLED: - lcd_drawline(LCD_WIDTH / 2 + 1 , y, - LCD_WIDTH / 2 + 1 + right, y); - lcd_drawline(LCD_WIDTH / 2 - 1 , y, - LCD_WIDTH / 2 - 1 -left , y); + rb->lcd_drawline(LCD_WIDTH / 2 + 1 , y, + LCD_WIDTH / 2 + 1 + right, y); + rb->lcd_drawline(LCD_WIDTH / 2 - 1 , y, + LCD_WIDTH / 2 - 1 -left , y); break; case DRAW_MODE_OUTLINE: @@ -87,10 +84,10 @@ bool oscillograph(void) /* Here real lines were neccessary because anything else was ugly. */ - lcd_drawline(LCD_WIDTH / 2 + right , y, - LCD_WIDTH / 2 + lastRight , lasty); - lcd_drawline(LCD_WIDTH / 2 - left , y, - LCD_WIDTH / 2 - lastLeft, lasty); + rb->lcd_drawline(LCD_WIDTH / 2 + right , y, + LCD_WIDTH / 2 + lastRight , lasty); + rb->lcd_drawline(LCD_WIDTH / 2 - left , y, + LCD_WIDTH / 2 - lastLeft, lasty); /* have to store the old values for drawing lines the next time */ @@ -100,8 +97,8 @@ bool oscillograph(void) case DRAW_MODE_PIXEL: /* straight and simple */ - lcd_drawpixel(LCD_WIDTH / 2 + right, y); - lcd_drawpixel(LCD_WIDTH / 2 - left, y); + rb->lcd_drawpixel(LCD_WIDTH / 2 + right, y); + rb->lcd_drawpixel(LCD_WIDTH / 2 - left, y); break; } @@ -114,19 +111,19 @@ bool oscillograph(void) /* I roll before update because otherwise the new line would appear at the wrong end of the display */ if (roll) - lcd_roll(y); + rb->lcd_roll(y); /* now finally make the new sample visible */ - lcd_update_rect(0, MAX(y-1, 0), LCD_WIDTH, 2); + rb->lcd_update_rect(0, MAX(y-1, 0), LCD_WIDTH, 2); /* There are two mechanisms to alter speed: 1.) slowing down is achieved by increasing - the time waiting for user input. This - mechanism uses positive values. + the time waiting for user input. This + mechanism uses positive values. 2.) speeding up is achieved by leaving out - the user input check for (-speed) volume - samples. For this mechanism negative values - are used. + the user input check for (-speed) volume + samples. For this mechanism negative values + are used. */ if (speed >= 0 || ((speed < 0) && (y % (-speed) == 0))) { @@ -138,7 +135,7 @@ bool oscillograph(void) it must be ensured that at least 1 is passed. */ /* react to user input */ - switch (button_get_w_tmo(MAX(speed, 1))) { + switch (rb->button_get_w_tmo(MAX(speed, 1))) { case BUTTON_UP: speed++; draw = true; @@ -151,7 +148,7 @@ bool oscillograph(void) case BUTTON_PLAY: /* pause the demo */ - button_get(true); + rb->button_get(true); break; case BUTTON_F1: @@ -170,7 +167,7 @@ bool oscillograph(void) That produces ugly results in DRAW_MODE_OUTLINE mode. If rolling is enabled this change will be reverted before the next update anyway.*/ - lcd_roll(0); + rb->lcd_roll(0); break; case BUTTON_F3: @@ -181,27 +178,30 @@ bool oscillograph(void) case BUTTON_OFF: exit = true; break; + + case SYS_USB_CONNECTED: + rb->usb_screen(); + return PLUGIN_USB_CONNECTED; } if (draw) { char buf[16]; - snprintf(buf, sizeof buf, "Speed: %d", -speed); - lcd_putsxy(0, (y + LCD_HEIGHT - 8) % LCD_HEIGHT, buf); - lcd_update_rect(0, (y + LCD_HEIGHT - 8) % LCD_HEIGHT, - LCD_WIDTH, 8); + rb->snprintf(buf, sizeof buf, "Speed: %d", -speed); + rb->lcd_putsxy(0, (y + LCD_HEIGHT - 8) % LCD_HEIGHT, buf); + rb->lcd_update_rect(0, (y + LCD_HEIGHT - 8) % LCD_HEIGHT, + LCD_WIDTH, 8); } } } /* restore to default roll position. Looks funny if you forget to do this... */ - lcd_roll(0); - lcd_update(); + rb->lcd_roll(0); + rb->lcd_update(); /* standard return */ - return false; + return PLUGIN_OK; } #endif /* #ifndef SIMULATOR */ - - +#endif diff --git a/apps/plugins/plugin.lds b/apps/plugins/plugin.lds new file mode 100644 index 0000000000..be6b6fd0a6 --- /dev/null +++ b/apps/plugins/plugin.lds @@ -0,0 +1,26 @@ +OUTPUT_FORMAT(elf32-sh) + +MEMORY +{ + PLUGIN_RAM : ORIGIN = 0x091f8000, LENGTH = 0x8000 +} + +SECTIONS +{ + .text : { + *(.entry) + *(.text) + } > PLUGIN_RAM + + .data : { + *(.data) + } > PLUGIN_RAM + + .bss : { + *(.bss) + } > PLUGIN_RAM + + .rodata : { + *(.rodata) + } > PLUGIN_RAM +} diff --git a/apps/recorder/snow.c b/apps/plugins/snow.c index c4e952f21d..df9966eb38 100644 --- a/apps/recorder/snow.c +++ b/apps/plugins/snow.c @@ -15,17 +15,15 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * - ****************************************************************************/ -#include <stdlib.h> -#include "lcd.h" -#include "config.h" -#include "kernel.h" -#include "menu.h" -#include "button.h" + **************************************************************************/ +#include "plugin.h" + +#ifdef HAVE_LCD_BITMAP #define NUM_PARTICLES 100 static short particles[NUM_PARTICLES][2]; +static struct plugin_api* rb; static bool particle_exists(int particle) { @@ -42,7 +40,7 @@ static int create_particle(void) for (i=0; i<NUM_PARTICLES; i++) { if (!particle_exists(i)) { - particles[i][0]=(rand()%112); + particles[i][0]=(rb->rand()%112); particles[i][1]=0; return i; } @@ -54,13 +52,13 @@ static void snow_move(void) { int i; - if (!(rand()%2)) + if (!(rb->rand()%2)) create_particle(); for (i=0; i<NUM_PARTICLES; i++) { if (particle_exists(i)) { - lcd_clearpixel(particles[i][0],particles[i][1]); - switch ((rand()%7)) { + rb->lcd_clearpixel(particles[i][0],particles[i][1]); + switch ((rb->rand()%7)) { case 0: particles[i][0]++; break; @@ -77,7 +75,7 @@ static void snow_move(void) break; } if (particle_exists(i)) - lcd_drawpixel(particles[i][0],particles[i][1]); + rb->lcd_drawpixel(particles[i][0],particles[i][1]); } } } @@ -90,28 +88,24 @@ static void snow_init(void) particles[i][0]=-1; particles[i][1]=-1; } - lcd_clear_display(); + rb->lcd_clear_display(); } -bool snow(void) +enum plugin_status plugin_start(struct plugin_api* api, void* parameter) { - snow_init(); + TEST_PLUGIN_API(api); + (void)(parameter); + rb = api; + snow_init(); while (1) { snow_move(); - lcd_update(); - sleep(HZ/20); + rb->lcd_update(); + rb->sleep(HZ/20); - if (button_get(false) == BUTTON_OFF) + if (rb->button_get(false) == BUTTON_OFF) return false; } } - - - - - - - - +#endif diff --git a/apps/plugins/sokoban.c b/apps/plugins/sokoban.c new file mode 100644 index 0000000000..2387fa9517 --- /dev/null +++ b/apps/plugins/sokoban.c @@ -0,0 +1,868 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2002 Eric Linenberg + * February 2003: Robert Hak performs a cleanup/rewrite/feature addition. + * Eric smiles. Bjorn cries. Linus say 'huh?'. + * + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include "plugin.h" + +#ifdef HAVE_LCD_BITMAP + +#define SOKOBAN_TITLE "Sokoban" +#define SOKOBAN_TITLE_FONT 2 + +#define LEVELS_FILE "/.rockbox/sokoban/levels.txt" + +#define ROWS 16 +#define COLS 20 +#define MAX_UNDOS 5 + +#define SOKOBAN_LEVEL_SIZE (ROWS*COLS) + +static void init_undo(void); +static void undo(void); +static void add_undo(int button); + +static int get_level(char *level, int level_size); +static int get_level_count(void); +static int load_level(void); +static void draw_level(void); + +static void init_boards(void); +static void update_screen(void); +static bool sokoban_loop(void); + +/* The Location, Undo and LevelInfo structs are OO-flavored. + * (oooh!-flavored as Schnueff puts it.) It makes more you have to know, + * but the overall data layout becomes more manageable. */ + +/* We use the same three values in 2 structs. Makeing them a struct + * hopefully ensures that if you change things in one, the other changes + * as well. */ +struct LevelInfo { + short level; + short moves; + short boxes_to_go; +}; + +/* What a given location on the board looks like at a given time */ +struct Location { + char spot; + short row; + short col; +}; + +/* A single level of undo. Each undo move can affect upto, + * but not more then, 3 spots on the board */ +struct Undo { + struct LevelInfo level; + struct Location location[3]; +}; + +/* Our full undo history */ +static struct UndoInfo { + short count; /* How many undos are there in history */ + short current; /* Which history is the current undo */ + struct Undo history[MAX_UNDOS]; +} undo_info; + +/* Our playing board */ +static struct BoardInfo { + char board[ROWS][COLS]; + struct LevelInfo level; + struct Location player; + int max_level; /* How many levels do we have? */ + int level_offset; /* Where in the level file is this level */ + int loaded_level; /* Which level is in memory */ +} current_info; + +static struct plugin_api* rb; + +static void init_undo(void) +{ + undo_info.count = 0; + undo_info.current = 0; +} + +static void undo(void) +{ + struct Undo *undo; + int i = 0; + short row, col; + + if (undo_info.count == 0) + return; + + /* Update board info */ + undo = &undo_info.history[undo_info.current]; + + rb->memcpy(¤t_info.level, &undo->level, sizeof(undo->level)); + rb->memcpy(¤t_info.player, &undo->location[0], sizeof(undo->location[0])); + + row = undo->location[0].row; + col = undo->location[0].col; + current_info.board[row][col] = '@'; + + /* Update the two other possible spots */ + for (i = 1; i < 3; i++) { + if (undo->location[i].spot != '\0') { + row = undo->location[i].row; + col = undo->location[i].col; + current_info.board[row][col] = undo->location[i].spot; + undo->location[i].spot = '\0'; + } + } + + /* Remove this undo from the list */ + if (undo_info.current == 0) { + if (undo_info.count > 1) + undo_info.current = MAX_UNDOS - 1; + } else { + undo_info.current--; + } + + undo_info.count--; + + return; +} + +static void add_undo(int button) +{ + struct Undo *undo; + int row, col, i; + bool storable; + + if ((button != BUTTON_LEFT) && (button != BUTTON_RIGHT) && + (button != BUTTON_UP) && (button != BUTTON_DOWN)) + return; + + if (undo_info.count != 0) { + if (undo_info.current < (MAX_UNDOS - 1)) + undo_info.current++; + else + undo_info.current = 0; + } + + /* Make what follows more readable */ + undo = &undo_info.history[undo_info.current]; + + /* Store our level info */ + rb->memcpy(&undo->level, ¤t_info.level, sizeof(undo->level)); + + /* Store our player info */ + rb->memcpy(&undo->location[0], ¤t_info.player, sizeof(undo->location[0])); + + /* Now we need to store upto 2 blocks that may be affected. + * If player.spot is NULL, then there is no info stored + * for that block */ + + row = current_info.player.row; + col = current_info.player.col; + + /* This must stay as _1_ because the first block (0) is the player */ + for (i = 1; i < 3; i++) { + storable = true; + + switch (button) { + case BUTTON_LEFT: + col--; + if (col < 0) + storable = false; + break; + + case BUTTON_RIGHT: + col++; + if (col >= COLS) + storable = false; + break; + + case BUTTON_UP: + row--; + if (row < 0) + storable = false; + break; + + case BUTTON_DOWN: + row++; + if (row >= ROWS) + storable = false; + break; + + default: + return; + } + + if (storable) { + undo->location[i].col = col; + undo->location[i].row = row; + undo->location[i].spot = current_info.board[row][col]; + } else { + undo->location[i].spot = '\0'; + } + } + + if (undo_info.count < MAX_UNDOS) + undo_info.count++; +} + +static void init_boards(void) +{ + current_info.level.level = 0; + current_info.level.moves = 0; + current_info.level.boxes_to_go = 0; + current_info.player.row = 0; + current_info.player.col = 0; + current_info.player.spot = ' '; + current_info.max_level = 0; + current_info.level_offset = 0; + current_info.loaded_level = 0; + + init_undo(); +} + +static int get_level_count(void) +{ + int fd = 0; + int lastlen = 0; + char buffer[COLS + 3]; /* COLS plus CR/LF and \0 */ + + if ((fd = rb->open(LEVELS_FILE, O_RDONLY)) < 0) { + rb->splash(0, 0, true, "Unable to open %s", LEVELS_FILE); + return -1; + } + + while(1) { + int len = rb->read_line(fd, buffer, sizeof(buffer)); + if(len <= 0) + break; + + /* Two short lines in a row means new level */ + if(len < 3 && lastlen < 3) + current_info.max_level++; + + lastlen = len; + } + + rb->close(fd); + return 0; +} + +static int get_level(char *level, int level_size) +{ + int fd = 0, i = 0; + int nread = 0; + int count = 0; + int lastlen = 0; + int level_ct = 1; + unsigned char buffer[SOKOBAN_LEVEL_SIZE * 2]; + bool level_found = false; + + /* open file */ + if ((fd = rb->open(LEVELS_FILE, O_RDONLY)) < 0) + return -1; + + /* Lets not reparse the full file if we can avoid it */ + if (current_info.loaded_level < current_info.level.level) { + rb->lseek(fd, current_info.level_offset, SEEK_SET); + level_ct = current_info.loaded_level; + } + + if(current_info.level.level > 1) { + while(!level_found) { + int len = rb->read_line(fd, buffer, SOKOBAN_LEVEL_SIZE); + if(len <= 0) { + rb->close(fd); + return -1; + } + + /* Two short lines in a row means new level */ + if(len < 3 && lastlen < 3) { + level_ct++; + if(level_ct == current_info.level.level) + level_found = true; + } + lastlen = len; + } + } + + /* Remember the current offset */ + current_info.level_offset = rb->lseek(fd, 0, SEEK_CUR); + + /* read a full buffer chunk from here */ + nread = rb->read(fd, buffer, sizeof(buffer)-1); + if (nread < 0) + return -1; + buffer[nread] = 0; + + rb->close(fd); + + /* If we read less then a level, error */ + if (nread < level_size) + return -1; + + /* Load our new level */ + for(i=0, count=0; (count < nread) && (i<level_size);) { + if (buffer[count] != '\n' && buffer[count] != '\r') + level[i++] = buffer[count]; + count++; + } + level[i] = 0; + + current_info.loaded_level = current_info.level.level; + return 0; +} + +/* return non-zero on error */ +static int load_level(void) +{ + short c = 0; + short r = 0; + short i = 0; + char level[ROWS*COLS+1]; + int x = 0; + + current_info.player.spot=' '; + current_info.level.boxes_to_go = 0; + current_info.level.moves = 0; + + if (get_level(level, sizeof(level)) != 0) + return -1; + + i = 0; + for (r = 0; r < ROWS; r++) { + x++; + for (c = 0; c < COLS; c++, i++) { + current_info.board[r][c] = level[i]; + + if (current_info.board[r][c] == '.') + current_info.level.boxes_to_go++; + + else if (current_info.board[r][c] == '@') { + current_info.player.row = r; + current_info.player.col = c; + } + } + } + + return 0; +} + +static void update_screen(void) +{ + short b = 0, c = 0; + short rows = 0, cols = 0; + char s[25]; + + short magnify = 4; + + /* load the board to the screen */ + for (rows=0 ; rows < ROWS ; rows++) { + for (cols = 0 ; cols < COLS ; cols++) { + c = cols * magnify; + b = rows * magnify; + + switch(current_info.board[rows][cols]) { + case 'X': /* black space */ + rb->lcd_drawrect(c, b, magnify, magnify); + rb->lcd_drawrect(c+1, b+1, 2, 2); + break; + + case '#': /* this is a wall */ + rb->lcd_drawpixel(c, b); + rb->lcd_drawpixel(c+2, b); + rb->lcd_drawpixel(c+1, b+1); + rb->lcd_drawpixel(c+3, b+1); + rb->lcd_drawpixel(c, b+2); + rb->lcd_drawpixel(c+2, b+2); + rb->lcd_drawpixel(c+1, b+3); + rb->lcd_drawpixel(c+3, b+3); + break; + + case '.': /* this is a home location */ + rb->lcd_drawrect(c+1, b+1, 2, 2); + break; + + case '$': /* this is a box */ + rb->lcd_drawrect(c, b, magnify, magnify); + break; + + case '@': /* this is you */ + rb->lcd_drawline(c+1, b, c+2, b); + rb->lcd_drawline(c, b+1, c+3, b+1); + rb->lcd_drawline(c+1, b+2, c+2, b+2); + + rb->lcd_drawpixel(c, b+3); + rb->lcd_drawpixel(c+3, b+3); + break; + + case '%': /* this is a box on a home spot */ + rb->lcd_drawrect(c, b, magnify, magnify); + rb->lcd_drawrect(c+1, b+1, 2, 2); + break; + } + } + } + + + rb->snprintf(s, sizeof(s), "%d", current_info.level.level); + rb->lcd_putsxy(86, 22, s); + rb->snprintf(s, sizeof(s), "%d", current_info.level.moves); + rb->lcd_putsxy(86, 54, s); + + rb->lcd_drawrect(80,0,32,32); + rb->lcd_drawrect(80,32,32,64); + rb->lcd_putsxy(81, 10, "Level"); + rb->lcd_putsxy(81, 42, "Moves"); + + /* print out the screen */ + rb->lcd_update(); +} + +static void draw_level(void) +{ + load_level(); + rb->lcd_clear_display(); + update_screen(); +} + +static bool sokoban_loop(void) +{ + char new_spot; + bool moved = true; + int i = 0, button = 0; + short r = 0, c = 0; + + current_info.level.level = 1; + + load_level(); + update_screen(); + + while (1) { + moved = true; + + r = current_info.player.row; + c = current_info.player.col; + + button = rb->button_get(true); + + add_undo(button); + + switch(button) + { + case BUTTON_OFF: + /* get out of here */ + return PLUGIN_OK; + + case BUTTON_ON: + case BUTTON_ON | BUTTON_REPEAT: + /* this is UNDO */ + undo(); + rb->lcd_clear_display(); + update_screen(); + moved = false; + break; + + case BUTTON_F3: + case BUTTON_F3 | BUTTON_REPEAT: + /* increase level */ + init_undo(); + current_info.level.boxes_to_go=0; + moved = true; + break; + + case BUTTON_F1: + case BUTTON_F1 | BUTTON_REPEAT: + /* previous level */ + init_undo(); + if (current_info.level.level > 1) + current_info.level.level--; + + draw_level(); + moved = false; + break; + + case BUTTON_F2: + case BUTTON_F2 | BUTTON_REPEAT: + /* same level */ + init_undo(); + draw_level(); + moved = false; + break; + + case BUTTON_LEFT: + switch(current_info.board[r][c-1]) + { + case ' ': /* if it is a blank spot */ + case '.': /* if it is a home spot */ + new_spot = current_info.board[r][c-1]; + current_info.board[r][c-1] = '@'; + current_info.board[r][c] = current_info.player.spot; + current_info.player.spot = new_spot; + break; + + case '$': + switch(current_info.board[r][c-2]) + { + case ' ': /* going from blank to blank */ + current_info.board[r][c-2] = current_info.board[r][c-1]; + current_info.board[r][c-1] = current_info.board[r][c]; + current_info.board[r][c] = current_info.player.spot; + current_info.player.spot = ' '; + break; + + case '.': /* going from a blank to home */ + current_info.board[r][c-2] = '%'; + current_info.board[r][c-1] = current_info.board[r][c]; + current_info.board[r][c] = current_info.player.spot; + current_info.player.spot = ' '; + current_info.level.boxes_to_go--; + break; + + default: + moved = false; + break; + } + break; + + case '%': + switch(current_info.board[r][c-2]) { + case ' ': /* we are going from a home to a blank */ + current_info.board[r][c-2] = '$'; + current_info.board[r][c-1] = current_info.board[r][c]; + current_info.board[r][c] = current_info.player.spot; + current_info.player.spot = '.'; + current_info.level.boxes_to_go++; + break; + + case '.': /* if we are going from a home to home */ + current_info.board[r][c-2] = '%'; + current_info.board[r][c-1] = current_info.board[r][c]; + current_info.board[r][c] = current_info.player.spot; + current_info.player.spot = '.'; + break; + + default: + moved = false; + break; + } + break; + + default: + moved = false; + break; + } + + if (moved) + current_info.player.col--; + break; + + case BUTTON_RIGHT: /* if it is a blank spot */ + switch(current_info.board[r][c+1]) { + case ' ': + case '.': /* if it is a home spot */ + new_spot = current_info.board[r][c+1]; + current_info.board[r][c+1] = '@'; + current_info.board[r][c] = current_info.player.spot; + current_info.player.spot = new_spot; + break; + + case '$': + switch(current_info.board[r][c+2]) { + case ' ': /* going from blank to blank */ + current_info.board[r][c+2] = current_info.board[r][c+1]; + current_info.board[r][c+1] = current_info.board[r][c]; + current_info.board[r][c] = current_info.player.spot; + current_info.player.spot = ' '; + break; + + case '.': /* going from a blank to home */ + current_info.board[r][c+2] = '%'; + current_info.board[r][c+1] = current_info.board[r][c]; + current_info.board[r][c] = current_info.player.spot; + current_info.player.spot = ' '; + current_info.level.boxes_to_go--; + break; + + default: + moved = false; + break; + } + break; + + case '%': + switch(current_info.board[r][c+2]) { + case ' ': /* going from a home to a blank */ + current_info.board[r][c+2] = '$'; + current_info.board[r][c+1] = current_info.board[r][c]; + current_info.board[r][c] = current_info.player.spot; + current_info.player.spot = '.'; + current_info.level.boxes_to_go++; + break; + + case '.': + current_info.board[r][c+2] = '%'; + current_info.board[r][c+1] = current_info.board[r][c]; + current_info.board[r][c] = current_info.player.spot; + current_info.player.spot = '.'; + break; + + default: + moved = false; + break; + } + break; + + default: + moved = false; + break; + } + + if (moved) + current_info.player.col++; + break; + + case BUTTON_UP: + switch(current_info.board[r-1][c]) { + case ' ': /* if it is a blank spot */ + case '.': /* if it is a home spot */ + new_spot = current_info.board[r-1][c]; + current_info.board[r-1][c] = '@'; + current_info.board[r][c] = current_info.player.spot; + current_info.player.spot = new_spot; + break; + + case '$': + switch(current_info.board[r-2][c]) { + case ' ': /* going from blank to blank */ + current_info.board[r-2][c] = current_info.board[r-1][c]; + current_info.board[r-1][c] = current_info.board[r][c]; + current_info.board[r][c] = current_info.player.spot; + current_info.player.spot = ' '; + break; + + case '.': /* going from a blank to home */ + current_info.board[r-2][c] = '%'; + current_info.board[r-1][c] = current_info.board[r][c]; + current_info.board[r][c] = current_info.player.spot; + current_info.player.spot = ' '; + current_info.level.boxes_to_go--; + break; + + default: + moved = false; + break; + } + break; + + case '%': + switch(current_info.board[r-2][c]) { + case ' ': /* we are going from a home to a blank */ + current_info.board[r-2][c] = '$'; + current_info.board[r-1][c] = current_info.board[r][c]; + current_info.board[r][c] = current_info.player.spot; + current_info.player.spot = '.'; + current_info.level.boxes_to_go++; + break; + + case '.': /* if we are going from a home to home */ + current_info.board[r-2][c] = '%'; + current_info.board[r-1][c] = current_info.board[r][c]; + current_info.board[r][c] = current_info.player.spot; + current_info.player.spot = '.'; + break; + + default: + moved = false; + break; + } + break; + + default: + moved = false; + break; + } + + if (moved) + current_info.player.row--; + break; + + case BUTTON_DOWN: + switch(current_info.board[r+1][c]) { + case ' ': /* if it is a blank spot */ + case '.': /* if it is a home spot */ + new_spot = current_info.board[r+1][c]; + current_info.board[r+1][c] = '@'; + current_info.board[r][c] = current_info.player.spot; + current_info.player.spot = new_spot; + break; + + case '$': + switch(current_info.board[r+2][c]) { + case ' ': /* going from blank to blank */ + current_info.board[r+2][c] = current_info.board[r+1][c]; + current_info.board[r+1][c] = current_info.board[r][c]; + current_info.board[r][c] = current_info.player.spot; + current_info.player.spot = ' '; + break; + + case '.': /* going from a blank to home */ + current_info.board[r+2][c] = '%'; + current_info.board[r+1][c] = current_info.board[r][c]; + current_info.board[r][c] = current_info.player.spot; + current_info.player.spot = ' '; + current_info.level.boxes_to_go--; + break; + + default: + moved = false; + break; + } + break; + + case '%': + switch(current_info.board[r+2][c]) { + case ' ': /* going from a home to a blank */ + current_info.board[r+2][c] = '$'; + current_info.board[r+1][c] = current_info.board[r][c]; + current_info.board[r][c] = current_info.player.spot; + current_info.player.spot = '.'; + current_info.level.boxes_to_go++; + break; + + case '.': /* going from a home to home */ + current_info.board[r+2][c] = '%'; + current_info.board[r+1][c] = current_info.board[r][c]; + current_info.board[r][c] = current_info.player.spot; + current_info.player.spot = '.'; + break; + + default: + moved = false; + break; + } + break; + + default: + moved = false; + break; + } + + if (moved) + current_info.player.row++; + break; + + case SYS_USB_CONNECTED: + rb->usb_screen(); + return PLUGIN_USB_CONNECTED; + + default: + moved = false; + break; + } + + if (moved) { + current_info.level.moves++; + rb->lcd_clear_display(); + update_screen(); + } + + /* We have completed this level */ + if (current_info.level.boxes_to_go == 0) { + current_info.level.level++; + + /* clear undo stats */ + init_undo(); + + rb->lcd_clear_display(); + + if (current_info.level.level > current_info.max_level) { + rb->lcd_putsxy(10, 20, "You WIN!!"); + + for (i = 0; i < 30000 ; i++) { + rb->lcd_invertrect(0, 0, 111, 63); + rb->lcd_update(); + + button = rb->button_get(false); + if (button && ((button & BUTTON_REL) != BUTTON_REL)) + break; + } + + return PLUGIN_OK; + } + + load_level(); + update_screen(); + } + + } /* end while */ + + return PLUGIN_OK; +} + + +enum plugin_status plugin_start(struct plugin_api* api, void* parameter) +{ + int w, h; + int len; + + TEST_PLUGIN_API(api); + (void)(parameter); + rb = api; + + rb->lcd_setfont(FONT_SYSFIXED); + rb->lcd_getstringsize(SOKOBAN_TITLE, &w, &h); + + /* Get horizontel centering for text */ + len = w; + if (len%2 != 0) + len =((len+1)/2)+(w/2); + else + len /= 2; + + if (h%2 != 0) + h = (h/2)+1; + else + h /= 2; + + rb->lcd_clear_display(); + rb->lcd_putsxy(LCD_WIDTH/2-len,(LCD_HEIGHT/2)-h, SOKOBAN_TITLE); + rb->lcd_update(); + rb->sleep(HZ*2); + + rb->lcd_clear_display(); + + rb->lcd_putsxy(3, 6, "[OFF] To Stop"); + rb->lcd_putsxy(3, 16, "[ON] To Undo"); + rb->lcd_putsxy(3, 26, "[F1] - Level"); + rb->lcd_putsxy(3, 36, "[F2] Same Level"); + rb->lcd_putsxy(3, 46, "[F3] + Level"); + + rb->lcd_update(); + rb->sleep(HZ*2); + rb->lcd_clear_display(); + + init_boards(); + + if (get_level_count() != 0) { + rb->splash(HZ*2,0,true,"Failed loading levels!"); + return PLUGIN_OK; + } + + return sokoban_loop(); +} + +#endif diff --git a/apps/viewer.c b/apps/plugins/viewer.c index f653866626..f8dc309a6e 100644 --- a/apps/viewer.c +++ b/apps/plugins/viewer.c @@ -17,24 +17,9 @@ * KIND, either express or implied. * ****************************************************************************/ -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <stdbool.h> - -#include "file.h" -#include "lcd.h" -#include "button.h" -#include "kernel.h" -#include "font.h" -#include "settings.h" -#include "icons.h" -#include "screens.h" -#include "status.h" - +#include "plugin.h" #define BUFFER_SIZE 1024 - #define OUTSIDE_BUFFER -10 #define OUTSIDE_FILE -11 @@ -50,6 +35,7 @@ static int begin_line; /* Index of the first line displayed on the lcd */ static int end_line; /* Index of the last line displayed on the lcd */ static int begin_line_pos; /* Position of the first_line in the bufffer */ static int end_line_pos; /* Position of the last_line in the buffer */ +static struct plugin_api* rb; /* * Known issue: The caching algorithm will fail (display incoherent data) if @@ -61,7 +47,7 @@ static void display_line_count(void) { #ifdef HAVE_LCD_BITMAP int w,h; - lcd_getstringsize("M", &w, &h); + rb->lcd_getstringsize("M", &w, &h); display_lines = LCD_HEIGHT / h; display_columns = LCD_WIDTH / w; #else @@ -126,7 +112,7 @@ static void viewer_draw(int col) char* str; int line_pos; - lcd_clear_display(); + rb->lcd_clear_display(); line_pos = begin_line_pos; @@ -137,11 +123,12 @@ static void viewer_draw(int col) str = buffer + line_pos + 1; for (j=0; j<col && *str!=0; ++j) str++; - lcd_puts(0, i, str); + rb->lcd_puts(0, i, str); line_pos = find_next_line(line_pos); } - - lcd_update(); +#ifdef HAVE_LCD_BITMAP + rb->lcd_update(); +#endif } static void fill_buffer(int pos) @@ -154,8 +141,8 @@ static void fill_buffer(int pos) if (pos<0) pos = 0; - lseek(fd, pos, SEEK_SET); - numread = read(fd, buffer, BUFFER_SIZE); + rb->lseek(fd, pos, SEEK_SET); + numread = rb->read(fd, buffer, BUFFER_SIZE); begin_line_pos -= pos - buffer_pos; end_line_pos -= pos - buffer_pos; @@ -181,11 +168,11 @@ static bool viewer_init(char* file) int i; int ret; - fd = open(file, O_RDONLY); + fd = rb->open(file, O_RDONLY); if (fd==-1) return false; - file_size = lseek(fd, 0, SEEK_END); + file_size = rb->lseek(fd, 0, SEEK_END); buffer_pos = 0; begin_line = 0; @@ -207,7 +194,7 @@ static bool viewer_init(char* file) static void viewer_exit(void) { - close(fd); + rb->close(fd); } static void viewer_scroll_down(void) @@ -264,7 +251,7 @@ static int pagescroll(int col) int i; while (!exit) { - switch (button_get(true)) { + switch (rb->button_get(true)) { #ifdef HAVE_RECORDER_KEYPAD case BUTTON_ON | BUTTON_UP: case BUTTON_ON | BUTTON_UP | BUTTON_REPEAT: @@ -328,31 +315,30 @@ static int pagescroll(int col) return col; } -bool viewer_run(char* file) + +enum plugin_status plugin_start(struct plugin_api* api, void* file) { bool exit=false; int button; int col = 0; int ok; -#ifdef HAVE_LCD_BITMAP - /* no margins */ - lcd_setmargins(0, 0); -#endif + TEST_PLUGIN_API(api); + rb = api; + + if (!file) + return PLUGIN_ERROR; ok = viewer_init(file); if (!ok) { - lcd_clear_display(); - lcd_puts(0, 0, "Error"); - lcd_update(); - sleep(HZ); + rb->splash(HZ, 0, false, "Error"); viewer_exit(); - return false; + return PLUGIN_OK; } viewer_draw(col); while (!exit) { - button = button_get(true); + button = rb->button_get(true); switch ( button ) { @@ -420,13 +406,10 @@ bool viewer_run(char* file) break; case SYS_USB_CONNECTED: - usb_screen(); -#ifdef HAVE_LCD_CHARCELLS - status_set_param(false); -#endif + rb->usb_screen(); viewer_exit(); - return true; + return PLUGIN_USB_CONNECTED; } } - return false; + return PLUGIN_OK; } diff --git a/apps/recorder/wormlet.c b/apps/plugins/wormlet.c index 2937a1bb83..be089cdb7c 100644 --- a/apps/recorder/wormlet.c +++ b/apps/plugins/wormlet.c @@ -16,26 +16,9 @@ * KIND, either express or implied. * ****************************************************************************/ +#include "plugin.h" -#include "config.h" -#include "options.h" - -#ifdef USE_GAMES - -/* #define DEBUG_WORMLET */ - -#include <sprintf.h> -#include <stdlib.h> -#include <string.h> -#include "system.h" -#include "lcd.h" -#include "button.h" -#include "kernel.h" -#include "menu.h" -#include "rtc.h" -#include "lang.h" -#include "screens.h" -#include "font.h" +#ifdef HAVE_LCD_BITMAP /* size of the field the worm lives in */ #define FIELD_RECT_X 1 @@ -149,6 +132,9 @@ static int player3_dir = EAST; control a worm */ static int players = 1; +/* the rockbox plugin api */ +static struct plugin_api* rb; + #ifdef DEBUG_WORMLET static void set_debug_out(char *str){ strcpy(debugout, str); @@ -507,8 +493,8 @@ static int make_food(int index) { do { /* make coordinates for a new food so that the entire food lies within the FIELD */ - x = rand() % (FIELD_RECT_WIDTH - FOOD_SIZE); - y = rand() % (FIELD_RECT_HEIGHT - FOOD_SIZE); + x = rb->rand() % (FIELD_RECT_WIDTH - FOOD_SIZE); + y = rb->rand() % (FIELD_RECT_HEIGHT - FOOD_SIZE); tries ++; /* Ensure that the new food doesn't collide with any @@ -549,7 +535,7 @@ static int make_food(int index) { static void clear_food(int index) { /* remove the old food from the screen */ - lcd_clearrect(foodx[index] + FIELD_RECT_X, + rb->lcd_clearrect(foodx[index] + FIELD_RECT_X, foody[index] + FIELD_RECT_Y, FOOD_SIZE, FOOD_SIZE); } @@ -563,10 +549,10 @@ static void clear_food(int index) static void draw_food(int index) { /* draw the food object */ - lcd_fillrect(foodx[index] + FIELD_RECT_X, + rb->lcd_fillrect(foodx[index] + FIELD_RECT_X, foody[index] + FIELD_RECT_Y, FOOD_SIZE, FOOD_SIZE); - lcd_clearrect(foodx[index] + FIELD_RECT_X + 1, + rb->lcd_clearrect(foodx[index] + FIELD_RECT_X + 1, foody[index] + FIELD_RECT_Y + 1, FOOD_SIZE - 2, FOOD_SIZE - 2); } @@ -588,8 +574,8 @@ static int make_argh(int index) do { /* make coordinates for a new argh so that the entire food lies within the FIELD */ - x = rand() % (FIELD_RECT_WIDTH - ARGH_SIZE); - y = rand() % (FIELD_RECT_HEIGHT - ARGH_SIZE); + x = rb->rand() % (FIELD_RECT_WIDTH - ARGH_SIZE); + y = rb->rand() % (FIELD_RECT_HEIGHT - ARGH_SIZE); tries ++; /* Ensure that the new argh doesn't intersect with any @@ -631,7 +617,7 @@ static int make_argh(int index) static void draw_argh(int index) { /* draw the new argh */ - lcd_fillrect(arghx[index] + FIELD_RECT_X, + rb->lcd_fillrect(arghx[index] + FIELD_RECT_X, arghy[index] + FIELD_RECT_Y, ARGH_SIZE, ARGH_SIZE); } @@ -744,7 +730,7 @@ static void init_wormlet(void) } /* Needed when the game is restarted using BUTTON_ON */ - lcd_clear_display(); + rb->lcd_clear_display(); /* make and display some food and argh */ argh_count = MAX_FOOD; @@ -756,11 +742,11 @@ static void init_wormlet(void) } /* draw the game field */ - lcd_invertrect(0, 0, FIELD_RECT_WIDTH + 2, FIELD_RECT_HEIGHT + 2); - lcd_invertrect(1, 1, FIELD_RECT_WIDTH, FIELD_RECT_HEIGHT); + rb->lcd_invertrect(0, 0, FIELD_RECT_WIDTH + 2, FIELD_RECT_HEIGHT + 2); + rb->lcd_invertrect(1, 1, FIELD_RECT_WIDTH, FIELD_RECT_HEIGHT); /* make everything visible */ - lcd_update(); + rb->lcd_update(); } @@ -852,14 +838,14 @@ static void draw_worm(struct worm *w) int x = w->x[w->head]; int y = w->y[w->head]; if (x >= 0 && x < FIELD_RECT_WIDTH && y >= 0 && y < FIELD_RECT_HEIGHT) { - lcd_drawpixel(x + FIELD_RECT_X, y + FIELD_RECT_Y); + rb->lcd_drawpixel(x + FIELD_RECT_X, y + FIELD_RECT_Y); } /* clear the space behind the worm */ x = w->x[w->tail] ; y = w->y[w->tail] ; if (x >= 0 && x < FIELD_RECT_WIDTH && y >= 0 && y < FIELD_RECT_HEIGHT) { - lcd_clearpixel(x + FIELD_RECT_X, y + FIELD_RECT_Y); + rb->lcd_clearpixel(x + FIELD_RECT_X, y + FIELD_RECT_Y); } } @@ -1166,10 +1152,10 @@ static void virtual_player(struct worm *w) { static void score_board(void) { char buf[15]; - char buf2[15]; + char* buf2 = NULL; int i; int y = 0; - lcd_clearrect(FIELD_RECT_WIDTH + 2, 0, LCD_WIDTH - FIELD_RECT_WIDTH - 2, LCD_HEIGHT); + rb->lcd_clearrect(FIELD_RECT_WIDTH + 2, 0, LCD_WIDTH - FIELD_RECT_WIDTH - 2, LCD_HEIGHT); for (i = 0; i < worm_count; i++) { int score = get_score(&worms[i]); @@ -1180,54 +1166,52 @@ static void score_board(void) } } - /* length */ - snprintf(buf, sizeof (buf),str(LANG_WORMLET_LENGTH), score); + /* length */ + rb->snprintf(buf, sizeof (buf),"Len:%d", score); /* worm state */ switch (check_collision(&worms[i])) { - case COLLISION_NONE: - if (worms[i].growing > 0){ - snprintf(buf2, sizeof(buf2), str(LANG_WORMLET_GROWING)); - } + case COLLISION_NONE: + if (worms[i].growing > 0) + buf2 = "Growing"; else { - if (worms[i].alive) { - snprintf(buf2, sizeof(buf2), str(LANG_WORMLET_HUNGRY)); - } else { - snprintf(buf2, sizeof(buf2), str(LANG_WORMLET_WORMED)); - } + if (worms[i].alive) + buf2 = "Hungry"; + else + buf2 = "Wormed"; } - break; + break; - case COLLISION_WORM: - snprintf(buf2, sizeof(buf2), str(LANG_WORMLET_WORMED)); - break; + case COLLISION_WORM: + buf2 = "Wormed"; + break; - case COLLISION_FOOD: - snprintf(buf2, sizeof(buf2), str(LANG_WORMLET_GROWING)); - break; + case COLLISION_FOOD: + buf2 = "Growing"; + break; - case COLLISION_ARGH: - snprintf(buf2, sizeof(buf2), str(LANG_WORMLET_ARGH)); - break; + case COLLISION_ARGH: + buf2 = "Argh"; + break; - case COLLISION_FIELD: - snprintf(buf2, sizeof(buf2), str(LANG_WORMLET_CRASHED)); - break; - } - lcd_putsxy(FIELD_RECT_WIDTH + 3, y , buf); - lcd_putsxy(FIELD_RECT_WIDTH + 3, y+8, buf2); + case COLLISION_FIELD: + buf2 = "Crashed"; + break; + } + rb->lcd_putsxy(FIELD_RECT_WIDTH + 3, y , buf); + rb->lcd_putsxy(FIELD_RECT_WIDTH + 3, y+8, buf2); if (!worms[i].alive){ - lcd_invertrect(FIELD_RECT_WIDTH + 2, y, - LCD_WIDTH - FIELD_RECT_WIDTH - 2, 17); + rb->lcd_invertrect(FIELD_RECT_WIDTH + 2, y, + LCD_WIDTH - FIELD_RECT_WIDTH - 2, 17); } y += 19; } - snprintf(buf , sizeof(buf), str(LANG_WORMLET_HIGHSCORE), highscore); + rb->snprintf(buf , sizeof(buf), "Hs: %d", highscore); #ifndef DEBUG_WORMLET - lcd_putsxy(FIELD_RECT_WIDTH + 3, LCD_HEIGHT - 8, buf); + rb->lcd_putsxy(FIELD_RECT_WIDTH + 3, LCD_HEIGHT - 8, buf); #else - lcd_putsxy(FIELD_RECT_WIDTH + 3, LCD_HEIGHT - 8, debugout); + rb->lcd_putsxy(FIELD_RECT_WIDTH + 3, LCD_HEIGHT - 8, debugout); #endif } @@ -1305,7 +1289,7 @@ static bool run(void) /* initialize the board and so on */ init_wormlet(); - cycle_start = current_tick; + cycle_start = *rb->current_tick; /* change the direction of the worm */ while (button != BUTTON_OFF && ! wormDead) { @@ -1358,7 +1342,7 @@ static bool run(void) case BUTTON_PLAY: do { - button = button_get(true); + button = rb->button_get(true); } while (button != BUTTON_PLAY && button != BUTTON_OFF && button != BUTTON_ON); @@ -1377,7 +1361,7 @@ static bool run(void) draw_worm(w); } score_board(); - lcd_update(); + rb->lcd_update(); if (button == BUTTON_ON) { wormDead = true; } @@ -1385,7 +1369,7 @@ static bool run(void) /* here the wormlet game cycle ends thus the current tick is stored as end time */ - cycle_end = current_tick; + cycle_end = *rb->current_tick; /* The duration of the game cycle */ cycle_duration = cycle_end - cycle_start; @@ -1403,15 +1387,14 @@ static bool run(void) max_cycle = cycle_duration; ticks_to_max_cycle_reset = 20; } - snprintf(buf, sizeof buf, "ticks %d", max_cycle); + rb->snprintf(buf, sizeof buf, "ticks %d", max_cycle); set_debug_out(buf); #endif /* adjust the number of ticks to wait for a button. This ensures that a complete game cycle including user input runs in constant time */ - button = button_get_w_tmo(SPEED - cycle_duration); - cycle_start = current_tick; - + button = rb->button_get_w_tmo(SPEED - cycle_duration); + cycle_start = *rb->current_tick; } return wormDead; } @@ -1425,7 +1408,7 @@ static bool run(void) static void test_worm_food_collision(void) { int collision_count = 0; int i; - lcd_clear_display(); + rb->lcd_clear_display(); init_worm(&worms[0], 10, 10); add_growing(&worms[0], 10); set_worm_dir(&worms[0], EAST); @@ -1451,12 +1434,12 @@ static void test_worm_food_collision(void) { if (collision) { collision_count++; } - snprintf(buf, sizeof buf, "collisions: %d", collision_count); - lcd_putsxy(0, LCD_HEIGHT -8, buf); - lcd_update(); + rb->snprintf(buf, sizeof buf, "collisions: %d", collision_count); + rb->lcd_putsxy(0, LCD_HEIGHT -8, buf); + rb->lcd_update(); } if (collision_count != FOOD_SIZE) { - button_get(true); + rb->button_get(true); } @@ -1470,12 +1453,12 @@ static void test_worm_food_collision(void) { if (collision) { collision_count ++; } - snprintf(buf, sizeof buf, "collisions: %d", collision_count); - lcd_putsxy(0, LCD_HEIGHT -8, buf); - lcd_update(); + rb->snprintf(buf, sizeof buf, "collisions: %d", collision_count); + rb->lcd_putsxy(0, LCD_HEIGHT -8, buf); + rb->lcd_update(); } if (collision_count != FOOD_SIZE * 2) { - button_get(true); + rb->button_get(true); } } @@ -1498,7 +1481,7 @@ static void test_worm_argh_collision(void) { int i; int dir; int collision_count = 0; - lcd_clear_display(); + rb->lcd_clear_display(); init_worm(&worms[0], 10, 10); add_growing(&worms[0], 40); for (dir = 0; dir < 4; dir++) { @@ -1518,12 +1501,12 @@ static void test_worm_argh_collision(void) { if (collision) { collision_count ++; } - snprintf(buf, sizeof buf, "collisions: %d", collision_count); - lcd_putsxy(0, LCD_HEIGHT -8, buf); - lcd_update(); + rb->snprintf(buf, sizeof buf, "collisions: %d", collision_count); + rb->lcd_putsxy(0, LCD_HEIGHT -8, buf); + rb->lcd_update(); } if (collision_count != ARGH_SIZE * 2) { - button_get(true); + rb->button_get(true); } arghy[0] = 12; @@ -1535,12 +1518,12 @@ static void test_worm_argh_collision(void) { if (collision) { collision_count ++; } - snprintf(buf, sizeof buf, "collisions: %d", collision_count); - lcd_putsxy(0, LCD_HEIGHT -8, buf); - lcd_update(); + rb->snprintf(buf, sizeof buf, "collisions: %d", collision_count); + rb->lcd_putsxy(0, LCD_HEIGHT -8, buf); + rb->lcd_update(); } if (collision_count != ARGH_SIZE * 4) { - button_get(true); + rb->button_get(true); } } @@ -1560,11 +1543,11 @@ static int testline_in_rect(void) { if (!line_in_rect(x1, y1, x2, y2, rx, ry, rw, rh) && !line_in_rect(x2, y2, x1, y1, rx, ry, rw, rh)) { - lcd_drawrect(rx, ry, rw, rh); - lcd_drawline(x1, y1, x2, y2); - lcd_update(); - lcd_putsxy(0, 0, "failed 1"); - button_get(true); + rb->lcd_drawrect(rx, ry, rw, rh); + rb->lcd_drawline(x1, y1, x2, y2); + rb->lcd_update(); + rb->lcd_putsxy(0, 0, "failed 1"); + rb->button_get(true); testfailed = 1; } @@ -1572,11 +1555,11 @@ static int testline_in_rect(void) { y2 = 20; if (!line_in_rect(x1, y1, x2, y2, rx, ry, rw, rh) && !line_in_rect(x2, y2, x1, y1, rx, ry, rw, rh)) { - lcd_drawrect(rx, ry, rw, rh); - lcd_drawline(x1, y1, x2, y2); - lcd_putsxy(0, 0, "failed 2"); - lcd_update(); - button_get(true); + rb->lcd_drawrect(rx, ry, rw, rh); + rb->lcd_drawline(x1, y1, x2, y2); + rb->lcd_putsxy(0, 0, "failed 2"); + rb->lcd_update(); + rb->button_get(true); testfailed = 2; } @@ -1584,11 +1567,11 @@ static int testline_in_rect(void) { y1 = 30; if (!line_in_rect(x1, y1, x2, y2, rx, ry, rw, rh) && !line_in_rect(x2, y2, x1, y1, rx, ry, rw, rh)) { - lcd_drawrect(rx, ry, rw, rh); - lcd_drawline(x1, y1, x2, y2); - lcd_putsxy(0, 0, "failed 3"); - lcd_update(); - button_get(true); + rb->lcd_drawrect(rx, ry, rw, rh); + rb->lcd_drawline(x1, y1, x2, y2); + rb->lcd_putsxy(0, 0, "failed 3"); + rb->lcd_update(); + rb->button_get(true); testfailed = 3; } @@ -1596,11 +1579,11 @@ static int testline_in_rect(void) { y2 = 45; if (!line_in_rect(x1, y1, x2, y2, rx, ry, rw, rh) && !line_in_rect(x2, y2, x1, y1, rx, ry, rw, rh)) { - lcd_drawrect(rx, ry, rw, rh); - lcd_drawline(x1, y1, x2, y2); - lcd_putsxy(0, 0, "failed 4"); - lcd_update(); - button_get(true); + rb->lcd_drawrect(rx, ry, rw, rh); + rb->lcd_drawline(x1, y1, x2, y2); + rb->lcd_putsxy(0, 0, "failed 4"); + rb->lcd_update(); + rb->button_get(true); testfailed = 4; } @@ -1608,11 +1591,11 @@ static int testline_in_rect(void) { y1 = 50; if (line_in_rect(x1, y1, x2, y2, rx, ry, rw, rh) || line_in_rect(x2, y2, x1, y1, rx, ry, rw, rh)) { - lcd_drawrect(rx, ry, rw, rh); - lcd_drawline(x1, y1, x2, y2); - lcd_putsxy(0, 0, "failed 5"); - lcd_update(); - button_get(true); + rb->lcd_drawrect(rx, ry, rw, rh); + rb->lcd_drawline(x1, y1, x2, y2); + rb->lcd_putsxy(0, 0, "failed 5"); + rb->lcd_update(); + rb->button_get(true); testfailed = 5; } @@ -1621,11 +1604,11 @@ static int testline_in_rect(void) { y2 = 7; if (line_in_rect(x1, y1, x2, y2, rx, ry, rw, rh) || line_in_rect(x2, y2, x1, y1, rx, ry, rw, rh)) { - lcd_drawrect(rx, ry, rw, rh); - lcd_drawline(x1, y1, x2, y2); - lcd_putsxy(0, 0, "failed 6"); - lcd_update(); - button_get(true); + rb->lcd_drawrect(rx, ry, rw, rh); + rb->lcd_drawline(x1, y1, x2, y2); + rb->lcd_putsxy(0, 0, "failed 6"); + rb->lcd_update(); + rb->button_get(true); testfailed = 6; } @@ -1636,11 +1619,11 @@ static int testline_in_rect(void) { y2 = 20; if (!line_in_rect(x1, y1, x2, y2, rx, ry, rw, rh) && !line_in_rect(x2, y2, x1, y1, rx, ry, rw, rh)) { - lcd_drawrect(rx, ry, rw, rh); - lcd_drawline(x1, y1, x2, y2); - lcd_putsxy(0, 0, "failed 7"); - lcd_update(); - button_get(true); + rb->lcd_drawrect(rx, ry, rw, rh); + rb->lcd_drawline(x1, y1, x2, y2); + rb->lcd_putsxy(0, 0, "failed 7"); + rb->lcd_update(); + rb->button_get(true); testfailed = 7; } @@ -1648,11 +1631,11 @@ static int testline_in_rect(void) { x2 = 12; if (!line_in_rect(x1, y1, x2, y2, rx, ry, rw, rh) && !line_in_rect(x2, y2, x1, y1, rx, ry, rw, rh)) { - lcd_drawrect(rx, ry, rw, rh); - lcd_drawline(x1, y1, x2, y2); - lcd_putsxy(0, 0, "failed 8"); - lcd_update(); - button_get(true); + rb->lcd_drawrect(rx, ry, rw, rh); + rb->lcd_drawline(x1, y1, x2, y2); + rb->lcd_putsxy(0, 0, "failed 8"); + rb->lcd_update(); + rb->button_get(true); testfailed = 8; } @@ -1660,11 +1643,11 @@ static int testline_in_rect(void) { x1 = 25; if (!line_in_rect(x1, y1, x2, y2, rx, ry, rw, rh) && !line_in_rect(x2, y2, x1, y1, rx, ry, rw, rh)) { - lcd_drawrect(rx, ry, rw, rh); - lcd_drawline(x1, y1, x2, y2); - lcd_putsxy(0, 0, "failed 9"); - lcd_update(); - button_get(true); + rb->lcd_drawrect(rx, ry, rw, rh); + rb->lcd_drawline(x1, y1, x2, y2); + rb->lcd_putsxy(0, 0, "failed 9"); + rb->lcd_update(); + rb->button_get(true); testfailed = 9; } @@ -1672,11 +1655,11 @@ static int testline_in_rect(void) { x2 = 37; if (!line_in_rect(x1, y1, x2, y2, rx, ry, rw, rh) && !line_in_rect(x2, y2, x1, y1, rx, ry, rw, rh)) { - lcd_drawrect(rx, ry, rw, rh); - lcd_drawline(x1, y1, x2, y2); - lcd_putsxy(0, 0, "failed 10"); - lcd_update(); - button_get(true); + rb->lcd_drawrect(rx, ry, rw, rh); + rb->lcd_drawline(x1, y1, x2, y2); + rb->lcd_putsxy(0, 0, "failed 10"); + rb->lcd_update(); + rb->button_get(true); testfailed = 10; } @@ -1684,11 +1667,11 @@ static int testline_in_rect(void) { x1 = 42; if (line_in_rect(x1, y1, x2, y2, rx, ry, rw, rh) || line_in_rect(x2, y2, x1, y1, rx, ry, rw, rh)) { - lcd_drawrect(rx, ry, rw, rh); - lcd_drawline(x1, y1, x2, y2); - lcd_putsxy(0, 0, "failed 11"); - lcd_update(); - button_get(true); + rb->lcd_drawrect(rx, ry, rw, rh); + rb->lcd_drawline(x1, y1, x2, y2); + rb->lcd_putsxy(0, 0, "failed 11"); + rb->lcd_update(); + rb->button_get(true); testfailed = 11; } @@ -1697,11 +1680,11 @@ static int testline_in_rect(void) { x2 = 7; if (line_in_rect(x1, y1, x2, y2, rx, ry, rw, rh) || line_in_rect(x2, y2, x1, y1, rx, ry, rw, rh)) { - lcd_drawrect(rx, ry, rw, rh); - lcd_drawline(x1, y1, x2, y2); - lcd_putsxy(0, 0, "failed 12"); - lcd_update(); - button_get(true); + rb->lcd_drawrect(rx, ry, rw, rh); + rb->lcd_drawline(x1, y1, x2, y2); + rb->lcd_putsxy(0, 0, "failed 12"); + rb->lcd_update(); + rb->button_get(true); testfailed = 12; } @@ -1717,11 +1700,11 @@ static int testline_in_rect(void) { y2 = 20; if (!(line_in_rect(x1, y1, x2, y2, rx, ry, rw, rh) && line_in_rect(x2, y2, x1, y1, rx, ry, rw, rh))) { - lcd_drawrect(rx, ry, rw, rh); - lcd_drawline(x1, y1, x2, y2); - lcd_putsxy(0, 0, "failed 13"); - lcd_update(); - button_get(true); + rb->lcd_drawrect(rx, ry, rw, rh); + rb->lcd_drawline(x1, y1, x2, y2); + rb->lcd_putsxy(0, 0, "failed 13"); + rb->lcd_update(); + rb->button_get(true); testfailed = 13; } @@ -1737,15 +1720,15 @@ static int testline_in_rect(void) { y2 = 19; if (!(line_in_rect(x1, y1, x2, y2, rx, ry, rw, rh) && line_in_rect(x2, y2, x1, y1, rx, ry, rw, rh))) { - lcd_drawline(x1, y1, x2, y2); - lcd_invertrect(rx, ry, rw, rh); - lcd_putsxy(0, 0, "failed 14"); - lcd_update(); - button_get(true); + rb->lcd_drawline(x1, y1, x2, y2); + rb->lcd_invertrect(rx, ry, rw, rh); + rb->lcd_putsxy(0, 0, "failed 14"); + rb->lcd_update(); + rb->button_get(true); testfailed = 14; } - lcd_clear_display(); + rb->lcd_clear_display(); return testfailed; } @@ -1759,7 +1742,7 @@ static int test_specific_worm_collision(void) { int x = 0; int y = 0; char buf[20]; - lcd_clear_display(); + rb->lcd_clear_display(); init_worm(&worms[0], 10, 20); add_growing(&worms[0], 20 - INITIAL_WORM_LENGTH); @@ -1779,14 +1762,14 @@ static int test_specific_worm_collision(void) { if (specific_worm_collision(&worms[0], x, y) != -1) { collisions ++; } - lcd_invertpixel(x + FIELD_RECT_X, y + FIELD_RECT_Y); - snprintf(buf, sizeof buf, "collisions %d", collisions); - lcd_putsxy(0, LCD_HEIGHT - 8, buf); - lcd_update(); + rb->lcd_invertpixel(x + FIELD_RECT_X, y + FIELD_RECT_Y); + rb->snprintf(buf, sizeof buf, "collisions %d", collisions); + rb->lcd_putsxy(0, LCD_HEIGHT - 8, buf); + rb->lcd_update(); } } if (collisions != 21) { - button_get(true); + rb->button_get(true); } return collisions; } @@ -1798,7 +1781,7 @@ static void test_make_argh(void){ int failures = 0; int last_failures = 0; int i, worm_idx; - lcd_clear_display(); + rb->lcd_clear_display(); worm_count = 3; for (worm_idx = 0; worm_idx < worm_count; worm_idx++) { @@ -1818,37 +1801,37 @@ static void test_make_argh(void){ } } - lcd_update(); + rb->lcd_update(); for (seed = 0; hit < 20; seed += 2) { char buf[20]; int x, y; - srand(seed); - x = rand() % (FIELD_RECT_WIDTH - ARGH_SIZE); - y = rand() % (FIELD_RECT_HEIGHT - ARGH_SIZE); + rb->srand(seed); + x = rb->rand() % (FIELD_RECT_WIDTH - ARGH_SIZE); + y = rb->rand() % (FIELD_RECT_HEIGHT - ARGH_SIZE); for (worm_idx = 0; worm_idx < worm_count; worm_idx++){ if (expensive_worm_in_rect(&worms[worm_idx], x, y, ARGH_SIZE, ARGH_SIZE)) { int tries = 0; - srand(seed); + rb->srand(seed); tries = make_argh(0); if ((x == arghx[0] && y == arghy[0]) || tries < 2) { failures ++; } - snprintf(buf, sizeof buf, "(%d;%d) fail%d try%d", x, y, failures, tries); - lcd_putsxy(0, LCD_HEIGHT - 8, buf); - lcd_update(); - lcd_invertrect(x + FIELD_RECT_X, y+ FIELD_RECT_Y, ARGH_SIZE, ARGH_SIZE); - lcd_update(); + rb->snprintf(buf, sizeof buf, "(%d;%d) fail%d try%d", x, y, failures, tries); + rb->lcd_putsxy(0, LCD_HEIGHT - 8, buf); + rb->lcd_update(); + rb->lcd_invertrect(x + FIELD_RECT_X, y+ FIELD_RECT_Y, ARGH_SIZE, ARGH_SIZE); + rb->lcd_update(); draw_argh(0); - lcd_update(); - lcd_invertrect(x + FIELD_RECT_X, y + FIELD_RECT_Y, ARGH_SIZE, ARGH_SIZE); - lcd_clearrect(arghx[0] + FIELD_RECT_X, arghy[0] + FIELD_RECT_Y, ARGH_SIZE, ARGH_SIZE); + rb->lcd_update(); + rb->lcd_invertrect(x + FIELD_RECT_X, y + FIELD_RECT_Y, ARGH_SIZE, ARGH_SIZE); + rb->lcd_clearrect(arghx[0] + FIELD_RECT_X, arghy[0] + FIELD_RECT_Y, ARGH_SIZE, ARGH_SIZE); if (failures > last_failures) { - button_get(true); + rb->button_get(true); } last_failures = failures; hit ++; @@ -1860,7 +1843,7 @@ static void test_make_argh(void){ static void test_worm_argh_collision_in_moves(void) { int hit_count = 0; int i; - lcd_clear_display(); + rb->lcd_clear_display(); init_worm(&worms[0], 10, 20); arghx[0] = 20; @@ -1875,12 +1858,12 @@ static void test_worm_argh_collision_in_moves(void) { if (worm_argh_collision_in_moves(&worms[0], 0, 5)){ hit_count ++; } - snprintf(buf, sizeof buf, "in 5 moves hits: %d", hit_count); - lcd_putsxy(0, LCD_HEIGHT - 8, buf); - lcd_update(); + rb->snprintf(buf, sizeof buf, "in 5 moves hits: %d", hit_count); + rb->lcd_putsxy(0, LCD_HEIGHT - 8, buf); + rb->lcd_update(); } if (hit_count != ARGH_SIZE + 5) { - button_get(true); + rb->button_get(true); } } #endif /* DEBUG_WORMLET */ @@ -1888,14 +1871,18 @@ static void test_worm_argh_collision_in_moves(void) { extern bool use_old_rect; /** - * Main entry point from the menu to start the game control. + * Main entry point */ -bool wormlet(void) +enum plugin_status plugin_start(struct plugin_api* api, void* parameter) { bool worm_dead = false; int button; - lcd_setfont(FONT_SYSFIXED); + TEST_PLUGIN_API(api); + (void)(parameter); + + rb = api; + rb->lcd_setfont(FONT_SYSFIXED); #ifdef DEBUG_WORMLET testline_in_rect(); @@ -1905,44 +1892,44 @@ bool wormlet(void) test_worm_argh_collision(); test_specific_worm_collision(); #endif - lcd_setmargins(0,0); /* Setup screen */ do { char buf[20]; - lcd_clear_display(); + char* ptr; + rb->lcd_clear_display(); /* first line players */ - snprintf(buf, sizeof buf, str(LANG_WORMLET_PLAYERS), players); - lcd_puts(0, 0, buf); + rb->snprintf(buf, sizeof buf, "%d Players UP/DN", players); + rb->lcd_puts(0, 0, buf); /* second line worms */ - snprintf(buf, sizeof buf, str(LANG_WORMLET_WORMS), worm_count); - lcd_puts(0, 1, buf); + rb->snprintf(buf, sizeof buf, "%d Worms L/R", worm_count); + rb->lcd_puts(0, 1, buf); /* third line control */ if (players > 1) { if (use_remote) { - snprintf(buf, sizeof buf, str(LANG_WORMLET_REMOTE_CTRL)); + ptr = "Remote Control F1"; } else { - snprintf(buf, sizeof buf, str(LANG_WORMLET_NO_REM_CTRL)); + ptr = "No Rem. Control F1"; } } else { if (players > 0) { if (use_remote) { - snprintf(buf, sizeof buf, str(LANG_WORMLET_2_KEY_CTRL)); + ptr = "2 Key Control F1"; } else { - snprintf(buf, sizeof buf, str(LANG_WORMLET_4_KEY_CTRL)); + ptr = "4 Key Control F1"; } } else { - snprintf(buf, sizeof buf, str(LANG_WORMLET_NO_CONTROL)); + ptr = "Out Of Control"; } } - lcd_puts(0, 2, buf); - lcd_update(); + rb->lcd_puts(0, 2, ptr); + rb->lcd_update(); /* user selection */ - button = button_get(true); + button = rb->button_get(true); switch (button) { case BUTTON_UP: if (players < 3) { @@ -1981,14 +1968,13 @@ bool wormlet(void) break; case SYS_USB_CONNECTED: - usb_screen(); - lcd_setfont(FONT_UI); - return true; + rb->usb_screen(); + return PLUGIN_USB_CONNECTED; } } while (button != BUTTON_PLAY && button != BUTTON_OFF && button != BUTTON_ON); - lcd_clear_display(); + rb->lcd_clear_display(); /* end of setup */ do { @@ -2008,7 +1994,7 @@ bool wormlet(void) via BUTTON_OFF -> no need to wait for buttons. */ if (worm_dead) { do { - button = button_get(true); + button = rb->button_get(true); } /* BUTTON_ON -> start new game */ /* BUTTON_OFF -> back to game menu */ @@ -2017,20 +2003,7 @@ bool wormlet(void) } while (button != BUTTON_OFF); - lcd_setfont(FONT_UI); - - return false; + return PLUGIN_OK; } - -#endif /* USE_GAMES */ - - - - - - - - - - +#endif diff --git a/apps/recorder/icons.c b/apps/recorder/icons.c index af0352094f..25d34d7591 100644 --- a/apps/recorder/icons.c +++ b/apps/recorder/icons.c @@ -64,6 +64,7 @@ unsigned char bitmap_icons_6x8[LastIcon][6] = { 0x3e, 0x2a, 0x3e, 0x2a, 0x2a, 0x3e }, /* Language file */ { 0x55, 0x55, 0x55, 0x55, 0x55, 0x55 }, /* Text file */ { 0x4e, 0x51, 0x51, 0x40, 0x55, 0x55 }, /* Config file */ + { 0x0a, 0x0a, 0x5f, 0x4e, 0x24, 0x18 }, /* Plugin file */ }; unsigned char bitmap_icons_7x8[][7] = diff --git a/apps/recorder/icons.h b/apps/recorder/icons.h index a7858cd0ae..40418468f3 100644 --- a/apps/recorder/icons.h +++ b/apps/recorder/icons.h @@ -29,6 +29,7 @@ enum icons_6x8 { Folder, Directory, Playlist, Repeat, Selected, Cursor, Wps, Mod_Ajz, Font, Language, Text, Config, + Plugin, LastIcon }; diff --git a/apps/recorder/sokoban.c b/apps/recorder/sokoban.c deleted file mode 100644 index d28e32f430..0000000000 --- a/apps/recorder/sokoban.c +++ /dev/null @@ -1,891 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Copyright (C) 2002 Eric Linenberg - * February 2003: Robert Hak performs a cleanup/rewrite/feature addition. - * Eric smiles. Bjorn cries. Linus say 'huh?'. - * - * All files in this archive are subject to the GNU General Public License. - * See the file COPYING in the source tree root for full license agreement. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ - -#include "config.h" -#include "options.h" - -#ifdef USE_GAMES - -#include <sprintf.h> -#include "ctype.h" -#include "sokoban.h" -#include "lcd.h" -#include "button.h" -#include "kernel.h" -#include "menu.h" -#include "screens.h" -#include "font.h" -#include "file.h" -#include "misc.h" -#include "debug.h" - -#ifdef SIMULATOR -#include <stdio.h> -#endif -#include <string.h> -#include "lang.h" -#include "sprintf.h" - -#define SOKOBAN_TITLE "Sokoban" -#define SOKOBAN_TITLE_FONT 2 - -#define LEVELS_FILE "/.rockbox/sokoban/levels.txt" - -#define ROWS 16 -#define COLS 20 -#define MAX_UNDOS 5 - -#define SOKOBAN_LEVEL_SIZE (ROWS*COLS) - -static void init_undo(void); -static void undo(void); -static void add_undo(int button); - -static int get_level(char *level, int level_size); -static int get_level_count(void); -static int load_level(void); -static void draw_level(void); - -static void init_boards(void); -static void update_screen(void); -static bool sokoban_loop(void); - -/* The Location, Undo and LevelInfo structs are OO-flavored. - * (oooh!-flavored as Schnueff puts it.) It makes more you have to know, - * but the overall data layout becomes more manageable. */ - -/* We use the same three values in 2 structs. Makeing them a struct - * hopefully ensures that if you change things in one, the other changes - * as well. */ -struct LevelInfo { - short level; - short moves; - short boxes_to_go; -}; - -/* What a given location on the board looks like at a given time */ -struct Location { - char spot; - short row; - short col; -}; - -/* A single level of undo. Each undo move can affect upto, - * but not more then, 3 spots on the board */ -struct Undo { - struct LevelInfo level; - struct Location location[3]; -}; - -/* Our full undo history */ -static struct UndoInfo { - short count; /* How many undos are there in history */ - short current; /* Which history is the current undo */ - struct Undo history[MAX_UNDOS]; -} undo_info; - -/* Our playing board */ -static struct BoardInfo { - char board[ROWS][COLS]; - struct LevelInfo level; - struct Location player; - int max_level; /* How many levels do we have? */ - int level_offset; /* Where in the level file is this level */ - int loaded_level; /* Which level is in memory */ -} current_info; - - -static void init_undo(void) -{ - undo_info.count = 0; - undo_info.current = 0; -} - -static void undo(void) -{ - struct Undo *undo; - int i = 0; - short row, col; - - if (undo_info.count == 0) - return; - - /* Update board info */ - undo = &undo_info.history[undo_info.current]; - - current_info.level = undo->level; - current_info.player = undo->location[0]; - - row = undo->location[0].row; - col = undo->location[0].col; - current_info.board[row][col] = '@'; - - /* Update the two other possible spots */ - for (i = 1; i < 3; i++) { - if (undo->location[i].spot != '\0') { - row = undo->location[i].row; - col = undo->location[i].col; - current_info.board[row][col] = undo->location[i].spot; - undo->location[i].spot = '\0'; - } - } - - /* Remove this undo from the list */ - if (undo_info.current == 0) { - if (undo_info.count > 1) - undo_info.current = MAX_UNDOS - 1; - } else { - undo_info.current--; - } - - undo_info.count--; - - return; -} - -static void add_undo(int button) -{ - struct Undo *undo; - int row, col, i; - bool storable; - - if ((button != BUTTON_LEFT) && (button != BUTTON_RIGHT) && - (button != BUTTON_UP) && (button != BUTTON_DOWN)) - return; - - if (undo_info.count != 0) { - if (undo_info.current < (MAX_UNDOS - 1)) - undo_info.current++; - else - undo_info.current = 0; - } - - /* Make what follows more readable */ - undo = &undo_info.history[undo_info.current]; - - /* Store our level info */ - undo->level = current_info.level; - - /* Store our player info */ - undo->location[0] = current_info.player; - - /* Now we need to store upto 2 blocks that may be affected. - * If player.spot is NULL, then there is no info stored - * for that block */ - - row = current_info.player.row; - col = current_info.player.col; - - /* This must stay as _1_ because the first block (0) is the player */ - for (i = 1; i < 3; i++) { - storable = true; - - switch (button) { - case BUTTON_LEFT: - col--; - if (col < 0) - storable = false; - break; - - case BUTTON_RIGHT: - col++; - if (col >= COLS) - storable = false; - break; - - case BUTTON_UP: - row--; - if (row < 0) - storable = false; - break; - - case BUTTON_DOWN: - row++; - if (row >= ROWS) - storable = false; - break; - - default: - return; - } - - if (storable) { - undo->location[i].col = col; - undo->location[i].row = row; - undo->location[i].spot = current_info.board[row][col]; - } else { - undo->location[i].spot = '\0'; - } - } - - if (undo_info.count < MAX_UNDOS) - undo_info.count++; -} - -static void init_boards(void) -{ - current_info.level.level = 0; - current_info.level.moves = 0; - current_info.level.boxes_to_go = 0; - current_info.player.row = 0; - current_info.player.col = 0; - current_info.player.spot = ' '; - current_info.max_level = 0; - current_info.level_offset = 0; - current_info.loaded_level = 0; - - init_undo(); -} - -static int get_level_count(void) -{ - int fd = 0; - int len, lastlen = 0; - char buffer[COLS + 3]; /* COLS plus CR/LF and \0 */ - - if ((fd = open(LEVELS_FILE, O_RDONLY)) < 0) { - splash(0, 0, true, "Unable to open %s", LEVELS_FILE); - return -1; - } - - while(1) { - len = read_line(fd, buffer, sizeof(buffer)); - if(len <= 0) - break; - - /* Two short lines in a row means new level */ - if(len < 3 && lastlen < 3) - current_info.max_level++; - - lastlen = len; - } - - DEBUGF("%d levels loaded\n", current_info.max_level); - close(fd); - return 0; -} - -static int get_level(char *level, int level_size) -{ - int fd = 0, i = 0; - int nread = 0; - int count = 0; - int len, lastlen = 0; - int level_ct = 1; - unsigned char buffer[SOKOBAN_LEVEL_SIZE * 2]; - bool level_found = false; - - /* open file */ - if ((fd = open(LEVELS_FILE, O_RDONLY)) < 0) - return -1; - - /* Lets not reparse the full file if we can avoid it */ - if (current_info.loaded_level < current_info.level.level) { - lseek(fd, current_info.level_offset, SEEK_SET); - level_ct = current_info.loaded_level; - } - - if(current_info.level.level > 1) { - while(!level_found) { - len = read_line(fd, buffer, SOKOBAN_LEVEL_SIZE); - if(len <= 0) { - close(fd); - return -1; - } - - /* Two short lines in a row means new level */ - if(len < 3 && lastlen < 3) { - level_ct++; - if(level_ct == current_info.level.level) - level_found = true; - } - lastlen = len; - } - } - - /* Remember the current offset */ - current_info.level_offset = lseek(fd, 0, SEEK_CUR); - - /* read a full buffer chunk from here */ - nread = read(fd, buffer, sizeof(buffer)-1); - if (nread < 0) - return -1; - buffer[nread] = 0; - - close(fd); - - /* If we read less then a level, error */ - if (nread < level_size) - return -1; - - /* Load our new level */ - for(i=0, count=0; (count < nread) && (i<level_size);) { - if (buffer[count] != '\n' && buffer[count] != '\r') - level[i++] = buffer[count]; - count++; - } - level[i] = 0; - - current_info.loaded_level = current_info.level.level; - return 0; -} - -/* return non-zero on error */ -static int load_level(void) -{ - short c = 0; - short r = 0; - short i = 0; - char level[ROWS*COLS+1]; - int x = 0; - - current_info.player.spot=' '; - current_info.level.boxes_to_go = 0; - current_info.level.moves = 0; - - if (get_level(level, sizeof(level)) != 0) - return -1; - - i = 0; - for (r = 0; r < ROWS; r++) { - x++; - for (c = 0; c < COLS; c++, i++) { - current_info.board[r][c] = level[i]; - - if (current_info.board[r][c] == '.') - current_info.level.boxes_to_go++; - - else if (current_info.board[r][c] == '@') { - current_info.player.row = r; - current_info.player.col = c; - } - } - } - - return 0; -} - -static void update_screen(void) -{ - short b = 0, c = 0; - short rows = 0, cols = 0; - char s[25]; - - short magnify = 4; - - /* load the board to the screen */ - for (rows=0 ; rows < ROWS ; rows++) { - for (cols = 0 ; cols < COLS ; cols++) { - c = cols * magnify; - b = rows * magnify; - - switch(current_info.board[rows][cols]) { - case 'X': /* black space */ - lcd_drawrect(c, b, magnify, magnify); - lcd_drawrect(c+1, b+1, 2, 2); - break; - - case '#': /* this is a wall */ - lcd_drawpixel(c, b); - lcd_drawpixel(c+2, b); - lcd_drawpixel(c+1, b+1); - lcd_drawpixel(c+3, b+1); - lcd_drawpixel(c, b+2); - lcd_drawpixel(c+2, b+2); - lcd_drawpixel(c+1, b+3); - lcd_drawpixel(c+3, b+3); - break; - - case '.': /* this is a home location */ - lcd_drawrect(c+1, b+1, 2, 2); - break; - - case '$': /* this is a box */ - lcd_drawrect(c, b, magnify, magnify); - break; - - case '@': /* this is you */ - lcd_drawline(c+1, b, c+2, b); - lcd_drawline(c, b+1, c+3, b+1); - lcd_drawline(c+1, b+2, c+2, b+2); - - lcd_drawpixel(c, b+3); - lcd_drawpixel(c+3, b+3); - break; - - case '%': /* this is a box on a home spot */ - lcd_drawrect(c, b, magnify, magnify); - lcd_drawrect(c+1, b+1, 2, 2); - break; - } - } - } - - - snprintf(s, sizeof(s), "%d", current_info.level.level); - lcd_putsxy(86, 22, s); - snprintf(s, sizeof(s), "%d", current_info.level.moves); - lcd_putsxy(86, 54, s); - - lcd_drawrect(80,0,32,32); - lcd_drawrect(80,32,32,64); - lcd_putsxy(81, 10, str(LANG_SOKOBAN_LEVEL)); - lcd_putsxy(81, 42, str(LANG_SOKOBAN_MOVE)); - - /* print out the screen */ - lcd_update(); -} - -static void draw_level(void) -{ - load_level(); - lcd_clear_display(); - update_screen(); -} - -static bool sokoban_loop(void) -{ - char new_spot; - bool moved = true; - int i = 0, button = 0; - short r = 0, c = 0; - - current_info.level.level = 1; - - load_level(); - update_screen(); - - while (1) { - moved = true; - - r = current_info.player.row; - c = current_info.player.col; - - button = button_get(true); - - add_undo(button); - - switch(button) - { - case BUTTON_OFF: - /* get out of here */ - return false; - - case BUTTON_ON: - case BUTTON_ON | BUTTON_REPEAT: - /* this is UNDO */ - undo(); - lcd_clear_display(); - update_screen(); - moved = false; - break; - - case BUTTON_F3: - case BUTTON_F3 | BUTTON_REPEAT: - /* increase level */ - init_undo(); - current_info.level.boxes_to_go=0; - moved = true; - break; - - case BUTTON_F1: - case BUTTON_F1 | BUTTON_REPEAT: - /* previous level */ - init_undo(); - if (current_info.level.level > 1) - current_info.level.level--; - - draw_level(); - moved = false; - break; - - case BUTTON_F2: - case BUTTON_F2 | BUTTON_REPEAT: - /* same level */ - init_undo(); - draw_level(); - moved = false; - break; - - case BUTTON_LEFT: - switch(current_info.board[r][c-1]) - { - case ' ': /* if it is a blank spot */ - case '.': /* if it is a home spot */ - new_spot = current_info.board[r][c-1]; - current_info.board[r][c-1] = '@'; - current_info.board[r][c] = current_info.player.spot; - current_info.player.spot = new_spot; - break; - - case '$': - switch(current_info.board[r][c-2]) - { - case ' ': /* going from blank to blank */ - current_info.board[r][c-2] = current_info.board[r][c-1]; - current_info.board[r][c-1] = current_info.board[r][c]; - current_info.board[r][c] = current_info.player.spot; - current_info.player.spot = ' '; - break; - - case '.': /* going from a blank to home */ - current_info.board[r][c-2] = '%'; - current_info.board[r][c-1] = current_info.board[r][c]; - current_info.board[r][c] = current_info.player.spot; - current_info.player.spot = ' '; - current_info.level.boxes_to_go--; - break; - - default: - moved = false; - break; - } - break; - - case '%': - switch(current_info.board[r][c-2]) { - case ' ': /* we are going from a home to a blank */ - current_info.board[r][c-2] = '$'; - current_info.board[r][c-1] = current_info.board[r][c]; - current_info.board[r][c] = current_info.player.spot; - current_info.player.spot = '.'; - current_info.level.boxes_to_go++; - break; - - case '.': /* if we are going from a home to home */ - current_info.board[r][c-2] = '%'; - current_info.board[r][c-1] = current_info.board[r][c]; - current_info.board[r][c] = current_info.player.spot; - current_info.player.spot = '.'; - break; - - default: - moved = false; - break; - } - break; - - default: - moved = false; - break; - } - - if (moved) - current_info.player.col--; - break; - - case BUTTON_RIGHT: /* if it is a blank spot */ - switch(current_info.board[r][c+1]) { - case ' ': - case '.': /* if it is a home spot */ - new_spot = current_info.board[r][c+1]; - current_info.board[r][c+1] = '@'; - current_info.board[r][c] = current_info.player.spot; - current_info.player.spot = new_spot; - break; - - case '$': - switch(current_info.board[r][c+2]) { - case ' ': /* going from blank to blank */ - current_info.board[r][c+2] = current_info.board[r][c+1]; - current_info.board[r][c+1] = current_info.board[r][c]; - current_info.board[r][c] = current_info.player.spot; - current_info.player.spot = ' '; - break; - - case '.': /* going from a blank to home */ - current_info.board[r][c+2] = '%'; - current_info.board[r][c+1] = current_info.board[r][c]; - current_info.board[r][c] = current_info.player.spot; - current_info.player.spot = ' '; - current_info.level.boxes_to_go--; - break; - - default: - moved = false; - break; - } - break; - - case '%': - switch(current_info.board[r][c+2]) { - case ' ': /* going from a home to a blank */ - current_info.board[r][c+2] = '$'; - current_info.board[r][c+1] = current_info.board[r][c]; - current_info.board[r][c] = current_info.player.spot; - current_info.player.spot = '.'; - current_info.level.boxes_to_go++; - break; - - case '.': - current_info.board[r][c+2] = '%'; - current_info.board[r][c+1] = current_info.board[r][c]; - current_info.board[r][c] = current_info.player.spot; - current_info.player.spot = '.'; - break; - - default: - moved = false; - break; - } - break; - - default: - moved = false; - break; - } - - if (moved) - current_info.player.col++; - break; - - case BUTTON_UP: - switch(current_info.board[r-1][c]) { - case ' ': /* if it is a blank spot */ - case '.': /* if it is a home spot */ - new_spot = current_info.board[r-1][c]; - current_info.board[r-1][c] = '@'; - current_info.board[r][c] = current_info.player.spot; - current_info.player.spot = new_spot; - break; - - case '$': - switch(current_info.board[r-2][c]) { - case ' ': /* going from blank to blank */ - current_info.board[r-2][c] = current_info.board[r-1][c]; - current_info.board[r-1][c] = current_info.board[r][c]; - current_info.board[r][c] = current_info.player.spot; - current_info.player.spot = ' '; - break; - - case '.': /* going from a blank to home */ - current_info.board[r-2][c] = '%'; - current_info.board[r-1][c] = current_info.board[r][c]; - current_info.board[r][c] = current_info.player.spot; - current_info.player.spot = ' '; - current_info.level.boxes_to_go--; - break; - - default: - moved = false; - break; - } - break; - - case '%': - switch(current_info.board[r-2][c]) { - case ' ': /* we are going from a home to a blank */ - current_info.board[r-2][c] = '$'; - current_info.board[r-1][c] = current_info.board[r][c]; - current_info.board[r][c] = current_info.player.spot; - current_info.player.spot = '.'; - current_info.level.boxes_to_go++; - break; - - case '.': /* if we are going from a home to home */ - current_info.board[r-2][c] = '%'; - current_info.board[r-1][c] = current_info.board[r][c]; - current_info.board[r][c] = current_info.player.spot; - current_info.player.spot = '.'; - break; - - default: - moved = false; - break; - } - break; - - default: - moved = false; - break; - } - - if (moved) - current_info.player.row--; - break; - - case BUTTON_DOWN: - switch(current_info.board[r+1][c]) { - case ' ': /* if it is a blank spot */ - case '.': /* if it is a home spot */ - new_spot = current_info.board[r+1][c]; - current_info.board[r+1][c] = '@'; - current_info.board[r][c] = current_info.player.spot; - current_info.player.spot = new_spot; - break; - - case '$': - switch(current_info.board[r+2][c]) { - case ' ': /* going from blank to blank */ - current_info.board[r+2][c] = current_info.board[r+1][c]; - current_info.board[r+1][c] = current_info.board[r][c]; - current_info.board[r][c] = current_info.player.spot; - current_info.player.spot = ' '; - break; - - case '.': /* going from a blank to home */ - current_info.board[r+2][c] = '%'; - current_info.board[r+1][c] = current_info.board[r][c]; - current_info.board[r][c] = current_info.player.spot; - current_info.player.spot = ' '; - current_info.level.boxes_to_go--; - break; - - default: - moved = false; - break; - } - break; - - case '%': - switch(current_info.board[r+2][c]) { - case ' ': /* going from a home to a blank */ - current_info.board[r+2][c] = '$'; - current_info.board[r+1][c] = current_info.board[r][c]; - current_info.board[r][c] = current_info.player.spot; - current_info.player.spot = '.'; - current_info.level.boxes_to_go++; - break; - - case '.': /* going from a home to home */ - current_info.board[r+2][c] = '%'; - current_info.board[r+1][c] = current_info.board[r][c]; - current_info.board[r][c] = current_info.player.spot; - current_info.player.spot = '.'; - break; - - default: - moved = false; - break; - } - break; - - default: - moved = false; - break; - } - - if (moved) - current_info.player.row++; - break; - - case SYS_USB_CONNECTED: - usb_screen(); - return true; - - default: - moved = false; - break; - } - - if (moved) { - current_info.level.moves++; - lcd_clear_display(); - update_screen(); - } - - /* We have completed this level */ - if (current_info.level.boxes_to_go == 0) { - current_info.level.level++; - - /* clear undo stats */ - init_undo(); - - lcd_clear_display(); - - if (current_info.level.level > current_info.max_level) { - lcd_putsxy(10, 20, str(LANG_SOKOBAN_WIN)); - - for (i = 0; i < 30000 ; i++) { - lcd_invertrect(0, 0, 111, 63); - lcd_update(); - - button = button_get(false); - if (button && ((button & BUTTON_REL) != BUTTON_REL)) - break; - } - - return false; - } - - load_level(); - update_screen(); - } - - } /* end while */ - - return false; -} - - -bool sokoban(void) -{ - bool result; - int w, h; - int len; - - lcd_setfont(FONT_SYSFIXED); - - lcd_getstringsize(SOKOBAN_TITLE, &w, &h); - - /* Get horizontel centering for text */ - len = w; - if (len%2 != 0) - len =((len+1)/2)+(w/2); - else - len /= 2; - - if (h%2 != 0) - h = (h/2)+1; - else - h /= 2; - - lcd_clear_display(); - lcd_putsxy(LCD_WIDTH/2-len,(LCD_HEIGHT/2)-h, SOKOBAN_TITLE); - - lcd_update(); - sleep(HZ*2); - - lcd_clear_display(); - - lcd_putsxy(3, 6, str(LANG_SOKOBAN_QUIT)); - lcd_putsxy(3, 16, str(LANG_SOKOBAN_ON)); - lcd_putsxy(3, 26, str(LANG_SOKOBAN_F1)); - lcd_putsxy(3, 36, str(LANG_SOKOBAN_F2)); - lcd_putsxy(3, 46, str(LANG_SOKOBAN_F3)); - - lcd_update(); - sleep(HZ*2); - lcd_clear_display(); - - init_boards(); - - if (get_level_count() != 0) - return false; - - result = sokoban_loop(); - - lcd_setfont(FONT_UI); - - return result; -} - -#endif diff --git a/apps/recorder/sokoban.h b/apps/recorder/sokoban.h deleted file mode 100644 index f4f8fdd24f..0000000000 --- a/apps/recorder/sokoban.h +++ /dev/null @@ -1,28 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Copyright (C) 2002 Robert E. Hak - * - * All files in this archive are subject to the GNU General Public License. - * See the file COPYING in the source tree root for full license agreement. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ - -#ifndef __SOKOBAN__ -#define __SOKOBAN__ - -#include "menu.h" - -bool sokoban(void); - -#endif /*__SOKOBAN__ */ - diff --git a/apps/recorder/tetris.c b/apps/recorder/tetris.c deleted file mode 100644 index 6302e40109..0000000000 --- a/apps/recorder/tetris.c +++ /dev/null @@ -1,438 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Copyright (C) 1999 Mattis Wadman (nappe@sudac.org) - * - * Heavily modified for embedded use by Björn Stenberg (bjorn@haxx.se) - * - * All files in this archive are subject to the GNU General Public License. - * See the file COPYING in the source tree root for full license agreement. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ - -#include "config.h" -#include "options.h" - -#ifdef USE_GAMES - -#include <stdbool.h> -#include <string.h> -#include "lcd.h" -#include "button.h" -#include "kernel.h" -#include "menu.h" -#include "screens.h" -#include "font.h" - -#ifdef SIMULATOR -#include <stdio.h> -#endif -#include "sprintf.h" -#include "lang.h" -#define TETRIS_TITLE "Tetris!" -#define TETRIS_TITLE_FONT 1 -#define TETRIS_TITLE_XLOC 43 -#define TETRIS_TITLE_YLOC 15 - -static const int start_x = 5; -static const int start_y = 5; -static const int max_x = 4 * 17; -static const int max_y = 3 * 10; -static const short level_speeds[10] = { - 1000, 900, 800, 700, 600, 500, 400, 300, 250, 200 -}; -static const int blocks = 7; -static const int block_frames[7] = {1,2,2,2,4,4,4}; - -static int current_x, current_y, current_f, current_b; -static int level, score; -static int next_b, next_f; -static short lines; -static char virtual[LCD_WIDTH * LCD_HEIGHT]; - -/* - block_data is built up the following way - - first array index specifies the block number - second array index specifies the rotation of the block - third array index specifies: - 0: x-coordinates of pixels - 1: y-coordinates of pixels - fourth array index specifies the coordinate of a pixel - - each block consists of four pixels whose relative coordinates are given - with block_data -*/ - -static const char block_data[7][4][2][4] = -{ - { - {{0,1,0,1},{0,0,1,1}} - }, - { - {{0,1,1,2},{1,1,0,0}}, - {{0,0,1,1},{0,1,1,2}} - }, - { - {{0,1,1,2},{0,0,1,1}}, - {{1,1,0,0},{0,1,1,2}} - }, - { - {{1,1,1,1},{0,1,2,3}}, - {{0,1,2,3},{2,2,2,2}} - }, - { - {{1,1,1,2},{2,1,0,0}}, - {{0,1,2,2},{1,1,1,2}}, - {{0,1,1,1},{2,2,1,0}}, - {{0,0,1,2},{0,1,1,1}} - }, - { - {{0,1,1,1},{0,0,1,2}}, - {{0,1,2,2},{1,1,1,0}}, - {{1,1,1,2},{0,1,2,2}}, - {{0,0,1,2},{2,1,1,1}} - }, - { - {{1,0,1,2},{0,1,1,1}}, - {{2,1,1,1},{1,0,1,2}}, - {{1,0,1,2},{2,1,1,1}}, - {{0,1,1,1},{1,0,1,2}} - } -}; - -static int t_rand(int range) -{ - return current_tick % range; -} - -static void draw_frame(int fstart_x,int fstop_x,int fstart_y,int fstop_y) -{ - lcd_drawline(fstart_x, fstart_y, fstop_x, fstart_y); - lcd_drawline(fstart_x, fstop_y, fstop_x, fstop_y); - - lcd_drawline(fstart_x, fstart_y, fstart_x, fstop_y); - lcd_drawline(fstop_x, fstart_y, fstop_x, fstop_y); - - lcd_drawline(fstart_x - 1, fstart_y + 1, fstart_x - 1, fstop_y + 1); - lcd_drawline(fstart_x - 1, fstop_y + 1, fstop_x - 1, fstop_y + 1); -} - -static void draw_block(int x, int y, int block, int frame, bool clear) -{ - int i, a, b; - for(i=0;i < 4;i++) { - if (clear) - { - for (a = 0; a < 3; a++) - for (b = 0; b < 4; b++) - lcd_clearpixel(start_x + x + block_data[block][frame][1][i] * 4 - b, - start_y + y + block_data[block][frame][0][i] * 3 + a); - } - else - { - for (a = 0; a < 3; a++) - for (b = 0; b < 4; b++) - lcd_drawpixel(start_x+x+block_data[block][frame][1][i] * 4 - b, - start_y+y+block_data[block][frame][0][i] * 3 + a); - } - } -} - -static void to_virtual(void) -{ - int i, a, b; - - for(i = 0; i < 4; i++) - for (a = 0; a < 3; a++) - for (b = 0; b < 4; b++) - *(virtual + - (current_y + block_data[current_b][current_f][0][i] * 3 + a) * - max_x + current_x + block_data[current_b][current_f][1][i] * - 4 - b) = current_b + 1; -} - -static bool block_touch (int x, int y) -{ - int a,b; - for (a = 0; a < 4; a++) - for (b = 0; b < 3; b++) - if (*(virtual + (y + b) * max_x + (x - a)) != 0) - return true; - return false; -} - -static bool gameover(void) -{ - int i; - int frame, block, y, x; - - x = current_x; - y = current_y; - block = current_b; - frame = current_f; - - for(i = 0; i < 4; i++){ - /* Do we have blocks touching? */ - if(block_touch(x + block_data[block][frame][1][i] * 4, - y + block_data[block][frame][0][i] * 3)) - { - /* Are we at the top of the frame? */ - if(x + block_data[block][frame][1][i] * 4 >= max_x - 16) - { - /* Game over ;) */ - return true; - } - } - } - return false; -} - -static bool valid_position(int x, int y, int block, int frame) -{ - int i; - for(i=0;i < 4;i++) - if ((y + block_data[block][frame][0][i] * 3 > max_y - 3) || - (x + block_data[block][frame][1][i] * 4 > max_x - 4) || - (y + block_data[block][frame][0][i] * 3 < 0) || - (x + block_data[block][frame][1][i] * 4 < 4) || - block_touch (x + block_data[block][frame][1][i] * 4, - y + block_data[block][frame][0][i] * 3)) - { - return false; - } - return true; -} - -static void from_virtual(void) -{ - int x,y; - for(y = 0; y < max_y; y++) - for(x = 1; x < max_x - 1; x++) - if(*(virtual + (y * max_x) + x) != 0) - lcd_drawpixel(start_x + x, start_y + y); - else - lcd_clearpixel(start_x + x, start_y + y); -} - -static void move_block(int x,int y,int f) -{ - int last_frame = current_f; - if(f != 0) - { - current_f += f; - if(current_f > block_frames[current_b]-1) - current_f = 0; - if(current_f < 0) - current_f = block_frames[current_b]-1; - } - - if(valid_position(current_x + x, current_y + y, current_b, current_f)) - { - draw_block(current_x,current_y,current_b,last_frame,true); - current_x += x; - current_y += y; - draw_block(current_x,current_y,current_b,current_f,false); - lcd_update(); - } - else - current_f = last_frame; -} - -static void new_block(void) -{ - current_b = next_b; - current_f = next_f; - current_x = max_x - 16; - current_y = (int)12; - next_b = t_rand(blocks); - next_f = t_rand(block_frames[next_b]); - - lcd_drawline (max_x + 7, start_y - 1, max_x + 29, start_y - 1); - lcd_drawline (max_x + 29, start_y, max_x + 29, start_y + 14); - lcd_drawline (max_x + 29, start_y + 14, max_x + 7, start_y + 14); - lcd_drawline (max_x + 7, start_y + 14, max_x + 7, start_y - 1); - lcd_drawline (max_x + 6, start_y + 15, max_x + 6, start_y); - lcd_drawline (max_x + 6, start_y + 15, max_x + 28, start_y + 15); - - draw_block(max_x + 9, start_y - 4, current_b, current_f, true); - draw_block(max_x + 9, start_y - 4, next_b, next_f, false); - if(!valid_position(current_x, current_y, current_b, current_f)) - { - draw_block(current_x, current_y, current_b, current_f, false); - lcd_update(); - } - else - draw_block(current_x, current_y, current_b, current_f, false); -} - -static int check_lines(void) -{ - int x,y,i,j; - bool line; - int lines = 0; - for(x = 0; x < max_x; x++) - { - line = true; - for(y = 0; y < max_y; y++) - { - if(*(virtual + y * max_x + x) == 0) - { - line = false; - break; - } - } - - if(line) - { - lines++; - /* move rows down */ - for(i = x; i < max_x - 1; i++) - for (j = 0; j < max_y; j++) - *(virtual + j * max_x + i)=*(virtual + j * max_x + (i + 1)); - - x--; /* re-check this line */ - } - } - - return lines / 4; -} - -static void move_down(void) -{ - int l; - char s[25]; - - if(!valid_position(current_x - 4, current_y, current_b, current_f)) - { - to_virtual(); - l = check_lines(); - if(l) - { - lines += l; - level = (int)lines/10; - if(level > 9) - level = 9; - from_virtual(); - score += l*l; - } - - snprintf (s, sizeof(s), "%d %s %d", lines, - str(LANG_TETRIS_LEVEL), level); - lcd_putsxy (2, 42, s); - - new_block(); - move_block(0,0,0); - } - else - move_block(-4,0,0); -} - -static bool game_loop(void) -{ - while(1) - { - int count = 0; - while(count * 300 < level_speeds[level]) - { - switch(button_get_w_tmo(HZ/10)) - { - case BUTTON_OFF: - return false; - - case BUTTON_UP: - case BUTTON_UP | BUTTON_REPEAT: - move_block(0,-3,0); - break; - - case BUTTON_DOWN: - case BUTTON_DOWN | BUTTON_REPEAT: - move_block(0,3,0); - break; - - case BUTTON_RIGHT: - case BUTTON_RIGHT | BUTTON_REPEAT: - move_block(0,0,1); - break; - - case BUTTON_LEFT: - case BUTTON_LEFT | BUTTON_REPEAT: - move_down(); - break; - - case SYS_USB_CONNECTED: - usb_screen(); - return true; - } - - count++; - } - - if(gameover()) - { - lcd_clearrect(0, 52, LCD_WIDTH, LCD_HEIGHT - 52); - lcd_putsxy (2, 52, str(LANG_TETRIS_LOSE)); - lcd_update(); - sleep(HZ * 3); - return false; - } - - move_down(); - } - - return false; -} - -static void init_tetris(void) -{ - memset(&virtual, 0, sizeof(virtual)); - - current_x = 0; - current_y = 0; - current_f = 0; - current_b = 0; - level = 0; - lines = 0; - score = 0; - next_b = 0; - next_f = 0; -} - -bool tetris(void) -{ - char buf[20]; - bool val; - - /* Lets use the default font */ - lcd_setfont(FONT_SYSFIXED); - - init_tetris(); - - draw_frame(start_x, start_x + max_x - 1, start_y - 1, start_y + max_y); - snprintf(buf, sizeof(buf), "0 %s 0", str(LANG_TETRIS_LEVEL)); - lcd_putsxy (2, 42, buf); - lcd_update(); - - next_b = t_rand(blocks); - next_f = t_rand(block_frames[next_b]); - new_block(); - val = game_loop(); - - lcd_setfont(FONT_UI); - - return val; -} - -#endif - - - diff --git a/apps/recorder/wormlet.h b/apps/recorder/wormlet.h deleted file mode 100644 index 0aeea3cc77..0000000000 --- a/apps/recorder/wormlet.h +++ /dev/null @@ -1,28 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Copyright (C) 2002 Philipp Pertermann - * - * All files in this archive are subject to the GNU General Public License. - * See the file COPYING in the source tree root for full license agreement. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ - -#ifndef __WORMLET__ -#define __WORMLET__ - -#include "menu.h" - -bool wormlet(void); - -#endif /*__WORMLET__ */ - diff --git a/apps/screens.c b/apps/screens.c index d12a93a4d4..6055be3a2d 100644 --- a/apps/screens.c +++ b/apps/screens.c @@ -31,6 +31,7 @@ #include "status.h" #include "playlist.h" #include "sprintf.h" +#include "kernel.h" #ifdef HAVE_LCD_BITMAP #define BMPHEIGHT_usb_logo 32 diff --git a/apps/tree.c b/apps/tree.c index 9935d8263d..e61fdc50cb 100644 --- a/apps/tree.c +++ b/apps/tree.c @@ -46,12 +46,12 @@ #include "rolo.h" #include "icons.h" #include "lang.h" -#include "viewer.h" #include "language.h" #include "screens.h" #include "keyboard.h" #include "onplay.h" #include "buffer.h" +#include "plugin.h" #ifdef HAVE_LCD_BITMAP #include "widgets.h" @@ -318,6 +318,8 @@ static int showdir(char *path, int start) else if (!strcasecmp(&entry->d_name[len-4], ".mod")) #endif dptr->attr |= TREE_ATTR_MOD; + else if (!strcasecmp(&entry->d_name[len-5], ".rock")) + dptr->attr |= TREE_ATTR_ROCK; } /* filter out all non-playlist files */ @@ -468,6 +470,10 @@ static int showdir(char *path, int start) icon_type = Mod_Ajz; break; + case TREE_ATTR_ROCK: + icon_type = Plugin; + break; + #ifdef HAVE_LCD_BITMAP case TREE_ATTR_FONT: icon_type = Font; @@ -962,7 +968,7 @@ bool dirbrowse(char *root) break; case TREE_ATTR_TXT: - viewer_run(buf); + plugin_load("/.rockbox/rocks/viewer.rock",buf); restore = true; break; @@ -998,6 +1004,14 @@ bool dirbrowse(char *root) rolo_load(buf); break; #endif + + /* plugin file */ + case TREE_ATTR_ROCK: + if (plugin_load(buf,NULL) == PLUGIN_USB_CONNECTED) + reload_root = true; + else + restore = true; + break; } if ( play ) { @@ -1194,6 +1208,7 @@ bool dirbrowse(char *root) /* the sub-screen might've ruined the margins */ lcd_setmargins(MARGIN_X,MARGIN_Y); /* leave room for cursor and icon */ + lcd_setfont(FONT_UI); #endif numentries = showdir(currdir, dirstart); update_all = true; diff --git a/apps/tree.h b/apps/tree.h index eb0aa8b98a..aa8f2127f3 100644 --- a/apps/tree.h +++ b/apps/tree.h @@ -30,6 +30,7 @@ #define TREE_ATTR_TXT 0x500 /* text file */ #define TREE_ATTR_FONT 0x800 /* font file */ #define TREE_ATTR_LNG 0x1000 /* binary lang file */ +#define TREE_ATTR_ROCK 0x2000 /* binary rockbox plugin */ #define TREE_ATTR_MASK 0xffd0 /* which bits tree.c uses (above + DIR) */ void tree_init(void); diff --git a/apps/viewer.h b/apps/viewer.h deleted file mode 100644 index ed9f64ca49..0000000000 --- a/apps/viewer.h +++ /dev/null @@ -1,24 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Copyright (C) 2002 Jerome Kuptz - * - * All files in this archive are subject to the GNU General Public License. - * See the file COPYING in the source tree root for full license agreement. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ -#ifndef _VIEWER_H -#define _VIEWER_H - -bool viewer_run(char* file); - -#endif diff --git a/firmware/app.lds b/firmware/app.lds index 46a6ca70fb..34ab1adf66 100644 --- a/firmware/app.lds +++ b/firmware/app.lds @@ -2,15 +2,17 @@ ENTRY(start) OUTPUT_FORMAT(elf32-sh) INPUT(crt0.o) +#define PLUGINSIZE 0x8000 + #ifdef DEBUG -#define DRAMSIZE 0x1f0000 +#define DRAMSIZE 0x1f0000 - PLUGINSIZE #define ORIGADDR 0x09010000 -#define ENDADDR 0x09200000 + #else -#define DRAMSIZE (MEMORYSIZE * 0x100000) +#define DRAMSIZE (MEMORYSIZE * 0x100000) - PLUGINSIZE #define ORIGADDR 0x09000000 -#define ENDADDR (ORIGADDR + DRAMSIZE) #endif +#define ENDADDR (ORIGADDR + DRAMSIZE) MEMORY { @@ -91,6 +93,11 @@ SECTIONS _topramend = .; } > DRAM + .plugin ENDADDR: + { + _pluginbuf = .; + } + .iram 0xf000000 : AT ( _iramcopy ) { _iramstart = .; diff --git a/firmware/drivers/lcd-player-charset.c b/firmware/drivers/lcd-player-charset.c index 523158f49f..df4f3f016d 100644 --- a/firmware/drivers/lcd-player-charset.c +++ b/firmware/drivers/lcd-player-charset.c @@ -47,7 +47,7 @@ unsigned short new_lcd_rocklatin1_to_xlcd[] = RESERVED_CHAR, /* 0x01-0x17 reserved */ RESERVED_CHAR, /* 0x01-0x17 reserved */ RESERVED_CHAR, /* 0x01-0x17 reserved */ - RESERVED_CHAR, /* 0x01-0x17 reserved */ + 0x217, /* 0x17 .. "plugin" icon */ 0x218, /* 0x18 .. "folder" icon */ 0x219, /* 0x19 .. "MOD/AJZ" icon (winlatin o (dote in the middle) */ 0x21a, /* 0x1a .. "language" icon (winlatin - (a bit longer minus sign) */ @@ -668,7 +668,7 @@ unsigned char extended_font_player[NO_EXTENDED_LCD_CHARS][8] = { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 14 */ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 15 */ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 16 */ - { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 17 */ + { 0x04, 0x1e, 0x07, 0x1f, 0x05, 0x01, 0x06, 0x00}, /* 17 Plugin file icon */ { 0x0c, 0x13, 0x11, 0x11, 0x11, 0x11, 0x1f, 0x00}, /* 18 Folder icon */ { 0x1f, 0x11, 0x1b, 0x15, 0x1b, 0x11, 0x1f, 0x00}, /* 19 MOD/AJZ icon */ { 0x00, 0x1f, 0x15, 0x1f, 0x15, 0x1f, 0x00, 0x00}, /* 1a Language icon */ |