From ba371fb595affd68c823926b85718d1d613dc7d3 Mon Sep 17 00:00:00 2001 From: Björn Stenberg Date: Sun, 29 Jun 2003 16:33:04 +0000 Subject: 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 --- apps/Makefile | 8 +- apps/demo_menu.c | 37 +- apps/games_menu.c | 29 +- apps/lang/english.lang | 76 +- apps/player/icons.h | 3 +- apps/plugin.c | 221 ++++ apps/plugin.h | 161 +++ apps/plugins/Makefile | 45 + apps/plugins/bounce.c | 409 +++++++ apps/plugins/cube.c | 338 ++++++ apps/plugins/helloworld.c | 48 + apps/plugins/oscillograph.c | 207 ++++ apps/plugins/plugin.lds | 26 + apps/plugins/snow.c | 111 ++ apps/plugins/sokoban.c | 868 ++++++++++++++ apps/plugins/viewer.c | 415 +++++++ apps/plugins/wormlet.c | 2009 ++++++++++++++++++++++++++++++++ apps/recorder/bounce.c | 417 ------- apps/recorder/cube.c | 353 ------ apps/recorder/icons.c | 1 + apps/recorder/icons.h | 1 + apps/recorder/oscillograph.c | 207 ---- apps/recorder/snow.c | 117 -- apps/recorder/sokoban.c | 891 --------------- apps/recorder/sokoban.h | 28 - apps/recorder/tetris.c | 438 ------- apps/recorder/wormlet.c | 2036 --------------------------------- apps/recorder/wormlet.h | 28 - apps/screens.c | 1 + apps/tree.c | 19 +- apps/tree.h | 1 + apps/viewer.c | 432 ------- apps/viewer.h | 24 - firmware/app.lds | 15 +- firmware/drivers/lcd-player-charset.c | 4 +- 35 files changed, 5002 insertions(+), 5022 deletions(-) create mode 100644 apps/plugin.c create mode 100644 apps/plugin.h create mode 100644 apps/plugins/Makefile create mode 100644 apps/plugins/bounce.c create mode 100644 apps/plugins/cube.c create mode 100644 apps/plugins/helloworld.c create mode 100644 apps/plugins/oscillograph.c create mode 100644 apps/plugins/plugin.lds create mode 100644 apps/plugins/snow.c create mode 100644 apps/plugins/sokoban.c create mode 100644 apps/plugins/viewer.c create mode 100644 apps/plugins/wormlet.c delete mode 100644 apps/recorder/bounce.c delete mode 100644 apps/recorder/cube.c delete mode 100644 apps/recorder/oscillograph.c delete mode 100644 apps/recorder/snow.c delete mode 100644 apps/recorder/sokoban.c delete mode 100644 apps/recorder/sokoban.h delete mode 100644 apps/recorder/tetris.c delete mode 100644 apps/recorder/wormlet.c delete mode 100644 apps/recorder/wormlet.h delete mode 100644 apps/viewer.c delete mode 100644 apps/viewer.h 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 #include -#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 #include -#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 +#include +#include +#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 +#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 +#include +#include +#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/plugins/bounce.c b/apps/plugins/bounce.c new file mode 100644 index 0000000000..0c53d49887 --- /dev/null +++ b/apps/plugins/bounce.c @@ -0,0 +1,409 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2002 Daniel 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" + +#ifdef HAVE_LCD_BITMAP + +#define SS_TITLE "Bouncer" +#define SS_TITLE_FONT 2 + +#define LETTERS_ON_SCREEN 12 + +#define YSPEED 2 +#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, +}; + +static unsigned char xtable[]={ +54,58,63,67,71,75,79,82,85,88,91,93,95,97,98,99,99,99,99,99,97,96,94,92,90,87,84,80,77,73,69,65,60,56,52,47,43,39,34,30,26,22,19,15,12,9,7,5,3,2,0,0,0,0,0,1,2,4,6,8,11,14,17,20,24,28,32,36,41,45,49 +}; + +static signed char speed[]={ + 1,2,3,3,3,2,1,0,-1,-2,-2,-2,-1,0,0,1, +}; + +const unsigned char char_gen_12x16[][22] = +{ + { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, + { 0x00,0x00,0x00,0x00,0x00,0x00,0x7c,0x00,0xff,0x33,0xff,0x33,0x7c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, + { 0x00,0x00,0x00,0x00,0x3c,0x00,0x3c,0x00,0x00,0x00,0x00,0x00,0x3c,0x00,0x3c,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, + { 0x00,0x02,0x10,0x1e,0x90,0x1f,0xf0,0x03,0x7e,0x02,0x1e,0x1e,0x90,0x1f,0xf0,0x03,0x7e,0x02,0x1e,0x00,0x10,0x00 }, + { 0x00,0x00,0x78,0x04,0xfc,0x0c,0xcc,0x0c,0xff,0x3f,0xff,0x3f,0xcc,0x0c,0xcc,0x0f,0x88,0x07,0x00,0x00,0x00,0x00 }, + { 0x00,0x30,0x38,0x38,0x38,0x1c,0x38,0x0e,0x00,0x07,0x80,0x03,0xc0,0x01,0xe0,0x38,0x70,0x38,0x38,0x38,0x1c,0x00 }, + { 0x00,0x00,0x00,0x1f,0xb8,0x3f,0xfc,0x31,0xc6,0x21,0xe2,0x37,0x3e,0x1e,0x1c,0x1c,0x00,0x36,0x00,0x22,0x00,0x00 }, + { 0x00,0x00,0x00,0x00,0x00,0x00,0x27,0x00,0x3f,0x00,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, + { 0x00,0x00,0x00,0x00,0xf0,0x03,0xfc,0x0f,0xfe,0x1f,0x07,0x38,0x01,0x20,0x01,0x20,0x00,0x00,0x00,0x00,0x00,0x00 }, + { 0x00,0x00,0x00,0x00,0x01,0x20,0x01,0x20,0x07,0x38,0xfe,0x1f,0xfc,0x0f,0xf0,0x03,0x00,0x00,0x00,0x00,0x00,0x00 }, + { 0x00,0x00,0x98,0x0c,0xb8,0x0e,0xe0,0x03,0xf8,0x0f,0xf8,0x0f,0xe0,0x03,0xb8,0x0e,0x98,0x0c,0x00,0x00,0x00,0x00 }, + { 0x00,0x00,0x80,0x01,0x80,0x01,0x80,0x01,0xf0,0x0f,0xf0,0x0f,0x80,0x01,0x80,0x01,0x80,0x01,0x00,0x00,0x00,0x00 }, + { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xb8,0x00,0xf8,0x00,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, + { 0x00,0x00,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x00,0x00,0x00,0x00 }, + { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x00,0x38,0x00,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, + { 0x00,0x18,0x00,0x1c,0x00,0x0e,0x00,0x07,0x80,0x03,0xc0,0x01,0xe0,0x00,0x70,0x00,0x38,0x00,0x1c,0x00,0x0e,0x00 }, + { 0xf8,0x07,0xfe,0x1f,0x06,0x1e,0x03,0x33,0x83,0x31,0xc3,0x30,0x63,0x30,0x33,0x30,0x1e,0x18,0xfe,0x1f,0xf8,0x07 }, + { 0x00,0x00,0x00,0x00,0x0c,0x30,0x0c,0x30,0x0e,0x30,0xff,0x3f,0xff,0x3f,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x00 }, + { 0x1c,0x30,0x1e,0x38,0x07,0x3c,0x03,0x3e,0x03,0x37,0x83,0x33,0xc3,0x31,0xe3,0x30,0x77,0x30,0x3e,0x30,0x1c,0x30 }, + { 0x0c,0x0c,0x0e,0x1c,0x07,0x38,0xc3,0x30,0xc3,0x30,0xc3,0x30,0xc3,0x30,0xc3,0x30,0xe7,0x39,0x7e,0x1f,0x3c,0x0e }, + { 0xc0,0x03,0xe0,0x03,0x70,0x03,0x38,0x03,0x1c,0x03,0x0e,0x03,0x07,0x03,0xff,0x3f,0xff,0x3f,0x00,0x03,0x00,0x03 }, + { 0x3f,0x0c,0x7f,0x1c,0x63,0x38,0x63,0x30,0x63,0x30,0x63,0x30,0x63,0x30,0x63,0x30,0xe3,0x38,0xc3,0x1f,0x83,0x0f }, + { 0xc0,0x0f,0xf0,0x1f,0xf8,0x39,0xdc,0x30,0xce,0x30,0xc7,0x30,0xc3,0x30,0xc3,0x30,0xc3,0x39,0x80,0x1f,0x00,0x0f }, + { 0x03,0x00,0x03,0x00,0x03,0x00,0x03,0x30,0x03,0x3c,0x03,0x0f,0xc3,0x03,0xf3,0x00,0x3f,0x00,0x0f,0x00,0x03,0x00 }, + { 0x00,0x0f,0xbc,0x1f,0xfe,0x39,0xe7,0x30,0xc3,0x30,0xc3,0x30,0xc3,0x30,0xe7,0x30,0xfe,0x39,0xbc,0x1f,0x00,0x0f }, + { 0x3c,0x00,0x7e,0x00,0xe7,0x30,0xc3,0x30,0xc3,0x30,0xc3,0x38,0xc3,0x1c,0xc3,0x0e,0xe7,0x07,0xfe,0x03,0xfc,0x00 }, + { 0x00,0x00,0x00,0x00,0x00,0x00,0x70,0x1c,0x70,0x1c,0x70,0x1c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, + { 0x00,0x00,0x00,0x00,0x00,0x00,0x70,0x9c,0x70,0xfc,0x70,0x7c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, + { 0x00,0x00,0xc0,0x00,0xe0,0x01,0xf0,0x03,0x38,0x07,0x1c,0x0e,0x0e,0x1c,0x07,0x38,0x03,0x30,0x00,0x00,0x00,0x00 }, + { 0x00,0x00,0x60,0x06,0x60,0x06,0x60,0x06,0x60,0x06,0x60,0x06,0x60,0x06,0x60,0x06,0x60,0x06,0x60,0x06,0x00,0x00 }, + { 0x00,0x00,0x03,0x30,0x07,0x38,0x0e,0x1c,0x1c,0x0e,0x38,0x07,0xf0,0x03,0xe0,0x01,0xc0,0x00,0x00,0x00,0x00,0x00 }, + { 0x1c,0x00,0x1e,0x00,0x07,0x00,0x03,0x00,0x83,0x37,0xc3,0x37,0xe3,0x00,0x77,0x00,0x3e,0x00,0x1c,0x00,0x00,0x00 }, + { 0xf8,0x0f,0xfe,0x1f,0x07,0x18,0xf3,0x33,0xfb,0x37,0x1b,0x36,0xfb,0x37,0xfb,0x37,0x07,0x36,0xfe,0x03,0xf8,0x01 }, + { 0x00,0x38,0x00,0x3f,0xe0,0x07,0xfc,0x06,0x1f,0x06,0x1f,0x06,0xfc,0x06,0xe0,0x07,0x00,0x3f,0x00,0x38,0x00,0x00 }, + { 0xff,0x3f,0xff,0x3f,0xc3,0x30,0xc3,0x30,0xc3,0x30,0xc3,0x30,0xe7,0x30,0xfe,0x39,0xbc,0x1f,0x00,0x0f,0x00,0x00 }, + { 0xf0,0x03,0xfc,0x0f,0x0e,0x1c,0x07,0x38,0x03,0x30,0x03,0x30,0x03,0x30,0x07,0x38,0x0e,0x1c,0x0c,0x0c,0x00,0x00 }, + { 0xff,0x3f,0xff,0x3f,0x03,0x30,0x03,0x30,0x03,0x30,0x03,0x30,0x07,0x38,0x0e,0x1c,0xfc,0x0f,0xf0,0x03,0x00,0x00 }, + { 0xff,0x3f,0xff,0x3f,0xc3,0x30,0xc3,0x30,0xc3,0x30,0xc3,0x30,0xc3,0x30,0xc3,0x30,0x03,0x30,0x03,0x30,0x00,0x00 }, + { 0xff,0x3f,0xff,0x3f,0xc3,0x00,0xc3,0x00,0xc3,0x00,0xc3,0x00,0xc3,0x00,0xc3,0x00,0x03,0x00,0x03,0x00,0x00,0x00 }, + { 0xf0,0x03,0xfc,0x0f,0x0e,0x1c,0x07,0x38,0x03,0x30,0xc3,0x30,0xc3,0x30,0xc3,0x30,0xc7,0x3f,0xc6,0x3f,0x00,0x00 }, + { 0xff,0x3f,0xff,0x3f,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xff,0x3f,0xff,0x3f,0x00,0x00 }, + { 0x00,0x00,0x00,0x00,0x03,0x30,0x03,0x30,0xff,0x3f,0xff,0x3f,0x03,0x30,0x03,0x30,0x00,0x00,0x00,0x00,0x00,0x00 }, + { 0x00,0x0e,0x00,0x1e,0x00,0x38,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x38,0xff,0x1f,0xff,0x07,0x00,0x00 }, + { 0xff,0x3f,0xff,0x3f,0xc0,0x00,0xe0,0x01,0xf0,0x03,0x38,0x07,0x1c,0x0e,0x0e,0x1c,0x07,0x38,0x03,0x30,0x00,0x00 }, + { 0xff,0x3f,0xff,0x3f,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x00 }, + { 0xff,0x3f,0xff,0x3f,0x1e,0x00,0x78,0x00,0xe0,0x01,0xe0,0x01,0x78,0x00,0x1e,0x00,0xff,0x3f,0xff,0x3f,0x00,0x00 }, + { 0xff,0x3f,0xff,0x3f,0x0e,0x00,0x38,0x00,0xf0,0x00,0xc0,0x03,0x00,0x07,0x00,0x1c,0xff,0x3f,0xff,0x3f,0x00,0x00 }, + { 0xf0,0x03,0xfc,0x0f,0x0e,0x1c,0x07,0x38,0x03,0x30,0x03,0x30,0x07,0x38,0x0e,0x1c,0xfc,0x0f,0xf0,0x03,0x00,0x00 }, + { 0xff,0x3f,0xff,0x3f,0x83,0x01,0x83,0x01,0x83,0x01,0x83,0x01,0x83,0x01,0xc7,0x01,0xfe,0x00,0x7c,0x00,0x00,0x00 }, + { 0xf0,0x03,0xfc,0x0f,0x0e,0x1c,0x07,0x38,0x03,0x30,0x03,0x36,0x07,0x3e,0x0e,0x1c,0xfc,0x3f,0xf0,0x33,0x00,0x00 }, + { 0xff,0x3f,0xff,0x3f,0x83,0x01,0x83,0x01,0x83,0x03,0x83,0x07,0x83,0x0f,0xc7,0x1d,0xfe,0x38,0x7c,0x30,0x00,0x00 }, + { 0x3c,0x0c,0x7e,0x1c,0xe7,0x38,0xc3,0x30,0xc3,0x30,0xc3,0x30,0xc3,0x30,0xc7,0x39,0x8e,0x1f,0x0c,0x0f,0x00,0x00 }, + { 0x00,0x00,0x03,0x00,0x03,0x00,0x03,0x00,0xff,0x3f,0xff,0x3f,0x03,0x00,0x03,0x00,0x03,0x00,0x00,0x00,0x00,0x00 }, + { 0xff,0x07,0xff,0x1f,0x00,0x38,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x38,0xff,0x1f,0xff,0x07,0x00,0x00 }, + { 0x07,0x00,0x3f,0x00,0xf8,0x01,0xc0,0x0f,0x00,0x3e,0x00,0x3e,0xc0,0x0f,0xf8,0x01,0x3f,0x00,0x07,0x00,0x00,0x00 }, + { 0xff,0x3f,0xff,0x3f,0x00,0x1c,0x00,0x06,0x80,0x03,0x80,0x03,0x00,0x06,0x00,0x1c,0xff,0x3f,0xff,0x3f,0x00,0x00 }, + { 0x03,0x30,0x0f,0x3c,0x1c,0x0e,0x30,0x03,0xe0,0x01,0xe0,0x01,0x30,0x03,0x1c,0x0e,0x0f,0x3c,0x03,0x30,0x00,0x00 }, + { 0x03,0x00,0x0f,0x00,0x3c,0x00,0xf0,0x00,0xc0,0x3f,0xc0,0x3f,0xf0,0x00,0x3c,0x00,0x0f,0x00,0x03,0x00,0x00,0x00 }, + { 0x03,0x30,0x03,0x3c,0x03,0x3e,0x03,0x33,0xc3,0x31,0xe3,0x30,0x33,0x30,0x1f,0x30,0x0f,0x30,0x03,0x30,0x00,0x00 }, + { 0x00,0x00,0x00,0x00,0xff,0x3f,0xff,0x3f,0x03,0x30,0x03,0x30,0x03,0x30,0x03,0x30,0x00,0x00,0x00,0x00,0x00,0x00 }, + { 0x0e,0x00,0x1c,0x00,0x38,0x00,0x70,0x00,0xe0,0x00,0xc0,0x01,0x80,0x03,0x00,0x07,0x00,0x0e,0x00,0x1c,0x00,0x18 }, + { 0x00,0x00,0x00,0x00,0x03,0x30,0x03,0x30,0x03,0x30,0x03,0x30,0xff,0x3f,0xff,0x3f,0x00,0x00,0x00,0x00,0x00,0x00 }, + { 0x60,0x00,0x70,0x00,0x38,0x00,0x1c,0x00,0x0e,0x00,0x07,0x00,0x0e,0x00,0x1c,0x00,0x38,0x00,0x70,0x00,0x60,0x00 }, + { 0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0 }, + { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3e,0x00,0x7e,0x00,0x4e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, + { 0x00,0x1c,0x40,0x3e,0x60,0x33,0x60,0x33,0x60,0x33,0x60,0x33,0x60,0x33,0x60,0x33,0xe0,0x3f,0xc0,0x3f,0x00,0x00 }, + { 0xff,0x3f,0xff,0x3f,0xc0,0x30,0x60,0x30,0x60,0x30,0x60,0x30,0x60,0x30,0xe0,0x38,0xc0,0x1f,0x80,0x0f,0x00,0x00 }, + { 0x80,0x0f,0xc0,0x1f,0xe0,0x38,0x60,0x30,0x60,0x30,0x60,0x30,0x60,0x30,0x60,0x30,0xc0,0x18,0x80,0x08,0x00,0x00 }, + { 0x80,0x0f,0xc0,0x1f,0xe0,0x38,0x60,0x30,0x60,0x30,0x60,0x30,0xe0,0x30,0xc0,0x30,0xff,0x3f,0xff,0x3f,0x00,0x00 }, + { 0x80,0x0f,0xc0,0x1f,0xe0,0x3b,0x60,0x33,0x60,0x33,0x60,0x33,0x60,0x33,0x60,0x33,0xc0,0x13,0x80,0x01,0x00,0x00 }, + { 0xc0,0x00,0xc0,0x00,0xfc,0x3f,0xfe,0x3f,0xc7,0x00,0xc3,0x00,0xc3,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, + { 0x80,0x03,0xc0,0xc7,0xe0,0xce,0x60,0xcc,0x60,0xcc,0x60,0xcc,0x60,0xcc,0x60,0xe6,0xe0,0x7f,0xe0,0x3f,0x00,0x00 }, + { 0xff,0x3f,0xff,0x3f,0xc0,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0xe0,0x00,0xc0,0x3f,0x80,0x3f,0x00,0x00,0x00,0x00 }, + { 0x00,0x00,0x00,0x00,0x00,0x30,0x60,0x30,0xec,0x3f,0xec,0x3f,0x00,0x30,0x00,0x30,0x00,0x00,0x00,0x00,0x00,0x00 }, + { 0x00,0x00,0x00,0x00,0x00,0x60,0x00,0xe0,0x00,0xc0,0x60,0xc0,0xec,0xff,0xec,0x7f,0x00,0x00,0x00,0x00,0x00,0x00 }, + { 0x00,0x00,0xff,0x3f,0xff,0x3f,0x00,0x03,0x80,0x07,0xc0,0x0f,0xe0,0x1c,0x60,0x38,0x00,0x30,0x00,0x00,0x00,0x00 }, + { 0x00,0x00,0x00,0x00,0x00,0x30,0x03,0x30,0xff,0x3f,0xff,0x3f,0x00,0x30,0x00,0x30,0x00,0x00,0x00,0x00,0x00,0x00 }, + { 0xe0,0x3f,0xc0,0x3f,0xe0,0x00,0xe0,0x00,0xc0,0x3f,0xc0,0x3f,0xe0,0x00,0xe0,0x00,0xc0,0x3f,0x80,0x3f,0x00,0x00 }, + { 0x00,0x00,0xe0,0x3f,0xe0,0x3f,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0xe0,0x00,0xc0,0x3f,0x80,0x3f,0x00,0x00 }, + { 0x80,0x0f,0xc0,0x1f,0xe0,0x38,0x60,0x30,0x60,0x30,0x60,0x30,0x60,0x30,0xe0,0x38,0xc0,0x1f,0x80,0x0f,0x00,0x00 }, + { 0xe0,0xff,0xe0,0xff,0x60,0x0c,0x60,0x18,0x60,0x18,0x60,0x18,0x60,0x18,0xe0,0x1c,0xc0,0x0f,0x80,0x07,0x00,0x00 }, + { 0x80,0x07,0xc0,0x0f,0xe0,0x1c,0x60,0x18,0x60,0x18,0x60,0x18,0x60,0x18,0x60,0x0c,0xe0,0xff,0xe0,0xff,0x00,0x00 }, + { 0x00,0x00,0xe0,0x3f,0xe0,0x3f,0xc0,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0xe0,0x00,0xc0,0x00,0x00,0x00 }, + { 0xc0,0x11,0xe0,0x33,0x60,0x33,0x60,0x33,0x60,0x33,0x60,0x33,0x60,0x3f,0x40,0x1e,0x00,0x00,0x00,0x00,0x00,0x00 }, + { 0x60,0x00,0x60,0x00,0xfe,0x1f,0xfe,0x3f,0x60,0x30,0x60,0x30,0x60,0x30,0x00,0x30,0x00,0x00,0x00,0x00,0x00,0x00 }, + { 0xe0,0x0f,0xe0,0x1f,0x00,0x38,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x18,0xe0,0x3f,0xe0,0x3f,0x00,0x00 }, + { 0x60,0x00,0xe0,0x01,0x80,0x07,0x00,0x1e,0x00,0x38,0x00,0x38,0x00,0x1e,0x80,0x07,0xe0,0x01,0x60,0x00,0x00,0x00 }, + { 0xe0,0x07,0xe0,0x1f,0x00,0x38,0x00,0x1c,0xe0,0x0f,0xe0,0x0f,0x00,0x1c,0x00,0x38,0xe0,0x1f,0xe0,0x07,0x00,0x00 }, + { 0x60,0x30,0xe0,0x38,0xc0,0x1d,0x80,0x0f,0x00,0x07,0x80,0x0f,0xc0,0x1d,0xe0,0x38,0x60,0x30,0x00,0x00,0x00,0x00 }, + { 0x00,0x00,0x60,0x00,0xe0,0x81,0x80,0xe7,0x00,0x7e,0x00,0x1e,0x80,0x07,0xe0,0x01,0x60,0x00,0x00,0x00,0x00,0x00 }, + { 0x60,0x30,0x60,0x38,0x60,0x3c,0x60,0x36,0x60,0x33,0xe0,0x31,0xe0,0x30,0x60,0x30,0x20,0x30,0x00,0x00,0x00,0x00 }, + { 0x00,0x00,0x80,0x00,0xc0,0x01,0xfc,0x1f,0x7e,0x3f,0x07,0x70,0x03,0x60,0x03,0x60,0x03,0x60,0x00,0x00,0x00,0x00 }, + { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x3f,0xff,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, + { 0x00,0x00,0x03,0x60,0x03,0x60,0x03,0x60,0x07,0x70,0x7e,0x3f,0xfc,0x1f,0xc0,0x01,0x80,0x00,0x00,0x00,0x00,0x00 }, + { 0x10,0x00,0x18,0x00,0x0c,0x00,0x04,0x00,0x0c,0x00,0x18,0x00,0x10,0x00,0x18,0x00,0x0c,0x00,0x04,0x00,0x00,0x00 }, + { 0xff,0x3f,0xff,0x3f,0xff,0x3f,0xff,0x3f,0xff,0x3f,0xff,0x3f,0xff,0x3f,0xff,0x3f,0xff,0x3f,0xff,0x3f,0x00,0x00 } +}; + +#define XDIFF -4 +#define YDIFF -6 + +enum { + NUM_XSANKE, + NUM_YSANKE, + NUM_XADD, + NUM_YADD, + NUM_XDIST, + NUM_YDIST, + + NUM_LAST +}; + +struct counter { + char *what; + int num; +}; + +struct counter values[]={ + {"xsanke", 1}, + {"ysanke", 1}, + {"xadd", 1}, + {"yadd", 1}, + {"xdist", -4}, + {"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, +}; +static unsigned char yhour[]={ +42,42,42,42,41,41,40,39,39,38,37,36,35,34,33,32,30,29,28,27,26,25,24,24,23,22,22,21,21,21,21,21,21,21,22,22,23,24,24,25,26,27,28,29,30,31,33,34,35,36,37,38,39,39,40,41,41,42,42,42, +}; + +static unsigned char xminute[]={ +56,59,63,67,71,74,77,80,83,86,88,90,91,92,93,93,93,92,91,90,88,86,83,80,77,74,71,67,63,59,56,52,48,44,40,37,34,31,28,25,23,21,20,19,18,18,18,19,20,21,23,25,28,31,34,37,40,44,48,52, +}; +static unsigned char xhour[]={ +56,57,59,61,63,65,66,68,69,71,72,73,73,74,74,74,74,74,73,73,72,71,69,68,66,65,63,61,59,57,56,54,52,50,48,46,45,43,42,40,39,38,38,37,37,37,37,37,38,38,39,40,42,43,45,46,48,50,52,54, +}; + +static void addclock(void) +{ + int i; + int hour; + int minute; + int pos; + + hour = rtc_read(3); + hour = (((hour & 0x30) >> 4) * 10 + (hour & 0x0f))%12; + minute = rtc_read(2); + minute = ((minute & 0x70) >> 4) * 10 + (minute & 0x0f); + + pos = 90-minute; + if(pos >= 60) + pos -= 60; + + 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; + + rb->lcd_drawline(LCD_WIDTH/2, LCD_HEIGHT/2, xhour[pos], yhour[pos]); + + /* draw a circle */ + for(i=0; i < 60; i+=3) { + rb->lcd_drawline( xminute[i], + yminute[i], + xminute[(i+1)%60], + yminute[(i+1)%60]); + } +} +#endif + +static int scrollit(void) +{ + int b; + unsigned int y=100; + int x=LCD_WIDTH; + unsigned int yy,xx; + unsigned int i; + int textpos=0; + + char* rock="Rockbox! Pure pleasure. Pure fun. Oooh. What fun! ;-) "; + int letter; + + rb->lcd_clear_display(); + while(1) + { + 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; + + rb->lcd_clear_display(); + + for(i=0, yy=y, xx=x; i< LETTERS_ON_SCREEN; i++) { + letter = rock[(i+textpos) % (sizeof(rock)-1) ]; + + 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(); +#endif + rb->lcd_update(); + + x-= XSPEED; + + if(x < 0) { + x += LCD_WIDTH/LETTERS_ON_SCREEN; + y += YADD; + textpos++; + } + + y+=YSPEED; + + } +} + +static int loopit(void) +{ + int b; + unsigned int y=100; + unsigned int x=100; + unsigned int yy,xx; + unsigned int i; + unsigned int ysanke=0; + unsigned int xsanke=0; + + char* rock="ROCKbox"; + + int show=0; + int timeout=0; + char buffer[30]; + + rb->lcd_clear_display(); + while(1) + { + b = rb->button_get_w_tmo(HZ/10); + if ( b == (BUTTON_OFF|BUTTON_REL) ) + return 0; + + if ( b == SYS_USB_CONNECTED) { + rb->usb_screen(); + return 0; + } + + if ( b == (BUTTON_ON|BUTTON_REL) ) + return 1; + else if(b != BUTTON_NONE) + timeout=20; + + y+= speed[ysanke&15] + values[NUM_YADD].num; + x+= speed[xsanke&15] + values[NUM_XADD].num; + + rb->lcd_clear_display(); +#ifdef USE_CLOCK + addclock(); +#endif + if(timeout) { + switch(b) { + case BUTTON_LEFT: + values[show].num--; + break; + case BUTTON_RIGHT: + values[show].num++; + break; + case BUTTON_UP: + if(++show == NUM_LAST) + show=0; + break; + case BUTTON_DOWN: + if(--show < 0) + show=NUM_LAST-1; + break; + } + 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; + ilcd_bitmap((char *)char_gen_12x16[rock[i]-0x20], + xtable[xx%71], table[yy&63], + 11, 16, false); + rb->lcd_update(); + + ysanke+= values[NUM_YSANKE].num; + xsanke+= values[NUM_XSANKE].num; + } +} + + +enum plugin_status plugin_start(struct plugin_api* api, void* parameter) +{ + int w, h; + char *off = "[Off] to stop"; + int len; + + TEST_PLUGIN_API(api); + (void)(parameter); + rb = api; + + len = rb->strlen(SS_TITLE); + rb->lcd_setfont(FONT_SYSFIXED); + rb->lcd_getstringsize(SS_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, SS_TITLE); + + len = 1; + rb->lcd_getstringsize(off, &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_putsxy(LCD_WIDTH/2-len, LCD_HEIGHT-(2*h), off); + rb->lcd_update(); + rb->sleep(HZ); + + do { + h= loopit(); + if(h) + h = scrollit(); + } while(h); + + rb->lcd_setfont(FONT_UI); + + return false; +} + +#endif diff --git a/apps/plugins/cube.c b/apps/plugins/cube.c new file mode 100644 index 0000000000..996a1a81dd --- /dev/null +++ b/apps/plugins/cube.c @@ -0,0 +1,338 @@ +/*************************************************************************** +* __________ __ ___. +* Open \______ \ ____ ____ | | _\_ |__ _______ ___ +* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / +* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < +* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ +* \/ \/ \/ \/ \/ +* $Id$ +* +* Copyright (C) 2002 Damien Teney +* modified to use int instead of float math by Andreas Zwirtes +* +* 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 + +/* Loops that the values are displayed */ +#define DISP_TIME 30 + +struct point_3D { + long x, y, z; +}; + +struct point_2D { + long x, y; +}; + +static struct point_3D sommet[8]; +static struct point_3D point3D[8]; +static struct point_2D point2D[8]; + +static long matrice[3][3]; + +static int nb_points = 8; + +static int x_off = 56; +static int y_off = 95; +static int z_off = 600; + +/* Precalculated sine and cosine * 10000 (four digit fixed point math) */ +static int sin_table[91] = +{ + 0, 174, 348, 523, 697, + 871,1045,1218,1391,1564, + 1736,1908,2079,2249,2419, + 2588,2756,2923,3090,3255, + 3420,3583,3746,3907,4067, + 4226,4383,4539,4694,4848, + 5000,5150,5299,5446,5591, + 5735,5877,6018,6156,6293, + 6427,6560,6691,6819,6946, + 7071,7193,7313,7431,7547, + 7660,7771,7880,7986,8090, + 8191,8290,8386,8480,8571, + 8660,8746,8829,8910,8987, + 9063,9135,9205,9271,9335, + 9396,9455,9510,9563,9612, + 9659,9702,9743,9781,9816, + 9848,9876,9902,9925,9945, + 9961,9975,9986,9993,9998, + 10000 +}; + +static struct plugin_api* rb; + +static long sin(int val) +{ + /* Speed improvement through sukzessive lookup */ + if (val<181) + { + if (val<91) + { + /* phase 0-90 degree */ + return (long)sin_table[val]; + } + else + { + /* phase 91-180 degree */ + return (long)sin_table[180-val]; + } + } + else + { + if (val<271) + { + /* phase 181-270 degree */ + return (-1L)*(long)sin_table[val-180]; + } + else + { + /* phase 270-359 degree */ + return (-1L)*(long)sin_table[360-val]; + } + } + return 0; +} + +static long cos(int val) +{ + /* Speed improvement through sukzessive lookup */ + if (val<181) + { + if (val<91) + { + /* phase 0-90 degree */ + return (long)sin_table[90-val]; + } + else + { + /* phase 91-180 degree */ + return (-1L)*(long)sin_table[val-90]; + } + } + else + { + if (val<271) + { + /* phase 181-270 degree */ + return (-1L)*(long)sin_table[270-val]; + } + else + { + /* phase 270-359 degree */ + return (long)sin_table[val-270]; + } + } + return 0; +} + + +static void cube_rotate(int xa, int ya, int za) +{ + int i; + + /* Just to prevent unnecessary lookups */ + long sxa,cxa,sya,cya,sza,cza; + sxa=sin(xa); + cxa=cos(xa); + sya=sin(ya); + cya=cos(ya); + sza=sin(za); + cza=cos(za); + + /* calculate overall translation matrix */ + matrice[0][0] = cza*cya/10000L; + matrice[1][0] = sza*cya/10000L; + matrice[2][0] = -sya; + + matrice[0][1] = cza*sya/10000L*sxa/10000L - sza*cxa/10000L; + matrice[1][1] = sza*sya/10000L*sxa/10000L + cxa*cza/10000L; + matrice[2][1] = sxa*cya/10000L; + + matrice[0][2] = cza*sya/10000L*cxa/10000L + sza*sxa/10000L; + matrice[1][2] = sza*sya/10000L*cxa/10000L - cza*sxa/10000L; + matrice[2][2] = cxa*cya/10000L; + + /* apply translation matrix to all points */ + for(i=0;ilcd_drawline(point2D[a].x, point2D[a].y, point2D[b].x, point2D[b].y); +} + +static void cube_draw(void) +{ + /* Draws front face */ + line(0,1); line(1,2); + line(2,3); line(3,0); + + /* Draws rear face */ + line(4,5); line(5,6); + line(6,7); line(7,4); + + /* Draws the other edges */ + line(0,5); + line(1,4); + line(2,7); + line(3,6); +} + + +enum plugin_status plugin_start(struct plugin_api* api, void* parameter) +{ + int t_disp=0; + char buffer[30]; + + int xa=0; + int ya=0; + int za=0; + int xs=1; + int ys=3; + int zs=1; + bool highspeed=0; + bool exit=0; + + TEST_PLUGIN_API(api); + (void)(parameter); + rb = api; + + rb->lcd_setfont(FONT_SYSFIXED); + + cube_init(); + + while(!exit) + { + if (!highspeed) + rb->sleep(4); + + rb->lcd_clear_display(); + cube_rotate(xa,ya,za); + cube_viewport(); + cube_draw(); + if (t_disp>0) + { + t_disp--; + rb->snprintf(buffer, 30, "x:%d y:%d z:%d h:%d",xs,ys,zs,highspeed); + rb->lcd_putsxy(0, 56, buffer); + } + rb->lcd_update(); + + xa+=xs; + if (xa>359) + xa-=360; + if (xa<0) + xa+=360; + ya+=ys; + if (ya>359) + ya-=360; + if (ya<0) + ya+=360; + za+=zs; + if (za>359) + za-=360; + if (za<0) + za+=360; + + switch(rb->button_get(false)) + { + case BUTTON_RIGHT: + xs+=1; + if (xs>10) + xs=10; + t_disp=DISP_TIME; + break; + case BUTTON_LEFT: + xs-=1; + if (xs<-10) + xs=-10; + t_disp=DISP_TIME; + break; + case BUTTON_UP: + ys+=1; + if (ys>10) + ys=10; + t_disp=DISP_TIME; + break; + case BUTTON_DOWN: + ys-=1; + if (ys<-10) + ys=-10; + t_disp=DISP_TIME; + break; + case BUTTON_F2: + zs+=1; + if (zs>10) + zs=10; + t_disp=DISP_TIME; + break; + case BUTTON_F1: + zs-=1; + if (zs<-10) + zs=-10; + t_disp=DISP_TIME; + break; + case BUTTON_PLAY: + highspeed=!highspeed; + t_disp=DISP_TIME; + break; + case BUTTON_OFF|BUTTON_REL: + exit=1; + break; + + case SYS_USB_CONNECTED: + rb->usb_screen(); + return PLUGIN_USB_CONNECTED; + } + } + + return PLUGIN_OK; +} + +#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/plugins/oscillograph.c b/apps/plugins/oscillograph.c new file mode 100644 index 0000000000..a34aa8bfa9 --- /dev/null +++ b/apps/plugins/oscillograph.c @@ -0,0 +1,207 @@ +/*************************************************************************** + * __________ __ ___. + * 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. + * + ****************************************************************************/ +#include "plugin.h" + +#ifdef HAVE_LCD_BITMAP +#ifndef SIMULATOR /* don't want this code in the simulator */ + +/* The different drawing modes */ +#define DRAW_MODE_FILLED 0 +#define DRAW_MODE_OUTLINE 1 +#define DRAW_MODE_PIXEL 2 +#define DRAW_MODE_COUNT 3 + +#define MAX_PEAK 0x8000 + +/* number of ticks between two volume samples */ +static int speed = 1; +/* roll == true -> lcd rolls */ +static bool roll = true; +/* see DRAW_MODE_XXX constants for valid values */ +static int drawMode = DRAW_MODE_FILLED; + +/** + * Displays a vertically scrolling oscillosgraph using + * hardware scrolling of the display. The user can change + * speed + */ +enum plugin_status plugin_start(struct plugin_api* rb, void* parameter) +{ + /* stores current volume value left */ + int left; + /* stores current volume value right */ + int right; + /* specifies the current position on the lcd */ + int y = LCD_WIDTH - 1; + + /* only needed when drawing lines */ + int lastLeft = 0; + int lastRight = 0; + int lasty = 0; + + bool exit = false; + + TEST_PLUGIN_API(rb); + (void)parameter; + + /* the main loop */ + while (!exit) { + + /* read the volume info from MAS */ + 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 */ + rb->lcd_clearline(0, y, LCD_WIDTH-1, y); + + switch (drawMode) { + case DRAW_MODE_FILLED: + 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: + /* last position needed for lines */ + lasty = MAX(y-1, 0); + + /* Here real lines were neccessary because + anything else was ugly. */ + 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 */ + lastRight = right; + lastLeft = left; + break; + + case DRAW_MODE_PIXEL: + /* straight and simple */ + rb->lcd_drawpixel(LCD_WIDTH / 2 + right, y); + rb->lcd_drawpixel(LCD_WIDTH / 2 - left, y); + break; + } + + + /* increment and adjust the drawing position */ + y++; + if (y >= LCD_HEIGHT) + y = 0; + + /* I roll before update because otherwise the new + line would appear at the wrong end of the display */ + if (roll) + rb->lcd_roll(y); + + /* now finally make the new sample visible */ + 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. + 2.) speeding up is achieved by leaving out + the user input check for (-speed) volume + samples. For this mechanism negative values + are used. + */ + + if (speed >= 0 || ((speed < 0) && (y % (-speed) == 0))) { + bool draw = false; + + /* speed values > 0 slow the oszi down. By user input + speed might become < 1. If a value < 1 was + passed user input would be disabled. Thus + it must be ensured that at least 1 is passed. */ + + /* react to user input */ + switch (rb->button_get_w_tmo(MAX(speed, 1))) { + case BUTTON_UP: + speed++; + draw = true; + break; + + case BUTTON_DOWN: + speed--; + draw = true; + break; + + case BUTTON_PLAY: + /* pause the demo */ + rb->button_get(true); + break; + + case BUTTON_F1: + /* toggle rolling */ + roll = !roll; + break; + + case BUTTON_F2: + /* step through the display modes */ + drawMode ++; + drawMode = drawMode % DRAW_MODE_COUNT; + + /* lcd buffer might be rolled so that + the transition from LCD_HEIGHT to 0 + takes place in the middle of the screen. + That produces ugly results in DRAW_MODE_OUTLINE + mode. If rolling is enabled this change will + be reverted before the next update anyway.*/ + rb->lcd_roll(0); + break; + + case BUTTON_F3: + speed = 1; + draw = true; + break; + + case BUTTON_OFF: + exit = true; + break; + + case SYS_USB_CONNECTED: + rb->usb_screen(); + return PLUGIN_USB_CONNECTED; + } + + if (draw) { + char buf[16]; + 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... */ + rb->lcd_roll(0); + rb->lcd_update(); + + /* standard return */ + 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/plugins/snow.c b/apps/plugins/snow.c new file mode 100644 index 0000000000..df9966eb38 --- /dev/null +++ b/apps/plugins/snow.c @@ -0,0 +1,111 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2002 Itai Shaked + * + * 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 NUM_PARTICLES 100 + +static short particles[NUM_PARTICLES][2]; +static struct plugin_api* rb; + +static bool particle_exists(int particle) +{ + if (particles[particle][0]>=0 && particles[particle][1]>=0 && + particles[particle][0]<112 && particles[particle][1]<64) + return true; + else + return false; +} + +static int create_particle(void) +{ + int i; + + for (i=0; irand()%112); + particles[i][1]=0; + return i; + } + } + return -1; +} + +static void snow_move(void) +{ + int i; + + if (!(rb->rand()%2)) + create_particle(); + + for (i=0; ilcd_clearpixel(particles[i][0],particles[i][1]); + switch ((rb->rand()%7)) { + case 0: + particles[i][0]++; + break; + + case 1: + particles[i][0]--; + break; + + case 2: + break; + + default: + particles[i][1]++; + break; + } + if (particle_exists(i)) + rb->lcd_drawpixel(particles[i][0],particles[i][1]); + } + } +} + +static void snow_init(void) +{ + int i; + + for (i=0; ilcd_clear_display(); +} + +enum plugin_status plugin_start(struct plugin_api* api, void* parameter) +{ + TEST_PLUGIN_API(api); + (void)(parameter); + rb = api; + + snow_init(); + while (1) { + snow_move(); + rb->lcd_update(); + rb->sleep(HZ/20); + + 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) && (ilcd_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/plugins/viewer.c b/apps/plugins/viewer.c new file mode 100644 index 0000000000..f8dc309a6e --- /dev/null +++ b/apps/plugins/viewer.c @@ -0,0 +1,415 @@ +/*************************************************************************** + * + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2002 Gilles Roux + * + * 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" + +#define BUFFER_SIZE 1024 +#define OUTSIDE_BUFFER -10 +#define OUTSIDE_FILE -11 + +static int fd; +static int file_size; + +static char buffer[BUFFER_SIZE+1]; +static int buffer_pos; /* Position of the buffer in the file */ + +static char display_lines; /* number of lines on the display */ +static char display_columns; /* number of columns on the display */ +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 + * the total space of the lines that are displayed on the screen exceeds the + * buffer size (only happens with very long lines). + */ + +static void display_line_count(void) +{ +#ifdef HAVE_LCD_BITMAP + int w,h; + rb->lcd_getstringsize("M", &w, &h); + display_lines = LCD_HEIGHT / h; + display_columns = LCD_WIDTH / w; +#else + display_lines = 2; + display_columns = 11; +#endif +} + +static int find_next_line(int pos) +{ + int i; + + if (pos==OUTSIDE_BUFFER || pos==OUTSIDE_FILE) + return pos; + + i = pos; + if (buffer_pos+i>=file_size) { + return OUTSIDE_FILE; + } + while (1) { + i++; + if (buffer_pos+i==file_size) { + return i; + } + if (i>=BUFFER_SIZE) { + return OUTSIDE_BUFFER; + } + if (buffer[i]==0) { + return i; + } + } +} + +static int find_prev_line(int pos) +{ + int i; + + if (pos==OUTSIDE_BUFFER || pos==OUTSIDE_FILE) + return pos; + + i = pos; + if (buffer_pos+i<0) { + return OUTSIDE_FILE; + } + while (1) { + i--; + if (buffer_pos+i<0) { + return i; + } + if (i<0) { + return OUTSIDE_BUFFER; + } + if (buffer[i]==0) { + return i; + } + } +} + +static void viewer_draw(int col) +{ + int i, j; + char* str; + int line_pos; + + rb->lcd_clear_display(); + + line_pos = begin_line_pos; + + for (i=0; i <= end_line - begin_line; i++) { + if (line_pos == OUTSIDE_BUFFER || + line_pos == OUTSIDE_FILE) + break; + str = buffer + line_pos + 1; + for (j=0; jlcd_puts(0, i, str); + line_pos = find_next_line(line_pos); + } +#ifdef HAVE_LCD_BITMAP + rb->lcd_update(); +#endif +} + +static void fill_buffer(int pos) +{ + int i; + int numread; + + if (pos>=file_size-BUFFER_SIZE) + pos = file_size-BUFFER_SIZE; + if (pos<0) + pos = 0; + + 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; + buffer_pos = pos; + + buffer[numread] = 0; + for(i=0;iopen(file, O_RDONLY); + if (fd==-1) + return false; + + file_size = rb->lseek(fd, 0, SEEK_END); + + buffer_pos = 0; + begin_line = 0; + begin_line_pos = -1; + end_line = -1; + end_line_pos = -1; + fill_buffer(0); + display_line_count(); + for (i=0; iclose(fd); +} + +static void viewer_scroll_down(void) +{ + int ret; + + ret = find_next_line(end_line_pos); + switch ( ret ) { + case OUTSIDE_BUFFER: + begin_line_pos = find_next_line(begin_line_pos); + fill_buffer(begin_line_pos+buffer_pos); + end_line_pos = find_next_line(end_line_pos); + break; + + case OUTSIDE_FILE: + return; + + default: + begin_line_pos = find_next_line(begin_line_pos); + end_line_pos = ret; + break; + } + begin_line++; + end_line++; +} + +static void viewer_scroll_up(void) +{ + int ret; + + ret = find_prev_line(begin_line_pos); + switch ( ret ) { + case OUTSIDE_BUFFER: + end_line_pos = find_prev_line(end_line_pos); + fill_buffer(buffer_pos+end_line_pos-BUFFER_SIZE); + begin_line_pos = find_prev_line(begin_line_pos); + break; + + case OUTSIDE_FILE: + return; + + default: + end_line_pos = find_prev_line(end_line_pos); + begin_line_pos = ret; + break; + } + begin_line--; + end_line--; +} + +static int pagescroll(int col) +{ + bool exit = false; + int i; + + while (!exit) { + switch (rb->button_get(true)) { +#ifdef HAVE_RECORDER_KEYPAD + case BUTTON_ON | BUTTON_UP: + case BUTTON_ON | BUTTON_UP | BUTTON_REPEAT: +#else + case BUTTON_ON | BUTTON_LEFT: + case BUTTON_ON | BUTTON_LEFT | BUTTON_REPEAT: +#endif + for (i=0; isplash(HZ, 0, false, "Error"); + viewer_exit(); + return PLUGIN_OK; + } + + viewer_draw(col); + while (!exit) { + button = rb->button_get(true); + + switch ( button ) { + +#ifdef HAVE_RECORDER_KEYPAD + case BUTTON_F1: + case BUTTON_OFF: +#else + case BUTTON_STOP: +#endif + viewer_exit(); + exit = true; + break; + +#ifdef HAVE_RECORDER_KEYPAD + case BUTTON_UP: + case BUTTON_UP | BUTTON_REPEAT: +#else + case BUTTON_LEFT: + case BUTTON_LEFT | BUTTON_REPEAT: +#endif + viewer_scroll_up(); + viewer_draw(col); + break; + +#ifdef HAVE_RECORDER_KEYPAD + case BUTTON_DOWN: + case BUTTON_DOWN | BUTTON_REPEAT: +#else + case BUTTON_RIGHT: + case BUTTON_RIGHT | BUTTON_REPEAT: +#endif + viewer_scroll_down(); + viewer_draw(col); + break; + +#ifdef HAVE_RECORDER_KEYPAD + case BUTTON_LEFT: + case BUTTON_LEFT | BUTTON_REPEAT: +#else + case BUTTON_MENU | BUTTON_LEFT: + case BUTTON_MENU | BUTTON_LEFT | BUTTON_REPEAT: +#endif + col--; + if (col < 0) + col = 0; + viewer_draw(col); + break; + +#ifdef HAVE_RECORDER_KEYPAD + case BUTTON_RIGHT: + case BUTTON_RIGHT | BUTTON_REPEAT: +#else + case BUTTON_MENU | BUTTON_RIGHT: + case BUTTON_MENU | BUTTON_RIGHT | BUTTON_REPEAT: +#endif + col++; + viewer_draw(col); + break; + + case BUTTON_ON: +#ifdef HAVE_PLAYER_KEYPAD + case BUTTON_ON | BUTTON_MENU: +#endif + col = pagescroll(col); + break; + + case SYS_USB_CONNECTED: + rb->usb_screen(); + viewer_exit(); + return PLUGIN_USB_CONNECTED; + } + } + return PLUGIN_OK; +} diff --git a/apps/plugins/wormlet.c b/apps/plugins/wormlet.c new file mode 100644 index 0000000000..be089cdb7c --- /dev/null +++ b/apps/plugins/wormlet.c @@ -0,0 +1,2009 @@ +/*************************************************************************** + * __________ __ ___. + * 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. + * + ****************************************************************************/ +#include "plugin.h" + +#ifdef HAVE_LCD_BITMAP + +/* size of the field the worm lives in */ +#define FIELD_RECT_X 1 +#define FIELD_RECT_Y 1 +#define FIELD_RECT_WIDTH (LCD_WIDTH - 45) +#define FIELD_RECT_HEIGHT (LCD_HEIGHT - 2) + +/* size of the ring of the worm + choos a value that is a power of 2 to help + the compiler optimize modul operations*/ +#define MAX_WORM_SEGMENTS 64 + +/* when the game starts */ +#define INITIAL_WORM_LENGTH 10 + +/* num of pixel the worm grows per eaten food */ +#define WORM_PER_FOOD 7 + +/* num of worms creeping in the FIELD */ +#define MAX_WORMS 3 + +/* minimal distance between a worm and an argh + when a new argh is made */ +#define MIN_ARGH_DIST 5 + +/** + * All the properties that a worm has. + */ +static struct worm { + /* The worm is stored in a ring of xy coordinates */ + char x[MAX_WORM_SEGMENTS]; + char y[MAX_WORM_SEGMENTS]; + + int head; /* index of the head within the buffer */ + int tail; /* index of the tail within the buffer */ + int growing; /* number of cyles the worm still keeps growing */ + bool alive; /* the worms living state */ + + /* direction vector in which the worm moves */ + int dirx; /* only values -1 0 1 allowed */ + int diry; /* only values -1 0 1 allowed */ + + /* this method is used to fetch the direction the user + has selected. It can be one of the values + human_player1, human_player2, remote_player, virtual_player. + All these values are fuctions, that can change the direction + of the worm */ + void (*fetch_worm_direction)(struct worm *w); +} worms[MAX_WORMS]; + +/* stores the highscore - besides it was scored by a virtual player */ +static int highscore; + +#define MAX_FOOD 5 /* maximal number of food items */ +#define FOOD_SIZE 3 /* the width and height of a food */ + +/* The arrays store the food coordinates */ +static char foodx[MAX_FOOD]; +static char foody[MAX_FOOD]; + +#define MAX_ARGH 100 /* maximal number of argh items */ +#define ARGH_SIZE 4 /* the width and height of a argh */ +#define ARGHS_PER_FOOD 2 /* number of arghs produced per eaten food */ + +/* The arrays store the argh coordinates */ +static char arghx[MAX_ARGH]; +static char arghy[MAX_ARGH]; + +/* the number of arghs that are currently in use */ +static int argh_count; + +#ifdef DEBUG_WORMLET +/* just a buffer used for debug output */ +static char debugout[15]; +#endif + +/* the number of ticks each game cycle should take */ +#define SPEED 14 + +/* the number of active worms (dead or alive) */ +static int worm_count = MAX_WORMS; + +/* in multiplayer mode: en- / disables the remote worm control + in singleplayer mode: toggles 4 / 2 button worm control */ +static bool use_remote = false; + +/* return values of check_collision */ +#define COLLISION_NONE 0 +#define COLLISION_WORM 1 +#define COLLISION_FOOD 2 +#define COLLISION_ARGH 3 +#define COLLISION_FIELD 4 + +/* constants for use as directions. + Note that the values are ordered clockwise. + Thus increasing / decreasing the values + is equivalent to right / left turns. */ +#define WEST 0 +#define NORTH 1 +#define EAST 2 +#define SOUTH 3 + +/* direction of human player 1 */ +static int player1_dir = EAST; +/* direction of human player 2 */ +static int player2_dir = EAST; +/* direction of human player 3 */ +static int player3_dir = EAST; + +/* the number of (human) players that currently + 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); +} +#endif + +/** + * Returns the direction id in which the worm + * currently is creeping. + * @param struct worm *w The worm that is to be investigated. + * w Must not be null. + * @return int A value 0 <= value < 4 + * Note the predefined constants NORTH, SOUTH, EAST, WEST + */ +static int get_worm_dir(struct worm *w) { + int retVal ; + if (w->dirx == 0) { + if (w->diry == 1) { + retVal = SOUTH; + } else { + retVal = NORTH; + } + } else { + if (w->dirx == 1) { + retVal = EAST; + } else { + retVal = WEST; + } + } + return retVal; +} + +/** + * Set the direction of the specified worm with a direction id. + * Increasing the value by 1 means to turn the worm direction + * to right by 90 degree. + * @param struct worm *w The worm that is to be altered. w Must not be null. + * @param int dir The new direction in which the worm is to creep. + * dir must be 0 <= dir < 4. Use predefined constants + * NORTH, SOUTH, EAST, WEST + */ +static void set_worm_dir(struct worm *w, int dir) { + switch (dir) { + case WEST: + w->dirx = -1; + w->diry = 0; + break; + case NORTH: + w->dirx = 0; + w->diry = - 1; + break; + case EAST: + w->dirx = 1; + w->diry = 0; + break; + case SOUTH: + w->dirx = 0; + w->diry = 1; + break; + } +} + +/** + * Returns the current length of the worm array. This + * is also a value for the number of bends that are in the worm. + * @return int a positive value with 0 <= value < MAX_WORM_SEGMENTS + */ +static int get_worm_array_length(struct worm *w) { + /* initial simple calculation will be overwritten if wrong. */ + int retVal = w->head - w->tail; + + /* if the worm 'crosses' the boundaries of the ringbuffer */ + if (retVal < 0) { + retVal = w->head + MAX_WORM_SEGMENTS - w->tail; + } + + return retVal; +} + +/** + * Returns the score the specified worm. The score is the length + * of the worm. + * @param struct worm *w The worm that is to be investigated. + * w must not be null. + * @return int The length of the worm (>= 0). + */ +static int get_score(struct worm *w) { + int retval = 0; + int length = get_worm_array_length(w); + int i; + for (i = 0; i < length; i++) { + + /* The iteration iterates the length of the worm. + Here's the conversion to the true indices within the worm arrays. */ + int linestart = (w->tail + i ) % MAX_WORM_SEGMENTS; + int lineend = (linestart + 1) % MAX_WORM_SEGMENTS; + int startx = w->x[linestart]; + int starty = w->y[linestart]; + int endx = w->x[lineend]; + int endy = w->y[lineend]; + + int minimum, maximum; + + if (startx == endx) { + minimum = MIN(starty, endy); + maximum = MAX(starty, endy); + } else { + minimum = MIN(startx, endx); + maximum = MAX(startx, endx); + } + retval += abs(maximum - minimum); + } + return retval; +} + +/** + * Determines wether the line specified by startx, starty, endx, endy intersects + * the rectangle specified by x, y, width, height. Note that the line must be exactly + * horizontal or vertical (startx == endx or starty == endy). + * @param int startx The x coordinate of the start point of the line. + * @param int starty The y coordinate of the start point of the line. + * @param int endx The x coordinate of the end point of the line. + * @param int endy The y coordinate of the end point of the line. + * @param int x The x coordinate of the top left corner of the rectangle. + * @param int y The y coordinate of the top left corner of the rectangle. + * @param int width The width of the rectangle. + * @param int height The height of the rectangle. + * @return bool Returns true if the specified line intersects with the recangle. + */ +static bool line_in_rect(int startx, int starty, int endx, int endy, int x, int y, int width, int height) { + bool retval = false; + int simple, simplemin, simplemax; + int compa, compb, compmin, compmax; + int temp; + if (startx == endx) { + simple = startx; + simplemin = x; + simplemax = x + width; + + compa = starty; + compb = endy; + compmin = y; + compmax = y + height; + } else { + simple = starty; + simplemin = y; + simplemax = y + height; + + compa = startx; + compb = endx; + compmin = x; + compmax = x + width; + }; + + temp = compa; + compa = MIN(compa, compb); + compb = MAX(temp, compb); + + if (simplemin <= simple && simple <= simplemax) { + if ((compmin <= compa && compa <= compmax) || + (compmin <= compb && compb <= compmax) || + (compa <= compmin && compb >= compmax)) { + retval = true; + } + } + return retval; +} + +/** + * Tests wether the specified worm intersects with the rect. + * @param struct worm *w The worm to be investigated + * @param int x The x coordinate of the top left corner of the rect + * @param int y The y coordinate of the top left corner of the rect + * @param int widht The width of the rect + * @param int height The height of the rect + * @return bool Returns true if the worm intersects with the rect + */ +static bool worm_in_rect(struct worm *w, int x, int y, int width, int height) { + bool retval = false; + + + /* get_worm_array_length is expensive -> buffer the value */ + int wormLength = get_worm_array_length(w); + int i; + + /* test each entry that is part of the worm */ + for (i = 0; i < wormLength && retval == false; i++) { + + /* The iteration iterates the length of the worm. + Here's the conversion to the true indices within the worm arrays. */ + int linestart = (w->tail + i ) % MAX_WORM_SEGMENTS; + int lineend = (linestart + 1) % MAX_WORM_SEGMENTS; + int startx = w->x[linestart]; + int starty = w->y[linestart]; + int endx = w->x[lineend]; + int endy = w->y[lineend]; + + retval = line_in_rect(startx, starty, endx, endy, x, y, width, height); + } + + return retval; +} + +/** + * Checks wether a specific food in the food arrays is at the + * specified coordinates. + * @param int foodIndex The index of the food in the food arrays + * @param int x the x coordinate. + * @param int y the y coordinate. + * @return Returns true if the coordinate hits the food specified by + * foodIndex. + */ +static bool specific_food_collision(int foodIndex, int x, int y) { + bool retVal = false; + if (x >= foodx[foodIndex] && + x < foodx[foodIndex] + FOOD_SIZE && + y >= foody[foodIndex] && + y < foody[foodIndex] + FOOD_SIZE) { + + retVal = true; + } + return retVal; +} + +/** + * Returns the index of the food that is at the + * given coordinates. If no food is at the coordinates + * -1 is returned. + * @return int -1 <= value < MAX_FOOD + */ +static int food_collision(int x, int y) { + int i = 0; + int retVal = -1; + for (i = 0; i < MAX_FOOD; i++) { + if (specific_food_collision(i, x, y)) { + retVal = i; + break; + } + } + return retVal; +} + +/** + * Checks wether a specific argh in the argh arrays is at the + * specified coordinates. + * @param int arghIndex The index of the argh in the argh arrays + * @param int x the x coordinate. + * @param int y the y coordinate. + * @return Returns true if the coordinate hits the argh specified by + * arghIndex. + */ +static bool specific_argh_collision(int arghIndex, int x, int y) { + + if ( x >= arghx[arghIndex] && + y >= arghy[arghIndex] && + x < arghx[arghIndex] + ARGH_SIZE && + y < arghy[arghIndex] + ARGH_SIZE ) + { + return true; + } + + return false; +} + +/** + * Returns the index of the argh that is at the + * given coordinates. If no argh is at the coordinates + * -1 is returned. + * @param int x The x coordinate. + * @param int y The y coordinate. + * @return int -1 <= value < argh_count <= MAX_ARGH + */ +static int argh_collision(int x, int y) { + int i = 0; + int retVal = -1; + + /* search for the argh that has the specified coords */ + for (i = 0; i < argh_count; i++) { + if (specific_argh_collision(i, x, y)) { + retVal = i; + break; + } + } + return retVal; +} + +/** + * Checks wether the worm collides with the food at the specfied food-arrays. + * @param int foodIndex The index of the food in the arrays. Ensure the value is + * 0 <= foodIndex <= MAX_FOOD + * @return Returns true if the worm collides with the specified food. + */ +static bool worm_food_collision(struct worm *w, int foodIndex) +{ + bool retVal = false; + + retVal = worm_in_rect(w, foodx[foodIndex], foody[foodIndex], + FOOD_SIZE - 1, FOOD_SIZE - 1); + + return retVal; +} + +/** + * Returns true if the worm hits the argh within the next moves (unless + * the worm changes it's direction). + * @param struct worm *w - The worm to investigate + * @param int argh_idx - The index of the argh + * @param int moves - The number of moves that are considered. + * @return Returns false if the specified argh is not hit within the next + * moves. + */ +static bool worm_argh_collision_in_moves(struct worm *w, int argh_idx, int moves){ + bool retVal = false; + int x1, y1, x2, y2; + x1 = w->x[w->head]; + y1 = w->y[w->head]; + + x2 = w->x[w->head] + moves * w->dirx; + y2 = w->y[w->head] + moves * w->diry; + + retVal = line_in_rect(x1, y1, x2, y2, arghx[argh_idx], arghy[argh_idx], + ARGH_SIZE, ARGH_SIZE); + return retVal; +} + +/** + * Checks wether the worm collides with the argh at the specfied argh-arrays. + * @param int arghIndex The index of the argh in the arrays. + * Ensure the value is 0 <= arghIndex < argh_count <= MAX_ARGH + * @return Returns true if the worm collides with the specified argh. + */ +static bool worm_argh_collision(struct worm *w, int arghIndex) +{ + bool retVal = false; + + retVal = worm_in_rect(w, arghx[arghIndex], arghy[arghIndex], + ARGH_SIZE - 1, ARGH_SIZE - 1); + + return retVal; +} + +/** + * Find new coordinates for the food stored in foodx[index], foody[index] + * that don't collide with any other food or argh + * @param int index + * Ensure that 0 <= index < MAX_FOOD. + */ +static int make_food(int index) { + + int x = 0; + int y = 0; + bool collisionDetected = false; + int tries = 0; + int i; + + do { + /* make coordinates for a new food so that + the entire food lies within the FIELD */ + 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 + existing foods or arghs. + If one or more corners of the new food hit any existing + argh or food a collision is detected. + */ + collisionDetected = + food_collision(x , y ) >= 0 || + food_collision(x , y + FOOD_SIZE - 1) >= 0 || + food_collision(x + FOOD_SIZE - 1, y ) >= 0 || + food_collision(x + FOOD_SIZE - 1, y + FOOD_SIZE - 1) >= 0 || + argh_collision(x , y ) >= 0 || + argh_collision(x , y + FOOD_SIZE - 1) >= 0 || + argh_collision(x + FOOD_SIZE - 1, y ) >= 0 || + argh_collision(x + FOOD_SIZE - 1, y + FOOD_SIZE - 1) >= 0; + + /* use coordinates for further testing */ + foodx[index] = x; + foody[index] = y; + + /* now test wether we accidently hit the worm with food ;) */ + i = 0; + for (i = 0; i < worm_count && !collisionDetected; i++) { + collisionDetected |= worm_food_collision(&worms[i], index); + } + } + while (collisionDetected); + return tries; +} + +/** + * Clears a food from the lcd buffer. + * @param int index The index of the food arrays under which + * the coordinates of the desired food can be found. Ensure + * that the value is 0 <= index <= MAX_FOOD. + */ +static void clear_food(int index) +{ + /* remove the old food from the screen */ + rb->lcd_clearrect(foodx[index] + FIELD_RECT_X, + foody[index] + FIELD_RECT_Y, + FOOD_SIZE, FOOD_SIZE); +} + +/** + * Draws a food in the lcd buffer. + * @param int index The index of the food arrays under which + * the coordinates of the desired food can be found. Ensure + * that the value is 0 <= index <= MAX_FOOD. + */ +static void draw_food(int index) +{ + /* draw the food object */ + rb->lcd_fillrect(foodx[index] + FIELD_RECT_X, + foody[index] + FIELD_RECT_Y, + FOOD_SIZE, FOOD_SIZE); + rb->lcd_clearrect(foodx[index] + FIELD_RECT_X + 1, + foody[index] + FIELD_RECT_Y + 1, + FOOD_SIZE - 2, FOOD_SIZE - 2); +} + +/** + * Find new coordinates for the argh stored in arghx[index], arghy[index] + * that don't collide with any other food or argh. + * @param int index + * Ensure that 0 <= index < argh_count < MAX_ARGH. + */ +static int make_argh(int index) +{ + int x = -1; + int y = -1; + bool collisionDetected = false; + int tries = 0; + int i; + + do { + /* make coordinates for a new argh so that + the entire food lies within the FIELD */ + 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 + existing foods or arghs. + If one or more corners of the new argh hit any existing + argh or food an intersection is detected. + */ + collisionDetected = + food_collision(x , y ) >= 0 || + food_collision(x , y + ARGH_SIZE - 1) >= 0 || + food_collision(x + ARGH_SIZE - 1, y ) >= 0 || + food_collision(x + ARGH_SIZE - 1, y + ARGH_SIZE - 1) >= 0 || + argh_collision(x , y ) >= 0 || + argh_collision(x , y + ARGH_SIZE - 1) >= 0 || + argh_collision(x + ARGH_SIZE - 1, y ) >= 0 || + argh_collision(x + ARGH_SIZE - 1, y + ARGH_SIZE - 1) >= 0; + + /* use the candidate coordinates to make a real argh */ + arghx[index] = x; + arghy[index] = y; + + /* now test wether we accidently hit the worm with argh ;) */ + for (i = 0; i < worm_count && !collisionDetected; i++) { + collisionDetected |= worm_argh_collision(&worms[i], index); + collisionDetected |= worm_argh_collision_in_moves(&worms[i], index, + MIN_ARGH_DIST); + } + } + while (collisionDetected); + return tries; +} + +/** + * Draws an argh in the lcd buffer. + * @param int index The index of the argh arrays under which + * the coordinates of the desired argh can be found. Ensure + * that the value is 0 <= index < argh_count <= MAX_ARGH. + */ +static void draw_argh(int index) +{ + /* draw the new argh */ + rb->lcd_fillrect(arghx[index] + FIELD_RECT_X, + arghy[index] + FIELD_RECT_Y, + ARGH_SIZE, ARGH_SIZE); +} + +static void virtual_player(struct worm *w); +/** + * Initialzes the specified worm with INITIAL_WORM_LENGTH + * and the tail at the specified position. The worm will + * be initialized alive and creeping EAST. + * @param struct worm *w The worm that is to be initialized + * @param int x The x coordinate at which the tail of the worm starts. + * x must be 0 <= x < FIELD_RECT_WIDTH. + * @param int y The y coordinate at which the tail of the worm starts + * y must be 0 <= y < FIELD_RECT_WIDTH. + */ +static void init_worm(struct worm *w, int x, int y){ + /* initialize the worm size */ + w->head = 1; + w->tail = 0; + + w->x[w->head] = x + 1; + w->y[w->head] = y; + + w->x[w->tail] = x; + w->y[w->tail] = y; + + /* set the initial direction the worm creeps to */ + w->dirx = 1; + w->diry = 0; + + w->growing = INITIAL_WORM_LENGTH - 1; + w->alive = true; + w->fetch_worm_direction = virtual_player; +} + +/** + * Writes the direction that was stored for + * human player 1 into the specified worm. This function + * may be used to be stored in worm.fetch_worm_direction. + * The value of + * the direction is read from player1_dir. + * @param struct worm *w - The worm of which the direction + * is altered. + */ +static void human_player1(struct worm *w) { + set_worm_dir(w, player1_dir); +} + +/** + * Writes the direction that was stored for + * human player 2 into the specified worm. This function + * may be used to be stored in worm.fetch_worm_direction. + * The value of + * the direction is read from player2_dir. + * @param struct worm *w - The worm of which the direction + * is altered. + */ +static void human_player2(struct worm *w) { + set_worm_dir(w, player2_dir); +} + +/** + * Writes the direction that was stored for + * human player using a remote control + * into the specified worm. This function + * may be used to be stored in worm.fetch_worm_direction. + * The value of + * the direction is read from player3_dir. + * @param struct worm *w - The worm of which the direction + * is altered. + */ +static void remote_player(struct worm *w) { + set_worm_dir(w, player3_dir); +} + +/** + * Initializes the worm-, food- and argh-arrays, draws a frame, + * makes some food and argh and display all that stuff. + */ +static void init_wormlet(void) +{ + int i; + + for (i = 0; i< worm_count; i++) { + /* Initialize all the worm coordinates to center. */ + int x = (int)(FIELD_RECT_WIDTH / 2); + int y = (int)((FIELD_RECT_HEIGHT - 20)/ 2) + i * 10; + + init_worm(&worms[i], x, y); + } + + player1_dir = EAST; + player2_dir = EAST; + player3_dir = EAST; + + if (players > 0) { + worms[0].fetch_worm_direction = human_player1; + } + + if (players > 1) { + if (use_remote) { + worms[1].fetch_worm_direction = remote_player; + } else { + worms[1].fetch_worm_direction = human_player2; + } + } + + if (players > 2) { + worms[2].fetch_worm_direction = human_player2; + } + + /* Needed when the game is restarted using BUTTON_ON */ + rb->lcd_clear_display(); + + /* make and display some food and argh */ + argh_count = MAX_FOOD; + for (i = 0; i < MAX_FOOD; i++) { + make_food(i); + draw_food(i); + make_argh(i); + draw_argh(i); + } + + /* draw the game field */ + 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 */ + rb->lcd_update(); +} + + +/** + * Move the worm one step further if it is alive. + * The direction in which the worm moves is taken from dirx and diry. + * move_worm decreases growing if > 0. While the worm is growing the tail + * is left untouched. + * @param struct worm *w The worm to move. w must not be NULL. + */ +static void move_worm(struct worm *w) +{ + if (w->alive) { + /* determine the head point and its precessor */ + int headx = w->x[w->head]; + int heady = w->y[w->head]; + int prehead = (w->head + MAX_WORM_SEGMENTS - 1) % MAX_WORM_SEGMENTS; + int preheadx = w->x[prehead]; + int preheady = w->y[prehead]; + + /* determine the old direction */ + int olddirx; + int olddiry; + if (headx == preheadx) { + olddirx = 0; + olddiry = (heady > preheady) ? 1 : -1; + } else { + olddiry = 0; + olddirx = (headx > preheadx) ? 1 : -1; + } + + /* olddir == dir? + a change of direction means a new segment + has been opened */ + if (olddirx != w->dirx || + olddiry != w->diry) { + w->head = (w->head + 1) % MAX_WORM_SEGMENTS; + } + + /* new head position */ + w->x[w->head] = headx + w->dirx; + w->y[w->head] = heady + w->diry; + + + /* while the worm is growing no tail procession is necessary */ + if (w->growing > 0) { + /* update the worms grow state */ + w->growing--; + } + + /* if the worm isn't growing the tail has to be dragged */ + else { + /* index of the end of the tail segment */ + int tail_segment_end = (w->tail + 1) % MAX_WORM_SEGMENTS; + + /* drag the end of the tail */ + /* only one coordinate has to be altered. Here it is + determined which one */ + int dir = 0; /* specifies wether the coord has to be in- or decreased */ + if (w->x[w->tail] == w->x[tail_segment_end]) { + dir = (w->y[w->tail] - w->y[tail_segment_end] < 0) ? 1 : -1; + w->y[w->tail] += dir; + } else { + dir = (w->x[w->tail] - w->x[tail_segment_end] < 0) ? 1 : -1; + w->x[w->tail] += dir; + } + + /* when the tail has been dragged so far that it meets + the next segment start the tail segment is obsolete and + must be freed */ + if (w->x[w->tail] == w->x[tail_segment_end] && + w->y[w->tail] == w->y[tail_segment_end]){ + + /* drop the last tail point */ + w->tail = tail_segment_end; + } + } + } +} + +/** + * Draws the head and clears the tail of the worm in + * the display buffer. lcd_update() is NOT called thus + * the caller has to take care that the buffer is displayed. + */ +static void draw_worm(struct worm *w) +{ + /* draw the new head */ + 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) { + 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) { + rb->lcd_clearpixel(x + FIELD_RECT_X, y + FIELD_RECT_Y); + } +} + +/** + * Checks wether the coordinate is part of the worm. Returns + * true if any part of the worm was hit - including the head. + * @param x int The x coordinate + * @param y int The y coordinate + * @return int The index of the worm arrays that contain x, y. + * Returns -1 if the coordinates are not part of the worm. + */ +static int specific_worm_collision(struct worm *w, int x, int y) +{ + int retVal = -1; + + /* get_worm_array_length is expensive -> buffer the value */ + int wormLength = get_worm_array_length(w); + int i; + + /* test each entry that is part of the worm */ + for (i = 0; i < wormLength && retVal == -1; i++) { + + /* The iteration iterates the length of the worm. + Here's the conversion to the true indices within the worm arrays. */ + int linestart = (w->tail + i ) % MAX_WORM_SEGMENTS; + int lineend = (linestart + 1) % MAX_WORM_SEGMENTS; + bool samex = (w->x[linestart] == x) && (w->x[lineend] == x); + bool samey = (w->y[linestart] == y) && (w->y[lineend] == y); + if (samex || samey){ + int test, min, max, tmp; + + if (samey) { + min = w->x[linestart]; + max = w->x[lineend]; + test = x; + } else { + min = w->y[linestart]; + max = w->y[lineend]; + test = y; + } + + tmp = min; + min = MIN(min, max); + max = MAX(tmp, max); + + if (min <= test && test <= max) { + retVal = lineend; + } + } + } + return retVal; +} + +/** + * Increases the length of the specified worm by marking + * that it may grow by len pixels. Note that the worm has + * to move to make the growing happen. + * @param worm *w The worm that is to be altered. + * @param int len A positive value specifying the amount of + * pixels the worm may grow. + */ +static void add_growing(struct worm *w, int len) { + w->growing += len; +} + +/** + * Determins the worm that is at the coordinates x, y. The parameter + * w is a switch parameter that changes the functionality of worm_collision. + * If w is specified and x,y hits the head of w NULL is returned. + * This is a useful way to determine wether the head of w hits + * any worm but including itself but excluding its own head. + * (It hits always its own head ;)) + * If w is set to NULL worm_collision returns any worm including all heads + * that is at position of x,y. + * @param struct worm *w The worm of which the head should be excluded in + * the test. w may be set to NULL. + * @param int x The x coordinate that is checked + * @param int y The y coordinate that is checkec + * @return struct worm* The worm that has been hit by x,y. If no worm + * was at the position NULL is returned. + */ +static struct worm* worm_collision(struct worm *w, int x, int y){ + struct worm *retVal = NULL; + int i; + for (i = 0; (i < worm_count) && (retVal == NULL); i++) { + int collision_at = specific_worm_collision(&worms[i], x, y); + if (collision_at != -1) { + if (!(w == &worms[i] && collision_at == w->head)){ + retVal = &worms[i]; + } + } + } + return retVal; +} + +/** + * Returns true if the head of the worm just has + * crossed the field boundaries. + * @return bool true if the worm just has wrapped. + */ +static bool field_collision(struct worm *w) +{ + bool retVal = false; + if ((w->x[w->head] >= FIELD_RECT_WIDTH) || + (w->y[w->head] >= FIELD_RECT_HEIGHT) || + (w->x[w->head] < 0) || + (w->y[w->head] < 0)) + { + retVal = true; + } + return retVal; +} + + +/** + * Returns true if the specified coordinates are within the + * field specified by the FIELD_RECT_XXX constants. + * @param int x The x coordinate of the point that is investigated + * @param int y The y coordinate of the point that is investigated + * @return bool Returns false if x,y specifies a point outside the + * field of worms. + */ +static bool is_in_field_rect(int x, int y) { + bool retVal = false; + retVal = (x >= 0 && x < FIELD_RECT_WIDTH && + y >= 0 && y < FIELD_RECT_HEIGHT); + return retVal; +} + +/** + * Checks and returns wether the head of the w + * is colliding with something currently. + * @return int One of the values: + * COLLISION_NONE + * COLLISION_w + * COLLISION_FOOD + * COLLISION_ARGH + * COLLISION_FIELD + */ +static int check_collision(struct worm *w) +{ + int retVal = COLLISION_NONE; + + if (worm_collision(w, w->x[w->head], w->y[w->head]) != NULL) + retVal = COLLISION_WORM; + + if (food_collision(w->x[w->head], w->y[w->head]) >= 0) + retVal = COLLISION_FOOD; + + if (argh_collision(w->x[w->head], w->y[w->head]) >= 0) + retVal = COLLISION_ARGH; + + if (field_collision(w)) + retVal = COLLISION_FIELD; + + return retVal; +} + +/** + * Returns the index of the food that is closest to the point + * specified by x, y. This index may be used in the foodx and + * foody arrays. + * @param int x The x coordinate of the point + * @param int y The y coordinate of the point + * @return int A value usable as index in foodx and foody. + */ +static int get_nearest_food(int x, int y){ + int nearestfood = 0; + int olddistance = FIELD_RECT_WIDTH + FIELD_RECT_HEIGHT; + int deltax = 0; + int deltay = 0; + int foodindex; + for (foodindex = 0; foodindex < MAX_FOOD; foodindex++) { + int distance; + deltax = foodx[foodindex] - x; + deltay = foody[foodindex] - y; + deltax = deltax > 0 ? deltax : deltax * (-1); + deltay = deltay > 0 ? deltay : deltay * (-1); + distance = deltax + deltay; + + if (distance < olddistance) { + olddistance = distance; + nearestfood = foodindex; + } + } + return nearestfood; +} + +/** + * Returns wether the specified position is next to the worm + * and in the direction the worm looks. Use this method to + * test wether this position would be hit with the next move of + * the worm unless the worm changes its direction. + * @param struct worm *w - The worm to be investigated + * @param int x - The x coordinate of the position to test. + * @param int y - The y coordinate of the position to test. + * @return Returns true if the worm will hit the position unless + * it change its direction before the next move. + */ +static bool is_in_front_of_worm(struct worm *w, int x, int y) { + bool infront = false; + int deltax = x - w->x[w->head]; + int deltay = y - w->y[w->head]; + + if (w->dirx == 0) { + infront = (w->diry * deltay) > 0; + } else { + infront = (w->dirx * deltax) > 0; + } + return infront; +} + +/** + * Returns true if the worm will collide with the next move unless + * it changes its direction. + * @param struct worm *w - The worm to be investigated. + * @return Returns true if the worm will collide with the next move + * unless it changes its direction. + */ +static bool will_worm_collide(struct worm *w) { + int x = w->x[w->head] + w->dirx; + int y = w->y[w->head] + w->diry; + bool retVal = !is_in_field_rect(x, y); + if (!retVal) { + retVal = (argh_collision(x, y) != -1); + } + + if (!retVal) { + retVal = (worm_collision(w, x, y) != NULL); + } + return retVal; +} + +/** + * This function + * may be used to be stored in worm.fetch_worm_direction for + * worms that are not controlled by humans but by artificial stupidity. + * A direction is searched that doesn't lead to collision but to the nearest + * food - but not very intelligent. The direction is written to the specified + * worm. + * @param struct worm *w - The worm of which the direction + * is altered. + */ +static void virtual_player(struct worm *w) { + bool isright; + int plana, planb, planc; + /* find the next lunch */ + int nearestfood = get_nearest_food(w->x[w->head], w->y[w->head]); + + /* determine in which direction it is */ + + /* in front of me? */ + bool infront = is_in_front_of_worm(w, foodx[nearestfood], foody[nearestfood]); + + /* left right of me? */ + int olddir = get_worm_dir(w); + set_worm_dir(w, (olddir + 1) % 4); + isright = is_in_front_of_worm(w, foodx[nearestfood], foody[nearestfood]); + set_worm_dir(w, olddir); + + /* detect situation, set strategy */ + if (infront) { + if (isright) { + plana = olddir; + planb = (olddir + 1) % 4; + planc = (olddir + 3) % 4; + } else { + plana = olddir; + planb = (olddir + 3) % 4; + planc = (olddir + 1) % 4; + } + } else { + if (isright) { + plana = (olddir + 1) % 4; + planb = olddir; + planc = (olddir + 3) % 4; + } else { + plana = (olddir + 3) % 4; + planb = olddir; + planc = (olddir + 1) % 4; + } + } + + /* test for collision */ + set_worm_dir(w, plana); + if (will_worm_collide(w)){ + + /* plan b */ + set_worm_dir(w, planb); + + /* test for collision */ + if (will_worm_collide(w)) { + + /* plan c */ + set_worm_dir(w, planc); + } + } +} + +/** + * prints out the score board with all the status information + * about the game. + */ +static void score_board(void) +{ + char buf[15]; + char* buf2 = NULL; + int i; + int y = 0; + 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]); + + /* high score */ + if (worms[i].fetch_worm_direction != virtual_player){ + if (highscore < score) { + highscore = 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) + buf2 = "Growing"; + else { + if (worms[i].alive) + buf2 = "Hungry"; + else + buf2 = "Wormed"; + } + break; + + case COLLISION_WORM: + buf2 = "Wormed"; + break; + + case COLLISION_FOOD: + buf2 = "Growing"; + break; + + case COLLISION_ARGH: + buf2 = "Argh"; + break; + + 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){ + rb->lcd_invertrect(FIELD_RECT_WIDTH + 2, y, + LCD_WIDTH - FIELD_RECT_WIDTH - 2, 17); + } + y += 19; + } + rb->snprintf(buf , sizeof(buf), "Hs: %d", highscore); +#ifndef DEBUG_WORMLET + rb->lcd_putsxy(FIELD_RECT_WIDTH + 3, LCD_HEIGHT - 8, buf); +#else + rb->lcd_putsxy(FIELD_RECT_WIDTH + 3, LCD_HEIGHT - 8, debugout); +#endif +} + +/** + * Checks for collisions of the worm and its environment and + * takes appropriate actions like growing the worm or killing it. + * @return bool Returns true if the worm is dead. Returns + * false if the worm is healthy, up and creeping. + */ +static bool process_collisions(struct worm *w) +{ + int index = -1; + + w->alive &= !field_collision(w); + + if (w->alive) { + + /* check if food was eaten */ + index = food_collision(w->x[w->head], w->y[w->head]); + if (index != -1){ + int i; + + clear_food(index); + make_food(index); + draw_food(index); + + for (i = 0; i < ARGHS_PER_FOOD; i++) { + argh_count++; + if (argh_count > MAX_ARGH) + argh_count = MAX_ARGH; + make_argh(argh_count - 1); + draw_argh(argh_count - 1); + } + + add_growing(w, WORM_PER_FOOD); + + draw_worm(w); + } + + /* check if argh was eaten */ + else { + index = argh_collision(w->x[w->head], w->y[w->head]); + if (index != -1) { + w->alive = false; + } + else { + if (worm_collision(w, w->x[w->head], w->y[w->head]) != NULL) { + w->alive = false; + } + } + } + } + return !w->alive; +} + +/** + * The main loop of the game. + * @return bool Returns true if the game ended + * with a dead worm. Returns false if the user + * aborted the game manually. + */ +static bool run(void) +{ + int button = 0; + int wormDead = false; + + /* ticks are counted to compensate speed variations */ + long cycle_start = 0, cycle_end = 0; +#ifdef DEBUG_WORMLET + int ticks_to_max_cycle_reset = 20; + long max_cycle = 0; + char buf[20]; +#endif + + /* initialize the board and so on */ + init_wormlet(); + + cycle_start = *rb->current_tick; + /* change the direction of the worm */ + while (button != BUTTON_OFF && ! wormDead) + { + int i; + long cycle_duration ; + switch (button) { + case BUTTON_UP: + if (players == 1 && !use_remote) { + player1_dir = NORTH; + } + break; + + case BUTTON_DOWN: + if (players == 1 && !use_remote) { + player1_dir = SOUTH; + } + break; + + case BUTTON_LEFT: + if (players != 1 || use_remote) { + player1_dir = (player1_dir + 3) % 4; + } else { + player1_dir = WEST; + } + break; + + case BUTTON_RIGHT: + if (players != 1 || use_remote) { + player1_dir = (player1_dir + 1) % 4; + } else { + player1_dir = EAST; + } + break; + + case BUTTON_F2: + player2_dir = (player2_dir + 3) % 4; + break; + + case BUTTON_F3: + player2_dir = (player2_dir + 1) % 4; + break; + + case BUTTON_RC_VOL_UP: + player3_dir = (player3_dir + 1) % 4; + break; + + case BUTTON_RC_VOL_DOWN: + player3_dir = (player3_dir + 3) % 4; + break; + + case BUTTON_PLAY: + do { + button = rb->button_get(true); + } while (button != BUTTON_PLAY && + button != BUTTON_OFF && + button != BUTTON_ON); + break; + } + + for (i = 0; i < worm_count; i++) { + worms[i].fetch_worm_direction(&worms[i]); + } + + wormDead = true; + for (i = 0; i < worm_count; i++){ + struct worm *w = &worms[i]; + move_worm(w); + wormDead &= process_collisions(w); + draw_worm(w); + } + score_board(); + rb->lcd_update(); + if (button == BUTTON_ON) { + wormDead = true; + } + + /* here the wormlet game cycle ends + thus the current tick is stored + as end time */ + cycle_end = *rb->current_tick; + + /* The duration of the game cycle */ + cycle_duration = cycle_end - cycle_start; + cycle_duration = MAX(0, cycle_duration); + cycle_duration = MIN(SPEED -1, cycle_duration); + + +#ifdef DEBUG_WORMLET + ticks_to_max_cycle_reset--; + if (ticks_to_max_cycle_reset <= 0) { + max_cycle = 0; + } + + if (max_cycle < cycle_duration) { + max_cycle = cycle_duration; + ticks_to_max_cycle_reset = 20; + } + 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 = rb->button_get_w_tmo(SPEED - cycle_duration); + cycle_start = *rb->current_tick; + } + return wormDead; +} + +#ifdef DEBUG_WORMLET + +/** + * Just a test routine that checks that worm_food_collision works + * in some typical situations. + */ +static void test_worm_food_collision(void) { + int collision_count = 0; + int i; + rb->lcd_clear_display(); + init_worm(&worms[0], 10, 10); + add_growing(&worms[0], 10); + set_worm_dir(&worms[0], EAST); + for (i = 0; i < 10; i++) { + move_worm(&worms[0]); + draw_worm(&worms[0]); + } + + set_worm_dir(&worms[0], SOUTH); + for (i = 0; i < 10; i++) { + move_worm(&worms[0]); + draw_worm(&worms[0]); + } + + foodx[0] = 15; + foody[0] = 12; + for (foody[0] = 20; foody[0] > 0; foody[0] --) { + char buf[20]; + bool collision; + draw_worm(&worms[0]); + draw_food(0); + collision = worm_food_collision(&worms[0], 0); + if (collision) { + collision_count++; + } + 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) { + rb->button_get(true); + } + + + foody[0] = 15; + for (foodx[0] = 30; foodx[0] > 0; foodx[0] --) { + char buf[20]; + bool collision; + draw_worm(&worms[0]); + draw_food(0); + collision = worm_food_collision(&worms[0], 0); + if (collision) { + collision_count ++; + } + 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) { + rb->button_get(true); + } + +} + + +static bool expensive_worm_in_rect(struct worm *w, int rx, int ry, int rw, int rh){ + int x, y; + bool retVal = false; + for (x = rx; x < rx + rw; x++){ + for (y = ry; y < ry + rh; y++) { + if (specific_worm_collision(w, x, y) != -1) { + retVal = true; + } + } + } + return retVal; +} + +static void test_worm_argh_collision(void) { + int i; + int dir; + int collision_count = 0; + rb->lcd_clear_display(); + init_worm(&worms[0], 10, 10); + add_growing(&worms[0], 40); + for (dir = 0; dir < 4; dir++) { + set_worm_dir(&worms[0], (EAST + dir) % 4); + for (i = 0; i < 10; i++) { + move_worm(&worms[0]); + draw_worm(&worms[0]); + } + } + + arghx[0] = 12; + for (arghy[0] = 0; arghy[0] < FIELD_RECT_HEIGHT - ARGH_SIZE; arghy[0]++){ + char buf[20]; + bool collision; + draw_argh(0); + collision = worm_argh_collision(&worms[0], 0); + if (collision) { + collision_count ++; + } + 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) { + rb->button_get(true); + } + + arghy[0] = 12; + for (arghx[0] = 0; arghx[0] < FIELD_RECT_HEIGHT - ARGH_SIZE; arghx[0]++){ + char buf[20]; + bool collision; + draw_argh(0); + collision = worm_argh_collision(&worms[0], 0); + if (collision) { + collision_count ++; + } + 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) { + rb->button_get(true); + } +} + +static int testline_in_rect(void) { + int testfailed = -1; + + int rx = 10; + int ry = 15; + int rw = 20; + int rh = 25; + + /* Test 1 */ + int x1 = 12; + int y1 = 8; + int x2 = 12; + int y2 = 42; + + if (!line_in_rect(x1, y1, x2, y2, rx, ry, rw, rh) && + !line_in_rect(x2, y2, x1, y1, rx, ry, rw, rh)) { + 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; + } + + /* test 2 */ + 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)) { + 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; + } + + /* test 3 */ + 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)) { + 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; + } + + /* test 4 */ + 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)) { + 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; + } + + /* test 5 */ + 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)) { + 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; + } + + /* test 6 */ + y1 = 5; + 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)) { + 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; + } + + /* test 7 */ + x1 = 8; + y1 = 20; + x2 = 35; + 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)) { + 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; + } + + /* test 8 */ + 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)) { + 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; + } + + /* test 9 */ + 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)) { + 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; + } + + /* test 10 */ + 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)) { + 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; + } + + /* test 11 */ + 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)) { + 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; + } + + /* test 12 */ + x1 = 5; + 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)) { + 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; + } + + /* test 13 */ + rx = 9; + ry = 15; + rw = FOOD_SIZE; + rh = FOOD_SIZE; + + x1 = 10; + y1 = 10; + x2 = 10; + 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))) { + 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; + } + + /* test 14 */ + rx = 9; + ry = 15; + rw = 4; + rh = 4; + + x1 = 10; + y1 = 10; + x2 = 10; + 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))) { + 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; + } + + rb->lcd_clear_display(); + + return testfailed; +} + +/** + * Just a test routine to test wether specific_worm_collision might work properly + */ +static int test_specific_worm_collision(void) { + int collisions = 0; + int dir; + int x = 0; + int y = 0; + char buf[20]; + rb->lcd_clear_display(); + init_worm(&worms[0], 10, 20); + add_growing(&worms[0], 20 - INITIAL_WORM_LENGTH); + + for (dir = EAST; dir < EAST + 4; dir++) { + int i; + set_worm_dir(&worms[0], dir % 4); + for (i = 0; i < 5; i++) { + if (!(dir % 4 == NORTH && i == 9)) { + move_worm(&worms[0]); + draw_worm(&worms[0]); + } + } + } + + for (y = 15; y < 30; y ++){ + for (x = 5; x < 20; x++) { + if (specific_worm_collision(&worms[0], x, y) != -1) { + collisions ++; + } + 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) { + rb->button_get(true); + } + return collisions; +} + +static void test_make_argh(void){ + int dir; + int seed = 0; + int hit = 0; + int failures = 0; + int last_failures = 0; + int i, worm_idx; + rb->lcd_clear_display(); + worm_count = 3; + + for (worm_idx = 0; worm_idx < worm_count; worm_idx++) { + init_worm(&worms[worm_idx], 10 + worm_idx * 20, 20); + add_growing(&worms[worm_idx], 40 - INITIAL_WORM_LENGTH); + } + + for (dir = EAST; dir < EAST + 4; dir++) { + for (worm_idx = 0; worm_idx < worm_count; worm_idx++) { + set_worm_dir(&worms[worm_idx], dir % 4); + for (i = 0; i < 10; i++) { + if (!(dir % 4 == NORTH && i == 9)) { + move_worm(&worms[worm_idx]); + draw_worm(&worms[worm_idx]); + } + } + } + } + + rb->lcd_update(); + + for (seed = 0; hit < 20; seed += 2) { + char buf[20]; + int x, y; + 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; + rb->srand(seed); + + tries = make_argh(0); + if ((x == arghx[0] && y == arghy[0]) || tries < 2) { + failures ++; + } + + 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); + 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) { + rb->button_get(true); + } + last_failures = failures; + hit ++; + } + } + } +} + +static void test_worm_argh_collision_in_moves(void) { + int hit_count = 0; + int i; + rb->lcd_clear_display(); + init_worm(&worms[0], 10, 20); + + arghx[0] = 20; + arghy[0] = 18; + draw_argh(0); + + set_worm_dir(&worms[0], EAST); + for (i = 0; i < 20; i++) { + char buf[20]; + move_worm(&worms[0]); + draw_worm(&worms[0]); + if (worm_argh_collision_in_moves(&worms[0], 0, 5)){ + hit_count ++; + } + 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) { + rb->button_get(true); + } +} +#endif /* DEBUG_WORMLET */ + +extern bool use_old_rect; + +/** + * Main entry point + */ +enum plugin_status plugin_start(struct plugin_api* api, void* parameter) +{ + bool worm_dead = false; + int button; + + TEST_PLUGIN_API(api); + (void)(parameter); + + rb = api; + rb->lcd_setfont(FONT_SYSFIXED); + +#ifdef DEBUG_WORMLET + testline_in_rect(); + test_worm_argh_collision_in_moves(); + test_make_argh(); + test_worm_food_collision(); + test_worm_argh_collision(); + test_specific_worm_collision(); +#endif + + /* Setup screen */ + do { + char buf[20]; + char* ptr; + rb->lcd_clear_display(); + + /* first line players */ + rb->snprintf(buf, sizeof buf, "%d Players UP/DN", players); + rb->lcd_puts(0, 0, buf); + + /* second line worms */ + 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) { + ptr = "Remote Control F1"; + } else { + ptr = "No Rem. Control F1"; + } + } else { + if (players > 0) { + if (use_remote) { + ptr = "2 Key Control F1"; + } else { + ptr = "4 Key Control F1"; + } + } else { + ptr = "Out Of Control"; + } + } + rb->lcd_puts(0, 2, ptr); + rb->lcd_update(); + + /* user selection */ + button = rb->button_get(true); + switch (button) { + case BUTTON_UP: + if (players < 3) { + players ++; + if (players > worm_count) { + worm_count = players; + } + if (players > 2) { + use_remote = true; + } + } + break; + case BUTTON_DOWN: + if (players > 0) { + players --; + } + break; + case BUTTON_LEFT: + if (worm_count > 1) { + worm_count--; + if (worm_count < players) { + players = worm_count; + } + } + break; + case BUTTON_RIGHT: + if (worm_count < MAX_WORMS) { + worm_count ++; + } + break; + case BUTTON_F1: + use_remote = !use_remote; + if (players > 2) { + use_remote = true; + } + break; + + case SYS_USB_CONNECTED: + rb->usb_screen(); + return PLUGIN_USB_CONNECTED; + } + } while (button != BUTTON_PLAY && + button != BUTTON_OFF && button != BUTTON_ON); + + rb->lcd_clear_display(); + /* end of setup */ + + do { + + /* button state will be overridden if + the game quits with the death of the worm. + Initializing button to BUTTON_OFF ensures + that the user can hit BUTTON_OFF during the + game to return to the menu. + */ + button = BUTTON_OFF; + + /* start the game */ + worm_dead = run(); + + /* if worm isn't dead the game was quit + via BUTTON_OFF -> no need to wait for buttons. */ + if (worm_dead) { + do { + button = rb->button_get(true); + } + /* BUTTON_ON -> start new game */ + /* BUTTON_OFF -> back to game menu */ + while (button != BUTTON_OFF && button != BUTTON_ON); + } + } + while (button != BUTTON_OFF); + + return PLUGIN_OK; +} + +#endif diff --git a/apps/recorder/bounce.c b/apps/recorder/bounce.c deleted file mode 100644 index ed4885bc39..0000000000 --- a/apps/recorder/bounce.c +++ /dev/null @@ -1,417 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Copyright (C) 2002 Daniel 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 "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 -#endif -#include - -#define SS_TITLE "Bouncer" -#define SS_TITLE_FONT 2 - -#define LETTERS_ON_SCREEN 12 - -#define YSPEED 2 -#define XSPEED 3 -#define YADD -4 - - -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, -}; - -static unsigned char xtable[]={ -54,58,63,67,71,75,79,82,85,88,91,93,95,97,98,99,99,99,99,99,97,96,94,92,90,87,84,80,77,73,69,65,60,56,52,47,43,39,34,30,26,22,19,15,12,9,7,5,3,2,0,0,0,0,0,1,2,4,6,8,11,14,17,20,24,28,32,36,41,45,49 -}; - -static signed char speed[]={ - 1,2,3,3,3,2,1,0,-1,-2,-2,-2,-1,0,0,1, -}; - -const unsigned char char_gen_12x16[][22] = -{ - { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, - { 0x00,0x00,0x00,0x00,0x00,0x00,0x7c,0x00,0xff,0x33,0xff,0x33,0x7c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, - { 0x00,0x00,0x00,0x00,0x3c,0x00,0x3c,0x00,0x00,0x00,0x00,0x00,0x3c,0x00,0x3c,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, - { 0x00,0x02,0x10,0x1e,0x90,0x1f,0xf0,0x03,0x7e,0x02,0x1e,0x1e,0x90,0x1f,0xf0,0x03,0x7e,0x02,0x1e,0x00,0x10,0x00 }, - { 0x00,0x00,0x78,0x04,0xfc,0x0c,0xcc,0x0c,0xff,0x3f,0xff,0x3f,0xcc,0x0c,0xcc,0x0f,0x88,0x07,0x00,0x00,0x00,0x00 }, - { 0x00,0x30,0x38,0x38,0x38,0x1c,0x38,0x0e,0x00,0x07,0x80,0x03,0xc0,0x01,0xe0,0x38,0x70,0x38,0x38,0x38,0x1c,0x00 }, - { 0x00,0x00,0x00,0x1f,0xb8,0x3f,0xfc,0x31,0xc6,0x21,0xe2,0x37,0x3e,0x1e,0x1c,0x1c,0x00,0x36,0x00,0x22,0x00,0x00 }, - { 0x00,0x00,0x00,0x00,0x00,0x00,0x27,0x00,0x3f,0x00,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, - { 0x00,0x00,0x00,0x00,0xf0,0x03,0xfc,0x0f,0xfe,0x1f,0x07,0x38,0x01,0x20,0x01,0x20,0x00,0x00,0x00,0x00,0x00,0x00 }, - { 0x00,0x00,0x00,0x00,0x01,0x20,0x01,0x20,0x07,0x38,0xfe,0x1f,0xfc,0x0f,0xf0,0x03,0x00,0x00,0x00,0x00,0x00,0x00 }, - { 0x00,0x00,0x98,0x0c,0xb8,0x0e,0xe0,0x03,0xf8,0x0f,0xf8,0x0f,0xe0,0x03,0xb8,0x0e,0x98,0x0c,0x00,0x00,0x00,0x00 }, - { 0x00,0x00,0x80,0x01,0x80,0x01,0x80,0x01,0xf0,0x0f,0xf0,0x0f,0x80,0x01,0x80,0x01,0x80,0x01,0x00,0x00,0x00,0x00 }, - { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xb8,0x00,0xf8,0x00,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, - { 0x00,0x00,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x00,0x00,0x00,0x00 }, - { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x00,0x38,0x00,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, - { 0x00,0x18,0x00,0x1c,0x00,0x0e,0x00,0x07,0x80,0x03,0xc0,0x01,0xe0,0x00,0x70,0x00,0x38,0x00,0x1c,0x00,0x0e,0x00 }, - { 0xf8,0x07,0xfe,0x1f,0x06,0x1e,0x03,0x33,0x83,0x31,0xc3,0x30,0x63,0x30,0x33,0x30,0x1e,0x18,0xfe,0x1f,0xf8,0x07 }, - { 0x00,0x00,0x00,0x00,0x0c,0x30,0x0c,0x30,0x0e,0x30,0xff,0x3f,0xff,0x3f,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x00 }, - { 0x1c,0x30,0x1e,0x38,0x07,0x3c,0x03,0x3e,0x03,0x37,0x83,0x33,0xc3,0x31,0xe3,0x30,0x77,0x30,0x3e,0x30,0x1c,0x30 }, - { 0x0c,0x0c,0x0e,0x1c,0x07,0x38,0xc3,0x30,0xc3,0x30,0xc3,0x30,0xc3,0x30,0xc3,0x30,0xe7,0x39,0x7e,0x1f,0x3c,0x0e }, - { 0xc0,0x03,0xe0,0x03,0x70,0x03,0x38,0x03,0x1c,0x03,0x0e,0x03,0x07,0x03,0xff,0x3f,0xff,0x3f,0x00,0x03,0x00,0x03 }, - { 0x3f,0x0c,0x7f,0x1c,0x63,0x38,0x63,0x30,0x63,0x30,0x63,0x30,0x63,0x30,0x63,0x30,0xe3,0x38,0xc3,0x1f,0x83,0x0f }, - { 0xc0,0x0f,0xf0,0x1f,0xf8,0x39,0xdc,0x30,0xce,0x30,0xc7,0x30,0xc3,0x30,0xc3,0x30,0xc3,0x39,0x80,0x1f,0x00,0x0f }, - { 0x03,0x00,0x03,0x00,0x03,0x00,0x03,0x30,0x03,0x3c,0x03,0x0f,0xc3,0x03,0xf3,0x00,0x3f,0x00,0x0f,0x00,0x03,0x00 }, - { 0x00,0x0f,0xbc,0x1f,0xfe,0x39,0xe7,0x30,0xc3,0x30,0xc3,0x30,0xc3,0x30,0xe7,0x30,0xfe,0x39,0xbc,0x1f,0x00,0x0f }, - { 0x3c,0x00,0x7e,0x00,0xe7,0x30,0xc3,0x30,0xc3,0x30,0xc3,0x38,0xc3,0x1c,0xc3,0x0e,0xe7,0x07,0xfe,0x03,0xfc,0x00 }, - { 0x00,0x00,0x00,0x00,0x00,0x00,0x70,0x1c,0x70,0x1c,0x70,0x1c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, - { 0x00,0x00,0x00,0x00,0x00,0x00,0x70,0x9c,0x70,0xfc,0x70,0x7c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, - { 0x00,0x00,0xc0,0x00,0xe0,0x01,0xf0,0x03,0x38,0x07,0x1c,0x0e,0x0e,0x1c,0x07,0x38,0x03,0x30,0x00,0x00,0x00,0x00 }, - { 0x00,0x00,0x60,0x06,0x60,0x06,0x60,0x06,0x60,0x06,0x60,0x06,0x60,0x06,0x60,0x06,0x60,0x06,0x60,0x06,0x00,0x00 }, - { 0x00,0x00,0x03,0x30,0x07,0x38,0x0e,0x1c,0x1c,0x0e,0x38,0x07,0xf0,0x03,0xe0,0x01,0xc0,0x00,0x00,0x00,0x00,0x00 }, - { 0x1c,0x00,0x1e,0x00,0x07,0x00,0x03,0x00,0x83,0x37,0xc3,0x37,0xe3,0x00,0x77,0x00,0x3e,0x00,0x1c,0x00,0x00,0x00 }, - { 0xf8,0x0f,0xfe,0x1f,0x07,0x18,0xf3,0x33,0xfb,0x37,0x1b,0x36,0xfb,0x37,0xfb,0x37,0x07,0x36,0xfe,0x03,0xf8,0x01 }, - { 0x00,0x38,0x00,0x3f,0xe0,0x07,0xfc,0x06,0x1f,0x06,0x1f,0x06,0xfc,0x06,0xe0,0x07,0x00,0x3f,0x00,0x38,0x00,0x00 }, - { 0xff,0x3f,0xff,0x3f,0xc3,0x30,0xc3,0x30,0xc3,0x30,0xc3,0x30,0xe7,0x30,0xfe,0x39,0xbc,0x1f,0x00,0x0f,0x00,0x00 }, - { 0xf0,0x03,0xfc,0x0f,0x0e,0x1c,0x07,0x38,0x03,0x30,0x03,0x30,0x03,0x30,0x07,0x38,0x0e,0x1c,0x0c,0x0c,0x00,0x00 }, - { 0xff,0x3f,0xff,0x3f,0x03,0x30,0x03,0x30,0x03,0x30,0x03,0x30,0x07,0x38,0x0e,0x1c,0xfc,0x0f,0xf0,0x03,0x00,0x00 }, - { 0xff,0x3f,0xff,0x3f,0xc3,0x30,0xc3,0x30,0xc3,0x30,0xc3,0x30,0xc3,0x30,0xc3,0x30,0x03,0x30,0x03,0x30,0x00,0x00 }, - { 0xff,0x3f,0xff,0x3f,0xc3,0x00,0xc3,0x00,0xc3,0x00,0xc3,0x00,0xc3,0x00,0xc3,0x00,0x03,0x00,0x03,0x00,0x00,0x00 }, - { 0xf0,0x03,0xfc,0x0f,0x0e,0x1c,0x07,0x38,0x03,0x30,0xc3,0x30,0xc3,0x30,0xc3,0x30,0xc7,0x3f,0xc6,0x3f,0x00,0x00 }, - { 0xff,0x3f,0xff,0x3f,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xff,0x3f,0xff,0x3f,0x00,0x00 }, - { 0x00,0x00,0x00,0x00,0x03,0x30,0x03,0x30,0xff,0x3f,0xff,0x3f,0x03,0x30,0x03,0x30,0x00,0x00,0x00,0x00,0x00,0x00 }, - { 0x00,0x0e,0x00,0x1e,0x00,0x38,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x38,0xff,0x1f,0xff,0x07,0x00,0x00 }, - { 0xff,0x3f,0xff,0x3f,0xc0,0x00,0xe0,0x01,0xf0,0x03,0x38,0x07,0x1c,0x0e,0x0e,0x1c,0x07,0x38,0x03,0x30,0x00,0x00 }, - { 0xff,0x3f,0xff,0x3f,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x00 }, - { 0xff,0x3f,0xff,0x3f,0x1e,0x00,0x78,0x00,0xe0,0x01,0xe0,0x01,0x78,0x00,0x1e,0x00,0xff,0x3f,0xff,0x3f,0x00,0x00 }, - { 0xff,0x3f,0xff,0x3f,0x0e,0x00,0x38,0x00,0xf0,0x00,0xc0,0x03,0x00,0x07,0x00,0x1c,0xff,0x3f,0xff,0x3f,0x00,0x00 }, - { 0xf0,0x03,0xfc,0x0f,0x0e,0x1c,0x07,0x38,0x03,0x30,0x03,0x30,0x07,0x38,0x0e,0x1c,0xfc,0x0f,0xf0,0x03,0x00,0x00 }, - { 0xff,0x3f,0xff,0x3f,0x83,0x01,0x83,0x01,0x83,0x01,0x83,0x01,0x83,0x01,0xc7,0x01,0xfe,0x00,0x7c,0x00,0x00,0x00 }, - { 0xf0,0x03,0xfc,0x0f,0x0e,0x1c,0x07,0x38,0x03,0x30,0x03,0x36,0x07,0x3e,0x0e,0x1c,0xfc,0x3f,0xf0,0x33,0x00,0x00 }, - { 0xff,0x3f,0xff,0x3f,0x83,0x01,0x83,0x01,0x83,0x03,0x83,0x07,0x83,0x0f,0xc7,0x1d,0xfe,0x38,0x7c,0x30,0x00,0x00 }, - { 0x3c,0x0c,0x7e,0x1c,0xe7,0x38,0xc3,0x30,0xc3,0x30,0xc3,0x30,0xc3,0x30,0xc7,0x39,0x8e,0x1f,0x0c,0x0f,0x00,0x00 }, - { 0x00,0x00,0x03,0x00,0x03,0x00,0x03,0x00,0xff,0x3f,0xff,0x3f,0x03,0x00,0x03,0x00,0x03,0x00,0x00,0x00,0x00,0x00 }, - { 0xff,0x07,0xff,0x1f,0x00,0x38,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x38,0xff,0x1f,0xff,0x07,0x00,0x00 }, - { 0x07,0x00,0x3f,0x00,0xf8,0x01,0xc0,0x0f,0x00,0x3e,0x00,0x3e,0xc0,0x0f,0xf8,0x01,0x3f,0x00,0x07,0x00,0x00,0x00 }, - { 0xff,0x3f,0xff,0x3f,0x00,0x1c,0x00,0x06,0x80,0x03,0x80,0x03,0x00,0x06,0x00,0x1c,0xff,0x3f,0xff,0x3f,0x00,0x00 }, - { 0x03,0x30,0x0f,0x3c,0x1c,0x0e,0x30,0x03,0xe0,0x01,0xe0,0x01,0x30,0x03,0x1c,0x0e,0x0f,0x3c,0x03,0x30,0x00,0x00 }, - { 0x03,0x00,0x0f,0x00,0x3c,0x00,0xf0,0x00,0xc0,0x3f,0xc0,0x3f,0xf0,0x00,0x3c,0x00,0x0f,0x00,0x03,0x00,0x00,0x00 }, - { 0x03,0x30,0x03,0x3c,0x03,0x3e,0x03,0x33,0xc3,0x31,0xe3,0x30,0x33,0x30,0x1f,0x30,0x0f,0x30,0x03,0x30,0x00,0x00 }, - { 0x00,0x00,0x00,0x00,0xff,0x3f,0xff,0x3f,0x03,0x30,0x03,0x30,0x03,0x30,0x03,0x30,0x00,0x00,0x00,0x00,0x00,0x00 }, - { 0x0e,0x00,0x1c,0x00,0x38,0x00,0x70,0x00,0xe0,0x00,0xc0,0x01,0x80,0x03,0x00,0x07,0x00,0x0e,0x00,0x1c,0x00,0x18 }, - { 0x00,0x00,0x00,0x00,0x03,0x30,0x03,0x30,0x03,0x30,0x03,0x30,0xff,0x3f,0xff,0x3f,0x00,0x00,0x00,0x00,0x00,0x00 }, - { 0x60,0x00,0x70,0x00,0x38,0x00,0x1c,0x00,0x0e,0x00,0x07,0x00,0x0e,0x00,0x1c,0x00,0x38,0x00,0x70,0x00,0x60,0x00 }, - { 0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0 }, - { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3e,0x00,0x7e,0x00,0x4e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, - { 0x00,0x1c,0x40,0x3e,0x60,0x33,0x60,0x33,0x60,0x33,0x60,0x33,0x60,0x33,0x60,0x33,0xe0,0x3f,0xc0,0x3f,0x00,0x00 }, - { 0xff,0x3f,0xff,0x3f,0xc0,0x30,0x60,0x30,0x60,0x30,0x60,0x30,0x60,0x30,0xe0,0x38,0xc0,0x1f,0x80,0x0f,0x00,0x00 }, - { 0x80,0x0f,0xc0,0x1f,0xe0,0x38,0x60,0x30,0x60,0x30,0x60,0x30,0x60,0x30,0x60,0x30,0xc0,0x18,0x80,0x08,0x00,0x00 }, - { 0x80,0x0f,0xc0,0x1f,0xe0,0x38,0x60,0x30,0x60,0x30,0x60,0x30,0xe0,0x30,0xc0,0x30,0xff,0x3f,0xff,0x3f,0x00,0x00 }, - { 0x80,0x0f,0xc0,0x1f,0xe0,0x3b,0x60,0x33,0x60,0x33,0x60,0x33,0x60,0x33,0x60,0x33,0xc0,0x13,0x80,0x01,0x00,0x00 }, - { 0xc0,0x00,0xc0,0x00,0xfc,0x3f,0xfe,0x3f,0xc7,0x00,0xc3,0x00,0xc3,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, - { 0x80,0x03,0xc0,0xc7,0xe0,0xce,0x60,0xcc,0x60,0xcc,0x60,0xcc,0x60,0xcc,0x60,0xe6,0xe0,0x7f,0xe0,0x3f,0x00,0x00 }, - { 0xff,0x3f,0xff,0x3f,0xc0,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0xe0,0x00,0xc0,0x3f,0x80,0x3f,0x00,0x00,0x00,0x00 }, - { 0x00,0x00,0x00,0x00,0x00,0x30,0x60,0x30,0xec,0x3f,0xec,0x3f,0x00,0x30,0x00,0x30,0x00,0x00,0x00,0x00,0x00,0x00 }, - { 0x00,0x00,0x00,0x00,0x00,0x60,0x00,0xe0,0x00,0xc0,0x60,0xc0,0xec,0xff,0xec,0x7f,0x00,0x00,0x00,0x00,0x00,0x00 }, - { 0x00,0x00,0xff,0x3f,0xff,0x3f,0x00,0x03,0x80,0x07,0xc0,0x0f,0xe0,0x1c,0x60,0x38,0x00,0x30,0x00,0x00,0x00,0x00 }, - { 0x00,0x00,0x00,0x00,0x00,0x30,0x03,0x30,0xff,0x3f,0xff,0x3f,0x00,0x30,0x00,0x30,0x00,0x00,0x00,0x00,0x00,0x00 }, - { 0xe0,0x3f,0xc0,0x3f,0xe0,0x00,0xe0,0x00,0xc0,0x3f,0xc0,0x3f,0xe0,0x00,0xe0,0x00,0xc0,0x3f,0x80,0x3f,0x00,0x00 }, - { 0x00,0x00,0xe0,0x3f,0xe0,0x3f,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0xe0,0x00,0xc0,0x3f,0x80,0x3f,0x00,0x00 }, - { 0x80,0x0f,0xc0,0x1f,0xe0,0x38,0x60,0x30,0x60,0x30,0x60,0x30,0x60,0x30,0xe0,0x38,0xc0,0x1f,0x80,0x0f,0x00,0x00 }, - { 0xe0,0xff,0xe0,0xff,0x60,0x0c,0x60,0x18,0x60,0x18,0x60,0x18,0x60,0x18,0xe0,0x1c,0xc0,0x0f,0x80,0x07,0x00,0x00 }, - { 0x80,0x07,0xc0,0x0f,0xe0,0x1c,0x60,0x18,0x60,0x18,0x60,0x18,0x60,0x18,0x60,0x0c,0xe0,0xff,0xe0,0xff,0x00,0x00 }, - { 0x00,0x00,0xe0,0x3f,0xe0,0x3f,0xc0,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0xe0,0x00,0xc0,0x00,0x00,0x00 }, - { 0xc0,0x11,0xe0,0x33,0x60,0x33,0x60,0x33,0x60,0x33,0x60,0x33,0x60,0x3f,0x40,0x1e,0x00,0x00,0x00,0x00,0x00,0x00 }, - { 0x60,0x00,0x60,0x00,0xfe,0x1f,0xfe,0x3f,0x60,0x30,0x60,0x30,0x60,0x30,0x00,0x30,0x00,0x00,0x00,0x00,0x00,0x00 }, - { 0xe0,0x0f,0xe0,0x1f,0x00,0x38,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x18,0xe0,0x3f,0xe0,0x3f,0x00,0x00 }, - { 0x60,0x00,0xe0,0x01,0x80,0x07,0x00,0x1e,0x00,0x38,0x00,0x38,0x00,0x1e,0x80,0x07,0xe0,0x01,0x60,0x00,0x00,0x00 }, - { 0xe0,0x07,0xe0,0x1f,0x00,0x38,0x00,0x1c,0xe0,0x0f,0xe0,0x0f,0x00,0x1c,0x00,0x38,0xe0,0x1f,0xe0,0x07,0x00,0x00 }, - { 0x60,0x30,0xe0,0x38,0xc0,0x1d,0x80,0x0f,0x00,0x07,0x80,0x0f,0xc0,0x1d,0xe0,0x38,0x60,0x30,0x00,0x00,0x00,0x00 }, - { 0x00,0x00,0x60,0x00,0xe0,0x81,0x80,0xe7,0x00,0x7e,0x00,0x1e,0x80,0x07,0xe0,0x01,0x60,0x00,0x00,0x00,0x00,0x00 }, - { 0x60,0x30,0x60,0x38,0x60,0x3c,0x60,0x36,0x60,0x33,0xe0,0x31,0xe0,0x30,0x60,0x30,0x20,0x30,0x00,0x00,0x00,0x00 }, - { 0x00,0x00,0x80,0x00,0xc0,0x01,0xfc,0x1f,0x7e,0x3f,0x07,0x70,0x03,0x60,0x03,0x60,0x03,0x60,0x00,0x00,0x00,0x00 }, - { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x3f,0xff,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, - { 0x00,0x00,0x03,0x60,0x03,0x60,0x03,0x60,0x07,0x70,0x7e,0x3f,0xfc,0x1f,0xc0,0x01,0x80,0x00,0x00,0x00,0x00,0x00 }, - { 0x10,0x00,0x18,0x00,0x0c,0x00,0x04,0x00,0x0c,0x00,0x18,0x00,0x10,0x00,0x18,0x00,0x0c,0x00,0x04,0x00,0x00,0x00 }, - { 0xff,0x3f,0xff,0x3f,0xff,0x3f,0xff,0x3f,0xff,0x3f,0xff,0x3f,0xff,0x3f,0xff,0x3f,0xff,0x3f,0xff,0x3f,0x00,0x00 } -}; - -#define XDIFF -4 -#define YDIFF -6 - -enum { - NUM_XSANKE, - NUM_YSANKE, - NUM_XADD, - NUM_YADD, - NUM_XDIST, - NUM_YDIST, - - NUM_LAST -}; - -struct counter { - char *what; - int num; -}; - -struct counter values[]={ - {"xsanke", 1}, - {"ysanke", 1}, - {"xadd", 1}, - {"yadd", 1}, - {"xdist", -4}, - {"ydistt", -6}, -}; - -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, -}; -static unsigned char yhour[]={ -42,42,42,42,41,41,40,39,39,38,37,36,35,34,33,32,30,29,28,27,26,25,24,24,23,22,22,21,21,21,21,21,21,21,22,22,23,24,24,25,26,27,28,29,30,31,33,34,35,36,37,38,39,39,40,41,41,42,42,42, -}; - -static unsigned char xminute[]={ -56,59,63,67,71,74,77,80,83,86,88,90,91,92,93,93,93,92,91,90,88,86,83,80,77,74,71,67,63,59,56,52,48,44,40,37,34,31,28,25,23,21,20,19,18,18,18,19,20,21,23,25,28,31,34,37,40,44,48,52, -}; -static unsigned char xhour[]={ -56,57,59,61,63,65,66,68,69,71,72,73,73,74,74,74,74,74,73,73,72,71,69,68,66,65,63,61,59,57,56,54,52,50,48,46,45,43,42,40,39,38,38,37,37,37,37,37,38,38,39,40,42,43,45,46,48,50,52,54, -}; - -static void addclock(void) -{ - int i; - int hour; - int minute; - int pos; - - hour = rtc_read(3); - hour = (((hour & 0x30) >> 4) * 10 + (hour & 0x0f))%12; - minute = rtc_read(2); - minute = ((minute & 0x70) >> 4) * 10 + (minute & 0x0f); - - pos = 90-minute; - if(pos >= 60) - pos -= 60; - - 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]); - - /* draw a circle */ - for(i=0; i < 60; i+=3) { - lcd_drawline( xminute[i], - yminute[i], - xminute[(i+1)%60], - yminute[(i+1)%60]); - } -} - -static int scrollit(void) -{ - int b; - unsigned int y=100; - int x=LCD_WIDTH; - unsigned int yy,xx; - unsigned int i; - int textpos=0; - - char rock[]="Rockbox! Pure pleasure. Pure fun. Oooh. What fun! ;-) "; - int letter; - - lcd_clear_display(); - while(1) - { - b = 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(); - - 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], - xx, table[yy&63], - 11, 16, false); - yy += YADD; - xx+= LCD_WIDTH/LETTERS_ON_SCREEN; - } - addclock(); - lcd_update(); - - x-= XSPEED; - - if(x < 0) { - x += LCD_WIDTH/LETTERS_ON_SCREEN; - y += YADD; - textpos++; - } - - y+=YSPEED; - - } -} - -static int loopit(void) -{ - int b; - unsigned int y=100; - unsigned int x=100; - unsigned int yy,xx; - unsigned int i; - unsigned int ysanke=0; - unsigned int xsanke=0; - - char rock[]="ROCKbox"; - - int show=0; - int timeout=0; - char buffer[30]; - - lcd_clear_display(); - while(1) - { - b = button_get_w_tmo(HZ/10); - if ( b == (BUTTON_OFF|BUTTON_REL) ) - return 0; - - if ( b == SYS_USB_CONNECTED) { - usb_screen(); - return 0; - } - - if ( b == (BUTTON_ON|BUTTON_REL) ) - return 1; - else if(b != BUTTON_NONE) - timeout=20; - - y+= speed[ysanke&15] + values[NUM_YADD].num; - x+= speed[xsanke&15] + values[NUM_XADD].num; - - lcd_clear_display(); - - addclock(); - - if(timeout) { - switch(b) { - case BUTTON_LEFT: - values[show].num--; - break; - case BUTTON_RIGHT: - values[show].num++; - break; - case BUTTON_UP: - if(++show == NUM_LAST) - show=0; - break; - case BUTTON_DOWN: - if(--show < 0) - show=NUM_LAST-1; - break; - } - snprintf(buffer, 30, "%s: %d", - values[show].what, values[show].num); - lcd_putsxy(0, 56, buffer); - timeout--; - } - for(i=0, yy=y, xx=x; - i ) \___| < | \_\ ( <_> > < < -* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ -* \/ \/ \/ \/ \/ -* $Id$ -* -* Copyright (C) 2002 Damien Teney -* modified to use int instead of float math by Andreas Zwirtes -* -* 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_DEMOS - -#include -#include "lcd.h" -#include "config.h" -#include "kernel.h" -#include "menu.h" -#include "button.h" -#include "sprintf.h" -#include "screens.h" -#include "font.h" - -/* Loops that the values are displayed */ -#define DISP_TIME 30 - -struct point_3D { - long x, y, z; -}; - -struct point_2D { - long x, y; -}; - -static struct point_3D sommet[8]; -static struct point_3D point3D[8]; -static struct point_2D point2D[8]; - -static long matrice[3][3]; - -static int nb_points = 8; - -static int x_off = 56; -static int y_off = 95; -static int z_off = 600; - -/* Precalculated sine and cosine * 10000 (four digit fixed point math) */ -static int sin_table[91] = -{ - 0, 174, 348, 523, 697, - 871,1045,1218,1391,1564, - 1736,1908,2079,2249,2419, - 2588,2756,2923,3090,3255, - 3420,3583,3746,3907,4067, - 4226,4383,4539,4694,4848, - 5000,5150,5299,5446,5591, - 5735,5877,6018,6156,6293, - 6427,6560,6691,6819,6946, - 7071,7193,7313,7431,7547, - 7660,7771,7880,7986,8090, - 8191,8290,8386,8480,8571, - 8660,8746,8829,8910,8987, - 9063,9135,9205,9271,9335, - 9396,9455,9510,9563,9612, - 9659,9702,9743,9781,9816, - 9848,9876,9902,9925,9945, - 9961,9975,9986,9993,9998, - 10000 -}; - -static long sin(int val) -{ - /* Speed improvement through sukzessive lookup */ - if (val<181) - { - if (val<91) - { - /* phase 0-90 degree */ - return (long)sin_table[val]; - } - else - { - /* phase 91-180 degree */ - return (long)sin_table[180-val]; - } - } - else - { - if (val<271) - { - /* phase 181-270 degree */ - return (-1L)*(long)sin_table[val-180]; - } - else - { - /* phase 270-359 degree */ - return (-1L)*(long)sin_table[360-val]; - } - } - return 0; -} - -static long cos(int val) -{ - /* Speed improvement through sukzessive lookup */ - if (val<181) - { - if (val<91) - { - /* phase 0-90 degree */ - return (long)sin_table[90-val]; - } - else - { - /* phase 91-180 degree */ - return (-1L)*(long)sin_table[val-90]; - } - } - else - { - if (val<271) - { - /* phase 181-270 degree */ - return (-1L)*(long)sin_table[270-val]; - } - else - { - /* phase 270-359 degree */ - return (long)sin_table[val-270]; - } - } - return 0; -} - - -static void cube_rotate(int xa, int ya, int za) -{ - int i; - - /* Just to prevent unnecessary lookups */ - long sxa,cxa,sya,cya,sza,cza; - sxa=sin(xa); - cxa=cos(xa); - sya=sin(ya); - cya=cos(ya); - sza=sin(za); - cza=cos(za); - - /* calculate overall translation matrix */ - matrice[0][0] = cza*cya/10000L; - matrice[1][0] = sza*cya/10000L; - matrice[2][0] = -sya; - - matrice[0][1] = cza*sya/10000L*sxa/10000L - sza*cxa/10000L; - matrice[1][1] = sza*sya/10000L*sxa/10000L + cxa*cza/10000L; - matrice[2][1] = sxa*cya/10000L; - - matrice[0][2] = cza*sya/10000L*cxa/10000L + sza*sxa/10000L; - matrice[1][2] = sza*sya/10000L*cxa/10000L - cza*sxa/10000L; - matrice[2][2] = cxa*cya/10000L; - - /* apply translation matrix to all points */ - for(i=0;i0) - { - t_disp--; - snprintf(buffer, 30, "x:%d y:%d z:%d h:%d",xs,ys,zs,highspeed); - lcd_putsxy(0, 56, buffer); - } - lcd_update(); - - xa+=xs; - if (xa>359) - xa-=360; - if (xa<0) - xa+=360; - ya+=ys; - if (ya>359) - ya-=360; - if (ya<0) - ya+=360; - za+=zs; - if (za>359) - za-=360; - if (za<0) - za+=360; - - switch(button_get(false)) - { - case BUTTON_RIGHT: - xs+=1; - if (xs>10) - xs=10; - t_disp=DISP_TIME; - break; - case BUTTON_LEFT: - xs-=1; - if (xs<-10) - xs=-10; - t_disp=DISP_TIME; - break; - case BUTTON_UP: - ys+=1; - if (ys>10) - ys=10; - t_disp=DISP_TIME; - break; - case BUTTON_DOWN: - ys-=1; - if (ys<-10) - ys=-10; - t_disp=DISP_TIME; - break; - case BUTTON_F2: - zs+=1; - if (zs>10) - zs=10; - t_disp=DISP_TIME; - break; - case BUTTON_F1: - zs-=1; - if (zs<-10) - zs=-10; - t_disp=DISP_TIME; - break; - case BUTTON_PLAY: - highspeed=!highspeed; - t_disp=DISP_TIME; - break; - case BUTTON_OFF|BUTTON_REL: - exit=1; - break; - - case SYS_USB_CONNECTED: - usb_screen(); - lcd_setfont(FONT_UI); - return true; - } - } - - lcd_setfont(FONT_UI); - - return false; -} - -#endif /* USE_DEMOS */ - -/* ----------------------------------------------------------------- - * vim: et sw=4 ts=8 sts=4 tw=78 - */ - - - 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/oscillograph.c b/apps/recorder/oscillograph.c deleted file mode 100644 index bf94db168f..0000000000 --- a/apps/recorder/oscillograph.c +++ /dev/null @@ -1,207 +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 SIMULATOR /* don't want this code in the simulator */ - -#include -#include -#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 -#define DRAW_MODE_PIXEL 2 -#define DRAW_MODE_COUNT 3 - -#define MAX_PEAK 0x8000 - -/* number of ticks between two volume samples */ -static int speed = 1; -/* roll == true -> lcd rolls */ -static bool roll = true; -/* see DRAW_MODE_XXX constants for valid values */ -static int drawMode = DRAW_MODE_FILLED; - -/** - * Displays a vertically scrolling oscillosgraph using - * hardware scrolling of the display. The user can change - * speed - */ -bool oscillograph(void) -{ - /* stores current volume value left */ - int left; - /* stores current volume value right */ - int right; - /* specifies the current position on the lcd */ - int y = LCD_WIDTH - 1; - - /* only needed when drawing lines */ - int lastLeft = 0; - int lastRight = 0; - int lasty = 0; - - bool exit = false; - - /* 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)); - - /* delete current line */ - 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); - break; - - case DRAW_MODE_OUTLINE: - /* last position needed for lines */ - lasty = MAX(y-1, 0); - - /* 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); - - /* have to store the old values for drawing lines - the next time */ - lastRight = right; - lastLeft = left; - break; - - case DRAW_MODE_PIXEL: - /* straight and simple */ - lcd_drawpixel(LCD_WIDTH / 2 + right, y); - lcd_drawpixel(LCD_WIDTH / 2 - left, y); - break; - } - - - /* increment and adjust the drawing position */ - y++; - if (y >= LCD_HEIGHT) - y = 0; - - /* I roll before update because otherwise the new - line would appear at the wrong end of the display */ - if (roll) - lcd_roll(y); - - /* now finally make the new sample visible */ - 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. - 2.) speeding up is achieved by leaving out - the user input check for (-speed) volume - samples. For this mechanism negative values - are used. - */ - - if (speed >= 0 || ((speed < 0) && (y % (-speed) == 0))) { - bool draw = false; - - /* speed values > 0 slow the oszi down. By user input - speed might become < 1. If a value < 1 was - passed user input would be disabled. Thus - it must be ensured that at least 1 is passed. */ - - /* react to user input */ - switch (button_get_w_tmo(MAX(speed, 1))) { - case BUTTON_UP: - speed++; - draw = true; - break; - - case BUTTON_DOWN: - speed--; - draw = true; - break; - - case BUTTON_PLAY: - /* pause the demo */ - button_get(true); - break; - - case BUTTON_F1: - /* toggle rolling */ - roll = !roll; - break; - - case BUTTON_F2: - /* step through the display modes */ - drawMode ++; - drawMode = drawMode % DRAW_MODE_COUNT; - - /* lcd buffer might be rolled so that - the transition from LCD_HEIGHT to 0 - takes place in the middle of the screen. - 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); - break; - - case BUTTON_F3: - speed = 1; - draw = true; - break; - - case BUTTON_OFF: - exit = true; - break; - } - - 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); - } - } - } - - /* restore to default roll position. - Looks funny if you forget to do this... */ - lcd_roll(0); - lcd_update(); - - /* standard return */ - return false; -} - -#endif /* #ifndef SIMULATOR */ - - diff --git a/apps/recorder/snow.c b/apps/recorder/snow.c deleted file mode 100644 index c4e952f21d..0000000000 --- a/apps/recorder/snow.c +++ /dev/null @@ -1,117 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Copyright (C) 2002 Itai Shaked - * - * 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 -#include "lcd.h" -#include "config.h" -#include "kernel.h" -#include "menu.h" -#include "button.h" - -#define NUM_PARTICLES 100 - -static short particles[NUM_PARTICLES][2]; - -static bool particle_exists(int particle) -{ - if (particles[particle][0]>=0 && particles[particle][1]>=0 && - particles[particle][0]<112 && particles[particle][1]<64) - return true; - else - return false; -} - -static int create_particle(void) -{ - int i; - - for (i=0; i ) \___| < | \_\ ( <_> > < < - * 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 -#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 -#endif -#include -#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 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 -#include -#include "lcd.h" -#include "button.h" -#include "kernel.h" -#include "menu.h" -#include "screens.h" -#include "font.h" - -#ifdef SIMULATOR -#include -#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.c b/apps/recorder/wormlet.c deleted file mode 100644 index 2937a1bb83..0000000000 --- a/apps/recorder/wormlet.c +++ /dev/null @@ -1,2036 +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. - * - ****************************************************************************/ - -#include "config.h" -#include "options.h" - -#ifdef USE_GAMES - -/* #define DEBUG_WORMLET */ - -#include -#include -#include -#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" - -/* size of the field the worm lives in */ -#define FIELD_RECT_X 1 -#define FIELD_RECT_Y 1 -#define FIELD_RECT_WIDTH (LCD_WIDTH - 45) -#define FIELD_RECT_HEIGHT (LCD_HEIGHT - 2) - -/* size of the ring of the worm - choos a value that is a power of 2 to help - the compiler optimize modul operations*/ -#define MAX_WORM_SEGMENTS 64 - -/* when the game starts */ -#define INITIAL_WORM_LENGTH 10 - -/* num of pixel the worm grows per eaten food */ -#define WORM_PER_FOOD 7 - -/* num of worms creeping in the FIELD */ -#define MAX_WORMS 3 - -/* minimal distance between a worm and an argh - when a new argh is made */ -#define MIN_ARGH_DIST 5 - -/** - * All the properties that a worm has. - */ -static struct worm { - /* The worm is stored in a ring of xy coordinates */ - char x[MAX_WORM_SEGMENTS]; - char y[MAX_WORM_SEGMENTS]; - - int head; /* index of the head within the buffer */ - int tail; /* index of the tail within the buffer */ - int growing; /* number of cyles the worm still keeps growing */ - bool alive; /* the worms living state */ - - /* direction vector in which the worm moves */ - int dirx; /* only values -1 0 1 allowed */ - int diry; /* only values -1 0 1 allowed */ - - /* this method is used to fetch the direction the user - has selected. It can be one of the values - human_player1, human_player2, remote_player, virtual_player. - All these values are fuctions, that can change the direction - of the worm */ - void (*fetch_worm_direction)(struct worm *w); -} worms[MAX_WORMS]; - -/* stores the highscore - besides it was scored by a virtual player */ -static int highscore; - -#define MAX_FOOD 5 /* maximal number of food items */ -#define FOOD_SIZE 3 /* the width and height of a food */ - -/* The arrays store the food coordinates */ -static char foodx[MAX_FOOD]; -static char foody[MAX_FOOD]; - -#define MAX_ARGH 100 /* maximal number of argh items */ -#define ARGH_SIZE 4 /* the width and height of a argh */ -#define ARGHS_PER_FOOD 2 /* number of arghs produced per eaten food */ - -/* The arrays store the argh coordinates */ -static char arghx[MAX_ARGH]; -static char arghy[MAX_ARGH]; - -/* the number of arghs that are currently in use */ -static int argh_count; - -#ifdef DEBUG_WORMLET -/* just a buffer used for debug output */ -static char debugout[15]; -#endif - -/* the number of ticks each game cycle should take */ -#define SPEED 14 - -/* the number of active worms (dead or alive) */ -static int worm_count = MAX_WORMS; - -/* in multiplayer mode: en- / disables the remote worm control - in singleplayer mode: toggles 4 / 2 button worm control */ -static bool use_remote = false; - -/* return values of check_collision */ -#define COLLISION_NONE 0 -#define COLLISION_WORM 1 -#define COLLISION_FOOD 2 -#define COLLISION_ARGH 3 -#define COLLISION_FIELD 4 - -/* constants for use as directions. - Note that the values are ordered clockwise. - Thus increasing / decreasing the values - is equivalent to right / left turns. */ -#define WEST 0 -#define NORTH 1 -#define EAST 2 -#define SOUTH 3 - -/* direction of human player 1 */ -static int player1_dir = EAST; -/* direction of human player 2 */ -static int player2_dir = EAST; -/* direction of human player 3 */ -static int player3_dir = EAST; - -/* the number of (human) players that currently - control a worm */ -static int players = 1; - -#ifdef DEBUG_WORMLET -static void set_debug_out(char *str){ - strcpy(debugout, str); -} -#endif - -/** - * Returns the direction id in which the worm - * currently is creeping. - * @param struct worm *w The worm that is to be investigated. - * w Must not be null. - * @return int A value 0 <= value < 4 - * Note the predefined constants NORTH, SOUTH, EAST, WEST - */ -static int get_worm_dir(struct worm *w) { - int retVal ; - if (w->dirx == 0) { - if (w->diry == 1) { - retVal = SOUTH; - } else { - retVal = NORTH; - } - } else { - if (w->dirx == 1) { - retVal = EAST; - } else { - retVal = WEST; - } - } - return retVal; -} - -/** - * Set the direction of the specified worm with a direction id. - * Increasing the value by 1 means to turn the worm direction - * to right by 90 degree. - * @param struct worm *w The worm that is to be altered. w Must not be null. - * @param int dir The new direction in which the worm is to creep. - * dir must be 0 <= dir < 4. Use predefined constants - * NORTH, SOUTH, EAST, WEST - */ -static void set_worm_dir(struct worm *w, int dir) { - switch (dir) { - case WEST: - w->dirx = -1; - w->diry = 0; - break; - case NORTH: - w->dirx = 0; - w->diry = - 1; - break; - case EAST: - w->dirx = 1; - w->diry = 0; - break; - case SOUTH: - w->dirx = 0; - w->diry = 1; - break; - } -} - -/** - * Returns the current length of the worm array. This - * is also a value for the number of bends that are in the worm. - * @return int a positive value with 0 <= value < MAX_WORM_SEGMENTS - */ -static int get_worm_array_length(struct worm *w) { - /* initial simple calculation will be overwritten if wrong. */ - int retVal = w->head - w->tail; - - /* if the worm 'crosses' the boundaries of the ringbuffer */ - if (retVal < 0) { - retVal = w->head + MAX_WORM_SEGMENTS - w->tail; - } - - return retVal; -} - -/** - * Returns the score the specified worm. The score is the length - * of the worm. - * @param struct worm *w The worm that is to be investigated. - * w must not be null. - * @return int The length of the worm (>= 0). - */ -static int get_score(struct worm *w) { - int retval = 0; - int length = get_worm_array_length(w); - int i; - for (i = 0; i < length; i++) { - - /* The iteration iterates the length of the worm. - Here's the conversion to the true indices within the worm arrays. */ - int linestart = (w->tail + i ) % MAX_WORM_SEGMENTS; - int lineend = (linestart + 1) % MAX_WORM_SEGMENTS; - int startx = w->x[linestart]; - int starty = w->y[linestart]; - int endx = w->x[lineend]; - int endy = w->y[lineend]; - - int minimum, maximum; - - if (startx == endx) { - minimum = MIN(starty, endy); - maximum = MAX(starty, endy); - } else { - minimum = MIN(startx, endx); - maximum = MAX(startx, endx); - } - retval += abs(maximum - minimum); - } - return retval; -} - -/** - * Determines wether the line specified by startx, starty, endx, endy intersects - * the rectangle specified by x, y, width, height. Note that the line must be exactly - * horizontal or vertical (startx == endx or starty == endy). - * @param int startx The x coordinate of the start point of the line. - * @param int starty The y coordinate of the start point of the line. - * @param int endx The x coordinate of the end point of the line. - * @param int endy The y coordinate of the end point of the line. - * @param int x The x coordinate of the top left corner of the rectangle. - * @param int y The y coordinate of the top left corner of the rectangle. - * @param int width The width of the rectangle. - * @param int height The height of the rectangle. - * @return bool Returns true if the specified line intersects with the recangle. - */ -static bool line_in_rect(int startx, int starty, int endx, int endy, int x, int y, int width, int height) { - bool retval = false; - int simple, simplemin, simplemax; - int compa, compb, compmin, compmax; - int temp; - if (startx == endx) { - simple = startx; - simplemin = x; - simplemax = x + width; - - compa = starty; - compb = endy; - compmin = y; - compmax = y + height; - } else { - simple = starty; - simplemin = y; - simplemax = y + height; - - compa = startx; - compb = endx; - compmin = x; - compmax = x + width; - }; - - temp = compa; - compa = MIN(compa, compb); - compb = MAX(temp, compb); - - if (simplemin <= simple && simple <= simplemax) { - if ((compmin <= compa && compa <= compmax) || - (compmin <= compb && compb <= compmax) || - (compa <= compmin && compb >= compmax)) { - retval = true; - } - } - return retval; -} - -/** - * Tests wether the specified worm intersects with the rect. - * @param struct worm *w The worm to be investigated - * @param int x The x coordinate of the top left corner of the rect - * @param int y The y coordinate of the top left corner of the rect - * @param int widht The width of the rect - * @param int height The height of the rect - * @return bool Returns true if the worm intersects with the rect - */ -static bool worm_in_rect(struct worm *w, int x, int y, int width, int height) { - bool retval = false; - - - /* get_worm_array_length is expensive -> buffer the value */ - int wormLength = get_worm_array_length(w); - int i; - - /* test each entry that is part of the worm */ - for (i = 0; i < wormLength && retval == false; i++) { - - /* The iteration iterates the length of the worm. - Here's the conversion to the true indices within the worm arrays. */ - int linestart = (w->tail + i ) % MAX_WORM_SEGMENTS; - int lineend = (linestart + 1) % MAX_WORM_SEGMENTS; - int startx = w->x[linestart]; - int starty = w->y[linestart]; - int endx = w->x[lineend]; - int endy = w->y[lineend]; - - retval = line_in_rect(startx, starty, endx, endy, x, y, width, height); - } - - return retval; -} - -/** - * Checks wether a specific food in the food arrays is at the - * specified coordinates. - * @param int foodIndex The index of the food in the food arrays - * @param int x the x coordinate. - * @param int y the y coordinate. - * @return Returns true if the coordinate hits the food specified by - * foodIndex. - */ -static bool specific_food_collision(int foodIndex, int x, int y) { - bool retVal = false; - if (x >= foodx[foodIndex] && - x < foodx[foodIndex] + FOOD_SIZE && - y >= foody[foodIndex] && - y < foody[foodIndex] + FOOD_SIZE) { - - retVal = true; - } - return retVal; -} - -/** - * Returns the index of the food that is at the - * given coordinates. If no food is at the coordinates - * -1 is returned. - * @return int -1 <= value < MAX_FOOD - */ -static int food_collision(int x, int y) { - int i = 0; - int retVal = -1; - for (i = 0; i < MAX_FOOD; i++) { - if (specific_food_collision(i, x, y)) { - retVal = i; - break; - } - } - return retVal; -} - -/** - * Checks wether a specific argh in the argh arrays is at the - * specified coordinates. - * @param int arghIndex The index of the argh in the argh arrays - * @param int x the x coordinate. - * @param int y the y coordinate. - * @return Returns true if the coordinate hits the argh specified by - * arghIndex. - */ -static bool specific_argh_collision(int arghIndex, int x, int y) { - - if ( x >= arghx[arghIndex] && - y >= arghy[arghIndex] && - x < arghx[arghIndex] + ARGH_SIZE && - y < arghy[arghIndex] + ARGH_SIZE ) - { - return true; - } - - return false; -} - -/** - * Returns the index of the argh that is at the - * given coordinates. If no argh is at the coordinates - * -1 is returned. - * @param int x The x coordinate. - * @param int y The y coordinate. - * @return int -1 <= value < argh_count <= MAX_ARGH - */ -static int argh_collision(int x, int y) { - int i = 0; - int retVal = -1; - - /* search for the argh that has the specified coords */ - for (i = 0; i < argh_count; i++) { - if (specific_argh_collision(i, x, y)) { - retVal = i; - break; - } - } - return retVal; -} - -/** - * Checks wether the worm collides with the food at the specfied food-arrays. - * @param int foodIndex The index of the food in the arrays. Ensure the value is - * 0 <= foodIndex <= MAX_FOOD - * @return Returns true if the worm collides with the specified food. - */ -static bool worm_food_collision(struct worm *w, int foodIndex) -{ - bool retVal = false; - - retVal = worm_in_rect(w, foodx[foodIndex], foody[foodIndex], - FOOD_SIZE - 1, FOOD_SIZE - 1); - - return retVal; -} - -/** - * Returns true if the worm hits the argh within the next moves (unless - * the worm changes it's direction). - * @param struct worm *w - The worm to investigate - * @param int argh_idx - The index of the argh - * @param int moves - The number of moves that are considered. - * @return Returns false if the specified argh is not hit within the next - * moves. - */ -static bool worm_argh_collision_in_moves(struct worm *w, int argh_idx, int moves){ - bool retVal = false; - int x1, y1, x2, y2; - x1 = w->x[w->head]; - y1 = w->y[w->head]; - - x2 = w->x[w->head] + moves * w->dirx; - y2 = w->y[w->head] + moves * w->diry; - - retVal = line_in_rect(x1, y1, x2, y2, arghx[argh_idx], arghy[argh_idx], - ARGH_SIZE, ARGH_SIZE); - return retVal; -} - -/** - * Checks wether the worm collides with the argh at the specfied argh-arrays. - * @param int arghIndex The index of the argh in the arrays. - * Ensure the value is 0 <= arghIndex < argh_count <= MAX_ARGH - * @return Returns true if the worm collides with the specified argh. - */ -static bool worm_argh_collision(struct worm *w, int arghIndex) -{ - bool retVal = false; - - retVal = worm_in_rect(w, arghx[arghIndex], arghy[arghIndex], - ARGH_SIZE - 1, ARGH_SIZE - 1); - - return retVal; -} - -/** - * Find new coordinates for the food stored in foodx[index], foody[index] - * that don't collide with any other food or argh - * @param int index - * Ensure that 0 <= index < MAX_FOOD. - */ -static int make_food(int index) { - - int x = 0; - int y = 0; - bool collisionDetected = false; - int tries = 0; - int i; - - 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); - tries ++; - - /* Ensure that the new food doesn't collide with any - existing foods or arghs. - If one or more corners of the new food hit any existing - argh or food a collision is detected. - */ - collisionDetected = - food_collision(x , y ) >= 0 || - food_collision(x , y + FOOD_SIZE - 1) >= 0 || - food_collision(x + FOOD_SIZE - 1, y ) >= 0 || - food_collision(x + FOOD_SIZE - 1, y + FOOD_SIZE - 1) >= 0 || - argh_collision(x , y ) >= 0 || - argh_collision(x , y + FOOD_SIZE - 1) >= 0 || - argh_collision(x + FOOD_SIZE - 1, y ) >= 0 || - argh_collision(x + FOOD_SIZE - 1, y + FOOD_SIZE - 1) >= 0; - - /* use coordinates for further testing */ - foodx[index] = x; - foody[index] = y; - - /* now test wether we accidently hit the worm with food ;) */ - i = 0; - for (i = 0; i < worm_count && !collisionDetected; i++) { - collisionDetected |= worm_food_collision(&worms[i], index); - } - } - while (collisionDetected); - return tries; -} - -/** - * Clears a food from the lcd buffer. - * @param int index The index of the food arrays under which - * the coordinates of the desired food can be found. Ensure - * that the value is 0 <= index <= MAX_FOOD. - */ -static void clear_food(int index) -{ - /* remove the old food from the screen */ - lcd_clearrect(foodx[index] + FIELD_RECT_X, - foody[index] + FIELD_RECT_Y, - FOOD_SIZE, FOOD_SIZE); -} - -/** - * Draws a food in the lcd buffer. - * @param int index The index of the food arrays under which - * the coordinates of the desired food can be found. Ensure - * that the value is 0 <= index <= MAX_FOOD. - */ -static void draw_food(int index) -{ - /* draw the food object */ - lcd_fillrect(foodx[index] + FIELD_RECT_X, - foody[index] + FIELD_RECT_Y, - FOOD_SIZE, FOOD_SIZE); - lcd_clearrect(foodx[index] + FIELD_RECT_X + 1, - foody[index] + FIELD_RECT_Y + 1, - FOOD_SIZE - 2, FOOD_SIZE - 2); -} - -/** - * Find new coordinates for the argh stored in arghx[index], arghy[index] - * that don't collide with any other food or argh. - * @param int index - * Ensure that 0 <= index < argh_count < MAX_ARGH. - */ -static int make_argh(int index) -{ - int x = -1; - int y = -1; - bool collisionDetected = false; - int tries = 0; - int i; - - 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); - tries ++; - - /* Ensure that the new argh doesn't intersect with any - existing foods or arghs. - If one or more corners of the new argh hit any existing - argh or food an intersection is detected. - */ - collisionDetected = - food_collision(x , y ) >= 0 || - food_collision(x , y + ARGH_SIZE - 1) >= 0 || - food_collision(x + ARGH_SIZE - 1, y ) >= 0 || - food_collision(x + ARGH_SIZE - 1, y + ARGH_SIZE - 1) >= 0 || - argh_collision(x , y ) >= 0 || - argh_collision(x , y + ARGH_SIZE - 1) >= 0 || - argh_collision(x + ARGH_SIZE - 1, y ) >= 0 || - argh_collision(x + ARGH_SIZE - 1, y + ARGH_SIZE - 1) >= 0; - - /* use the candidate coordinates to make a real argh */ - arghx[index] = x; - arghy[index] = y; - - /* now test wether we accidently hit the worm with argh ;) */ - for (i = 0; i < worm_count && !collisionDetected; i++) { - collisionDetected |= worm_argh_collision(&worms[i], index); - collisionDetected |= worm_argh_collision_in_moves(&worms[i], index, - MIN_ARGH_DIST); - } - } - while (collisionDetected); - return tries; -} - -/** - * Draws an argh in the lcd buffer. - * @param int index The index of the argh arrays under which - * the coordinates of the desired argh can be found. Ensure - * that the value is 0 <= index < argh_count <= MAX_ARGH. - */ -static void draw_argh(int index) -{ - /* draw the new argh */ - lcd_fillrect(arghx[index] + FIELD_RECT_X, - arghy[index] + FIELD_RECT_Y, - ARGH_SIZE, ARGH_SIZE); -} - -static void virtual_player(struct worm *w); -/** - * Initialzes the specified worm with INITIAL_WORM_LENGTH - * and the tail at the specified position. The worm will - * be initialized alive and creeping EAST. - * @param struct worm *w The worm that is to be initialized - * @param int x The x coordinate at which the tail of the worm starts. - * x must be 0 <= x < FIELD_RECT_WIDTH. - * @param int y The y coordinate at which the tail of the worm starts - * y must be 0 <= y < FIELD_RECT_WIDTH. - */ -static void init_worm(struct worm *w, int x, int y){ - /* initialize the worm size */ - w->head = 1; - w->tail = 0; - - w->x[w->head] = x + 1; - w->y[w->head] = y; - - w->x[w->tail] = x; - w->y[w->tail] = y; - - /* set the initial direction the worm creeps to */ - w->dirx = 1; - w->diry = 0; - - w->growing = INITIAL_WORM_LENGTH - 1; - w->alive = true; - w->fetch_worm_direction = virtual_player; -} - -/** - * Writes the direction that was stored for - * human player 1 into the specified worm. This function - * may be used to be stored in worm.fetch_worm_direction. - * The value of - * the direction is read from player1_dir. - * @param struct worm *w - The worm of which the direction - * is altered. - */ -static void human_player1(struct worm *w) { - set_worm_dir(w, player1_dir); -} - -/** - * Writes the direction that was stored for - * human player 2 into the specified worm. This function - * may be used to be stored in worm.fetch_worm_direction. - * The value of - * the direction is read from player2_dir. - * @param struct worm *w - The worm of which the direction - * is altered. - */ -static void human_player2(struct worm *w) { - set_worm_dir(w, player2_dir); -} - -/** - * Writes the direction that was stored for - * human player using a remote control - * into the specified worm. This function - * may be used to be stored in worm.fetch_worm_direction. - * The value of - * the direction is read from player3_dir. - * @param struct worm *w - The worm of which the direction - * is altered. - */ -static void remote_player(struct worm *w) { - set_worm_dir(w, player3_dir); -} - -/** - * Initializes the worm-, food- and argh-arrays, draws a frame, - * makes some food and argh and display all that stuff. - */ -static void init_wormlet(void) -{ - int i; - - for (i = 0; i< worm_count; i++) { - /* Initialize all the worm coordinates to center. */ - int x = (int)(FIELD_RECT_WIDTH / 2); - int y = (int)((FIELD_RECT_HEIGHT - 20)/ 2) + i * 10; - - init_worm(&worms[i], x, y); - } - - player1_dir = EAST; - player2_dir = EAST; - player3_dir = EAST; - - if (players > 0) { - worms[0].fetch_worm_direction = human_player1; - } - - if (players > 1) { - if (use_remote) { - worms[1].fetch_worm_direction = remote_player; - } else { - worms[1].fetch_worm_direction = human_player2; - } - } - - if (players > 2) { - worms[2].fetch_worm_direction = human_player2; - } - - /* Needed when the game is restarted using BUTTON_ON */ - lcd_clear_display(); - - /* make and display some food and argh */ - argh_count = MAX_FOOD; - for (i = 0; i < MAX_FOOD; i++) { - make_food(i); - draw_food(i); - make_argh(i); - draw_argh(i); - } - - /* 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); - - /* make everything visible */ - lcd_update(); -} - - -/** - * Move the worm one step further if it is alive. - * The direction in which the worm moves is taken from dirx and diry. - * move_worm decreases growing if > 0. While the worm is growing the tail - * is left untouched. - * @param struct worm *w The worm to move. w must not be NULL. - */ -static void move_worm(struct worm *w) -{ - if (w->alive) { - /* determine the head point and its precessor */ - int headx = w->x[w->head]; - int heady = w->y[w->head]; - int prehead = (w->head + MAX_WORM_SEGMENTS - 1) % MAX_WORM_SEGMENTS; - int preheadx = w->x[prehead]; - int preheady = w->y[prehead]; - - /* determine the old direction */ - int olddirx; - int olddiry; - if (headx == preheadx) { - olddirx = 0; - olddiry = (heady > preheady) ? 1 : -1; - } else { - olddiry = 0; - olddirx = (headx > preheadx) ? 1 : -1; - } - - /* olddir == dir? - a change of direction means a new segment - has been opened */ - if (olddirx != w->dirx || - olddiry != w->diry) { - w->head = (w->head + 1) % MAX_WORM_SEGMENTS; - } - - /* new head position */ - w->x[w->head] = headx + w->dirx; - w->y[w->head] = heady + w->diry; - - - /* while the worm is growing no tail procession is necessary */ - if (w->growing > 0) { - /* update the worms grow state */ - w->growing--; - } - - /* if the worm isn't growing the tail has to be dragged */ - else { - /* index of the end of the tail segment */ - int tail_segment_end = (w->tail + 1) % MAX_WORM_SEGMENTS; - - /* drag the end of the tail */ - /* only one coordinate has to be altered. Here it is - determined which one */ - int dir = 0; /* specifies wether the coord has to be in- or decreased */ - if (w->x[w->tail] == w->x[tail_segment_end]) { - dir = (w->y[w->tail] - w->y[tail_segment_end] < 0) ? 1 : -1; - w->y[w->tail] += dir; - } else { - dir = (w->x[w->tail] - w->x[tail_segment_end] < 0) ? 1 : -1; - w->x[w->tail] += dir; - } - - /* when the tail has been dragged so far that it meets - the next segment start the tail segment is obsolete and - must be freed */ - if (w->x[w->tail] == w->x[tail_segment_end] && - w->y[w->tail] == w->y[tail_segment_end]){ - - /* drop the last tail point */ - w->tail = tail_segment_end; - } - } - } -} - -/** - * Draws the head and clears the tail of the worm in - * the display buffer. lcd_update() is NOT called thus - * the caller has to take care that the buffer is displayed. - */ -static void draw_worm(struct worm *w) -{ - /* draw the new head */ - 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); - } - - /* 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); - } -} - -/** - * Checks wether the coordinate is part of the worm. Returns - * true if any part of the worm was hit - including the head. - * @param x int The x coordinate - * @param y int The y coordinate - * @return int The index of the worm arrays that contain x, y. - * Returns -1 if the coordinates are not part of the worm. - */ -static int specific_worm_collision(struct worm *w, int x, int y) -{ - int retVal = -1; - - /* get_worm_array_length is expensive -> buffer the value */ - int wormLength = get_worm_array_length(w); - int i; - - /* test each entry that is part of the worm */ - for (i = 0; i < wormLength && retVal == -1; i++) { - - /* The iteration iterates the length of the worm. - Here's the conversion to the true indices within the worm arrays. */ - int linestart = (w->tail + i ) % MAX_WORM_SEGMENTS; - int lineend = (linestart + 1) % MAX_WORM_SEGMENTS; - bool samex = (w->x[linestart] == x) && (w->x[lineend] == x); - bool samey = (w->y[linestart] == y) && (w->y[lineend] == y); - if (samex || samey){ - int test, min, max, tmp; - - if (samey) { - min = w->x[linestart]; - max = w->x[lineend]; - test = x; - } else { - min = w->y[linestart]; - max = w->y[lineend]; - test = y; - } - - tmp = min; - min = MIN(min, max); - max = MAX(tmp, max); - - if (min <= test && test <= max) { - retVal = lineend; - } - } - } - return retVal; -} - -/** - * Increases the length of the specified worm by marking - * that it may grow by len pixels. Note that the worm has - * to move to make the growing happen. - * @param worm *w The worm that is to be altered. - * @param int len A positive value specifying the amount of - * pixels the worm may grow. - */ -static void add_growing(struct worm *w, int len) { - w->growing += len; -} - -/** - * Determins the worm that is at the coordinates x, y. The parameter - * w is a switch parameter that changes the functionality of worm_collision. - * If w is specified and x,y hits the head of w NULL is returned. - * This is a useful way to determine wether the head of w hits - * any worm but including itself but excluding its own head. - * (It hits always its own head ;)) - * If w is set to NULL worm_collision returns any worm including all heads - * that is at position of x,y. - * @param struct worm *w The worm of which the head should be excluded in - * the test. w may be set to NULL. - * @param int x The x coordinate that is checked - * @param int y The y coordinate that is checkec - * @return struct worm* The worm that has been hit by x,y. If no worm - * was at the position NULL is returned. - */ -static struct worm* worm_collision(struct worm *w, int x, int y){ - struct worm *retVal = NULL; - int i; - for (i = 0; (i < worm_count) && (retVal == NULL); i++) { - int collision_at = specific_worm_collision(&worms[i], x, y); - if (collision_at != -1) { - if (!(w == &worms[i] && collision_at == w->head)){ - retVal = &worms[i]; - } - } - } - return retVal; -} - -/** - * Returns true if the head of the worm just has - * crossed the field boundaries. - * @return bool true if the worm just has wrapped. - */ -static bool field_collision(struct worm *w) -{ - bool retVal = false; - if ((w->x[w->head] >= FIELD_RECT_WIDTH) || - (w->y[w->head] >= FIELD_RECT_HEIGHT) || - (w->x[w->head] < 0) || - (w->y[w->head] < 0)) - { - retVal = true; - } - return retVal; -} - - -/** - * Returns true if the specified coordinates are within the - * field specified by the FIELD_RECT_XXX constants. - * @param int x The x coordinate of the point that is investigated - * @param int y The y coordinate of the point that is investigated - * @return bool Returns false if x,y specifies a point outside the - * field of worms. - */ -static bool is_in_field_rect(int x, int y) { - bool retVal = false; - retVal = (x >= 0 && x < FIELD_RECT_WIDTH && - y >= 0 && y < FIELD_RECT_HEIGHT); - return retVal; -} - -/** - * Checks and returns wether the head of the w - * is colliding with something currently. - * @return int One of the values: - * COLLISION_NONE - * COLLISION_w - * COLLISION_FOOD - * COLLISION_ARGH - * COLLISION_FIELD - */ -static int check_collision(struct worm *w) -{ - int retVal = COLLISION_NONE; - - if (worm_collision(w, w->x[w->head], w->y[w->head]) != NULL) - retVal = COLLISION_WORM; - - if (food_collision(w->x[w->head], w->y[w->head]) >= 0) - retVal = COLLISION_FOOD; - - if (argh_collision(w->x[w->head], w->y[w->head]) >= 0) - retVal = COLLISION_ARGH; - - if (field_collision(w)) - retVal = COLLISION_FIELD; - - return retVal; -} - -/** - * Returns the index of the food that is closest to the point - * specified by x, y. This index may be used in the foodx and - * foody arrays. - * @param int x The x coordinate of the point - * @param int y The y coordinate of the point - * @return int A value usable as index in foodx and foody. - */ -static int get_nearest_food(int x, int y){ - int nearestfood = 0; - int olddistance = FIELD_RECT_WIDTH + FIELD_RECT_HEIGHT; - int deltax = 0; - int deltay = 0; - int foodindex; - for (foodindex = 0; foodindex < MAX_FOOD; foodindex++) { - int distance; - deltax = foodx[foodindex] - x; - deltay = foody[foodindex] - y; - deltax = deltax > 0 ? deltax : deltax * (-1); - deltay = deltay > 0 ? deltay : deltay * (-1); - distance = deltax + deltay; - - if (distance < olddistance) { - olddistance = distance; - nearestfood = foodindex; - } - } - return nearestfood; -} - -/** - * Returns wether the specified position is next to the worm - * and in the direction the worm looks. Use this method to - * test wether this position would be hit with the next move of - * the worm unless the worm changes its direction. - * @param struct worm *w - The worm to be investigated - * @param int x - The x coordinate of the position to test. - * @param int y - The y coordinate of the position to test. - * @return Returns true if the worm will hit the position unless - * it change its direction before the next move. - */ -static bool is_in_front_of_worm(struct worm *w, int x, int y) { - bool infront = false; - int deltax = x - w->x[w->head]; - int deltay = y - w->y[w->head]; - - if (w->dirx == 0) { - infront = (w->diry * deltay) > 0; - } else { - infront = (w->dirx * deltax) > 0; - } - return infront; -} - -/** - * Returns true if the worm will collide with the next move unless - * it changes its direction. - * @param struct worm *w - The worm to be investigated. - * @return Returns true if the worm will collide with the next move - * unless it changes its direction. - */ -static bool will_worm_collide(struct worm *w) { - int x = w->x[w->head] + w->dirx; - int y = w->y[w->head] + w->diry; - bool retVal = !is_in_field_rect(x, y); - if (!retVal) { - retVal = (argh_collision(x, y) != -1); - } - - if (!retVal) { - retVal = (worm_collision(w, x, y) != NULL); - } - return retVal; -} - -/** - * This function - * may be used to be stored in worm.fetch_worm_direction for - * worms that are not controlled by humans but by artificial stupidity. - * A direction is searched that doesn't lead to collision but to the nearest - * food - but not very intelligent. The direction is written to the specified - * worm. - * @param struct worm *w - The worm of which the direction - * is altered. - */ -static void virtual_player(struct worm *w) { - bool isright; - int plana, planb, planc; - /* find the next lunch */ - int nearestfood = get_nearest_food(w->x[w->head], w->y[w->head]); - - /* determine in which direction it is */ - - /* in front of me? */ - bool infront = is_in_front_of_worm(w, foodx[nearestfood], foody[nearestfood]); - - /* left right of me? */ - int olddir = get_worm_dir(w); - set_worm_dir(w, (olddir + 1) % 4); - isright = is_in_front_of_worm(w, foodx[nearestfood], foody[nearestfood]); - set_worm_dir(w, olddir); - - /* detect situation, set strategy */ - if (infront) { - if (isright) { - plana = olddir; - planb = (olddir + 1) % 4; - planc = (olddir + 3) % 4; - } else { - plana = olddir; - planb = (olddir + 3) % 4; - planc = (olddir + 1) % 4; - } - } else { - if (isright) { - plana = (olddir + 1) % 4; - planb = olddir; - planc = (olddir + 3) % 4; - } else { - plana = (olddir + 3) % 4; - planb = olddir; - planc = (olddir + 1) % 4; - } - } - - /* test for collision */ - set_worm_dir(w, plana); - if (will_worm_collide(w)){ - - /* plan b */ - set_worm_dir(w, planb); - - /* test for collision */ - if (will_worm_collide(w)) { - - /* plan c */ - set_worm_dir(w, planc); - } - } -} - -/** - * prints out the score board with all the status information - * about the game. - */ -static void score_board(void) -{ - char buf[15]; - char buf2[15]; - int i; - int y = 0; - 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]); - - /* high score */ - if (worms[i].fetch_worm_direction != virtual_player){ - if (highscore < score) { - highscore = score; - } - } - - /* length */ - snprintf(buf, sizeof (buf),str(LANG_WORMLET_LENGTH), score); - - /* worm state */ - switch (check_collision(&worms[i])) { - case COLLISION_NONE: - if (worms[i].growing > 0){ - snprintf(buf2, sizeof(buf2), str(LANG_WORMLET_GROWING)); - } - else { - if (worms[i].alive) { - snprintf(buf2, sizeof(buf2), str(LANG_WORMLET_HUNGRY)); - } else { - snprintf(buf2, sizeof(buf2), str(LANG_WORMLET_WORMED)); - } - } - break; - - case COLLISION_WORM: - snprintf(buf2, sizeof(buf2), str(LANG_WORMLET_WORMED)); - break; - - case COLLISION_FOOD: - snprintf(buf2, sizeof(buf2), str(LANG_WORMLET_GROWING)); - break; - - case COLLISION_ARGH: - snprintf(buf2, sizeof(buf2), str(LANG_WORMLET_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); - - if (!worms[i].alive){ - 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); -#ifndef DEBUG_WORMLET - lcd_putsxy(FIELD_RECT_WIDTH + 3, LCD_HEIGHT - 8, buf); -#else - lcd_putsxy(FIELD_RECT_WIDTH + 3, LCD_HEIGHT - 8, debugout); -#endif -} - -/** - * Checks for collisions of the worm and its environment and - * takes appropriate actions like growing the worm or killing it. - * @return bool Returns true if the worm is dead. Returns - * false if the worm is healthy, up and creeping. - */ -static bool process_collisions(struct worm *w) -{ - int index = -1; - - w->alive &= !field_collision(w); - - if (w->alive) { - - /* check if food was eaten */ - index = food_collision(w->x[w->head], w->y[w->head]); - if (index != -1){ - int i; - - clear_food(index); - make_food(index); - draw_food(index); - - for (i = 0; i < ARGHS_PER_FOOD; i++) { - argh_count++; - if (argh_count > MAX_ARGH) - argh_count = MAX_ARGH; - make_argh(argh_count - 1); - draw_argh(argh_count - 1); - } - - add_growing(w, WORM_PER_FOOD); - - draw_worm(w); - } - - /* check if argh was eaten */ - else { - index = argh_collision(w->x[w->head], w->y[w->head]); - if (index != -1) { - w->alive = false; - } - else { - if (worm_collision(w, w->x[w->head], w->y[w->head]) != NULL) { - w->alive = false; - } - } - } - } - return !w->alive; -} - -/** - * The main loop of the game. - * @return bool Returns true if the game ended - * with a dead worm. Returns false if the user - * aborted the game manually. - */ -static bool run(void) -{ - int button = 0; - int wormDead = false; - - /* ticks are counted to compensate speed variations */ - long cycle_start = 0, cycle_end = 0; -#ifdef DEBUG_WORMLET - int ticks_to_max_cycle_reset = 20; - long max_cycle = 0; - char buf[20]; -#endif - - /* initialize the board and so on */ - init_wormlet(); - - cycle_start = current_tick; - /* change the direction of the worm */ - while (button != BUTTON_OFF && ! wormDead) - { - int i; - long cycle_duration ; - switch (button) { - case BUTTON_UP: - if (players == 1 && !use_remote) { - player1_dir = NORTH; - } - break; - - case BUTTON_DOWN: - if (players == 1 && !use_remote) { - player1_dir = SOUTH; - } - break; - - case BUTTON_LEFT: - if (players != 1 || use_remote) { - player1_dir = (player1_dir + 3) % 4; - } else { - player1_dir = WEST; - } - break; - - case BUTTON_RIGHT: - if (players != 1 || use_remote) { - player1_dir = (player1_dir + 1) % 4; - } else { - player1_dir = EAST; - } - break; - - case BUTTON_F2: - player2_dir = (player2_dir + 3) % 4; - break; - - case BUTTON_F3: - player2_dir = (player2_dir + 1) % 4; - break; - - case BUTTON_RC_VOL_UP: - player3_dir = (player3_dir + 1) % 4; - break; - - case BUTTON_RC_VOL_DOWN: - player3_dir = (player3_dir + 3) % 4; - break; - - case BUTTON_PLAY: - do { - button = button_get(true); - } while (button != BUTTON_PLAY && - button != BUTTON_OFF && - button != BUTTON_ON); - break; - } - - for (i = 0; i < worm_count; i++) { - worms[i].fetch_worm_direction(&worms[i]); - } - - wormDead = true; - for (i = 0; i < worm_count; i++){ - struct worm *w = &worms[i]; - move_worm(w); - wormDead &= process_collisions(w); - draw_worm(w); - } - score_board(); - lcd_update(); - if (button == BUTTON_ON) { - wormDead = true; - } - - /* here the wormlet game cycle ends - thus the current tick is stored - as end time */ - cycle_end = current_tick; - - /* The duration of the game cycle */ - cycle_duration = cycle_end - cycle_start; - cycle_duration = MAX(0, cycle_duration); - cycle_duration = MIN(SPEED -1, cycle_duration); - - -#ifdef DEBUG_WORMLET - ticks_to_max_cycle_reset--; - if (ticks_to_max_cycle_reset <= 0) { - max_cycle = 0; - } - - if (max_cycle < cycle_duration) { - max_cycle = cycle_duration; - ticks_to_max_cycle_reset = 20; - } - 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; - - } - return wormDead; -} - -#ifdef DEBUG_WORMLET - -/** - * Just a test routine that checks that worm_food_collision works - * in some typical situations. - */ -static void test_worm_food_collision(void) { - int collision_count = 0; - int i; - lcd_clear_display(); - init_worm(&worms[0], 10, 10); - add_growing(&worms[0], 10); - set_worm_dir(&worms[0], EAST); - for (i = 0; i < 10; i++) { - move_worm(&worms[0]); - draw_worm(&worms[0]); - } - - set_worm_dir(&worms[0], SOUTH); - for (i = 0; i < 10; i++) { - move_worm(&worms[0]); - draw_worm(&worms[0]); - } - - foodx[0] = 15; - foody[0] = 12; - for (foody[0] = 20; foody[0] > 0; foody[0] --) { - char buf[20]; - bool collision; - draw_worm(&worms[0]); - draw_food(0); - collision = worm_food_collision(&worms[0], 0); - if (collision) { - collision_count++; - } - snprintf(buf, sizeof buf, "collisions: %d", collision_count); - lcd_putsxy(0, LCD_HEIGHT -8, buf); - lcd_update(); - } - if (collision_count != FOOD_SIZE) { - button_get(true); - } - - - foody[0] = 15; - for (foodx[0] = 30; foodx[0] > 0; foodx[0] --) { - char buf[20]; - bool collision; - draw_worm(&worms[0]); - draw_food(0); - collision = worm_food_collision(&worms[0], 0); - if (collision) { - collision_count ++; - } - snprintf(buf, sizeof buf, "collisions: %d", collision_count); - lcd_putsxy(0, LCD_HEIGHT -8, buf); - lcd_update(); - } - if (collision_count != FOOD_SIZE * 2) { - button_get(true); - } - -} - - -static bool expensive_worm_in_rect(struct worm *w, int rx, int ry, int rw, int rh){ - int x, y; - bool retVal = false; - for (x = rx; x < rx + rw; x++){ - for (y = ry; y < ry + rh; y++) { - if (specific_worm_collision(w, x, y) != -1) { - retVal = true; - } - } - } - return retVal; -} - -static void test_worm_argh_collision(void) { - int i; - int dir; - int collision_count = 0; - lcd_clear_display(); - init_worm(&worms[0], 10, 10); - add_growing(&worms[0], 40); - for (dir = 0; dir < 4; dir++) { - set_worm_dir(&worms[0], (EAST + dir) % 4); - for (i = 0; i < 10; i++) { - move_worm(&worms[0]); - draw_worm(&worms[0]); - } - } - - arghx[0] = 12; - for (arghy[0] = 0; arghy[0] < FIELD_RECT_HEIGHT - ARGH_SIZE; arghy[0]++){ - char buf[20]; - bool collision; - draw_argh(0); - collision = worm_argh_collision(&worms[0], 0); - if (collision) { - collision_count ++; - } - snprintf(buf, sizeof buf, "collisions: %d", collision_count); - lcd_putsxy(0, LCD_HEIGHT -8, buf); - lcd_update(); - } - if (collision_count != ARGH_SIZE * 2) { - button_get(true); - } - - arghy[0] = 12; - for (arghx[0] = 0; arghx[0] < FIELD_RECT_HEIGHT - ARGH_SIZE; arghx[0]++){ - char buf[20]; - bool collision; - draw_argh(0); - collision = worm_argh_collision(&worms[0], 0); - if (collision) { - collision_count ++; - } - snprintf(buf, sizeof buf, "collisions: %d", collision_count); - lcd_putsxy(0, LCD_HEIGHT -8, buf); - lcd_update(); - } - if (collision_count != ARGH_SIZE * 4) { - button_get(true); - } -} - -static int testline_in_rect(void) { - int testfailed = -1; - - int rx = 10; - int ry = 15; - int rw = 20; - int rh = 25; - - /* Test 1 */ - int x1 = 12; - int y1 = 8; - int x2 = 12; - int y2 = 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_update(); - lcd_putsxy(0, 0, "failed 1"); - button_get(true); - testfailed = 1; - } - - /* test 2 */ - 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); - testfailed = 2; - } - - /* test 3 */ - 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); - testfailed = 3; - } - - /* test 4 */ - 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); - testfailed = 4; - } - - /* test 5 */ - 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); - testfailed = 5; - } - - /* test 6 */ - y1 = 5; - 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); - testfailed = 6; - } - - /* test 7 */ - x1 = 8; - y1 = 20; - x2 = 35; - 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); - testfailed = 7; - } - - /* test 8 */ - 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); - testfailed = 8; - } - - /* test 9 */ - 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); - testfailed = 9; - } - - /* test 10 */ - 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); - testfailed = 10; - } - - /* test 11 */ - 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); - testfailed = 11; - } - - /* test 12 */ - x1 = 5; - 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); - testfailed = 12; - } - - /* test 13 */ - rx = 9; - ry = 15; - rw = FOOD_SIZE; - rh = FOOD_SIZE; - - x1 = 10; - y1 = 10; - x2 = 10; - 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); - testfailed = 13; - } - - /* test 14 */ - rx = 9; - ry = 15; - rw = 4; - rh = 4; - - x1 = 10; - y1 = 10; - x2 = 10; - 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); - testfailed = 14; - } - - lcd_clear_display(); - - return testfailed; -} - -/** - * Just a test routine to test wether specific_worm_collision might work properly - */ -static int test_specific_worm_collision(void) { - int collisions = 0; - int dir; - int x = 0; - int y = 0; - char buf[20]; - lcd_clear_display(); - init_worm(&worms[0], 10, 20); - add_growing(&worms[0], 20 - INITIAL_WORM_LENGTH); - - for (dir = EAST; dir < EAST + 4; dir++) { - int i; - set_worm_dir(&worms[0], dir % 4); - for (i = 0; i < 5; i++) { - if (!(dir % 4 == NORTH && i == 9)) { - move_worm(&worms[0]); - draw_worm(&worms[0]); - } - } - } - - for (y = 15; y < 30; y ++){ - for (x = 5; x < 20; x++) { - 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(); - } - } - if (collisions != 21) { - button_get(true); - } - return collisions; -} - -static void test_make_argh(void){ - int dir; - int seed = 0; - int hit = 0; - int failures = 0; - int last_failures = 0; - int i, worm_idx; - lcd_clear_display(); - worm_count = 3; - - for (worm_idx = 0; worm_idx < worm_count; worm_idx++) { - init_worm(&worms[worm_idx], 10 + worm_idx * 20, 20); - add_growing(&worms[worm_idx], 40 - INITIAL_WORM_LENGTH); - } - - for (dir = EAST; dir < EAST + 4; dir++) { - for (worm_idx = 0; worm_idx < worm_count; worm_idx++) { - set_worm_dir(&worms[worm_idx], dir % 4); - for (i = 0; i < 10; i++) { - if (!(dir % 4 == NORTH && i == 9)) { - move_worm(&worms[worm_idx]); - draw_worm(&worms[worm_idx]); - } - } - } - } - - 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); - - 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); - - 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(); - 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); - - if (failures > last_failures) { - button_get(true); - } - last_failures = failures; - hit ++; - } - } - } -} - -static void test_worm_argh_collision_in_moves(void) { - int hit_count = 0; - int i; - lcd_clear_display(); - init_worm(&worms[0], 10, 20); - - arghx[0] = 20; - arghy[0] = 18; - draw_argh(0); - - set_worm_dir(&worms[0], EAST); - for (i = 0; i < 20; i++) { - char buf[20]; - move_worm(&worms[0]); - draw_worm(&worms[0]); - 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(); - } - if (hit_count != ARGH_SIZE + 5) { - button_get(true); - } -} -#endif /* DEBUG_WORMLET */ - -extern bool use_old_rect; - -/** - * Main entry point from the menu to start the game control. - */ -bool wormlet(void) -{ - bool worm_dead = false; - int button; - - lcd_setfont(FONT_SYSFIXED); - -#ifdef DEBUG_WORMLET - testline_in_rect(); - test_worm_argh_collision_in_moves(); - test_make_argh(); - test_worm_food_collision(); - test_worm_argh_collision(); - test_specific_worm_collision(); -#endif - lcd_setmargins(0,0); - - /* Setup screen */ - do { - char buf[20]; - lcd_clear_display(); - - /* first line players */ - snprintf(buf, sizeof buf, str(LANG_WORMLET_PLAYERS), players); - lcd_puts(0, 0, buf); - - /* second line worms */ - snprintf(buf, sizeof buf, str(LANG_WORMLET_WORMS), worm_count); - lcd_puts(0, 1, buf); - - /* third line control */ - if (players > 1) { - if (use_remote) { - snprintf(buf, sizeof buf, str(LANG_WORMLET_REMOTE_CTRL)); - } else { - snprintf(buf, sizeof buf, str(LANG_WORMLET_NO_REM_CTRL)); - } - } else { - if (players > 0) { - if (use_remote) { - snprintf(buf, sizeof buf, str(LANG_WORMLET_2_KEY_CTRL)); - } else { - snprintf(buf, sizeof buf, str(LANG_WORMLET_4_KEY_CTRL)); - } - } else { - snprintf(buf, sizeof buf, str(LANG_WORMLET_NO_CONTROL)); - } - } - lcd_puts(0, 2, buf); - lcd_update(); - - /* user selection */ - button = button_get(true); - switch (button) { - case BUTTON_UP: - if (players < 3) { - players ++; - if (players > worm_count) { - worm_count = players; - } - if (players > 2) { - use_remote = true; - } - } - break; - case BUTTON_DOWN: - if (players > 0) { - players --; - } - break; - case BUTTON_LEFT: - if (worm_count > 1) { - worm_count--; - if (worm_count < players) { - players = worm_count; - } - } - break; - case BUTTON_RIGHT: - if (worm_count < MAX_WORMS) { - worm_count ++; - } - break; - case BUTTON_F1: - use_remote = !use_remote; - if (players > 2) { - use_remote = true; - } - break; - - case SYS_USB_CONNECTED: - usb_screen(); - lcd_setfont(FONT_UI); - return true; - } - } while (button != BUTTON_PLAY && - button != BUTTON_OFF && button != BUTTON_ON); - - lcd_clear_display(); - /* end of setup */ - - do { - - /* button state will be overridden if - the game quits with the death of the worm. - Initializing button to BUTTON_OFF ensures - that the user can hit BUTTON_OFF during the - game to return to the menu. - */ - button = BUTTON_OFF; - - /* start the game */ - worm_dead = run(); - - /* if worm isn't dead the game was quit - via BUTTON_OFF -> no need to wait for buttons. */ - if (worm_dead) { - do { - button = button_get(true); - } - /* BUTTON_ON -> start new game */ - /* BUTTON_OFF -> back to game menu */ - while (button != BUTTON_OFF && button != BUTTON_ON); - } - } - while (button != BUTTON_OFF); - - lcd_setfont(FONT_UI); - - return false; -} - - -#endif /* USE_GAMES */ - - - - - - - - - - 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.c b/apps/viewer.c deleted file mode 100644 index f653866626..0000000000 --- a/apps/viewer.c +++ /dev/null @@ -1,432 +0,0 @@ -/*************************************************************************** - * - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Copyright (C) 2002 Gilles Roux - * - * 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 -#include -#include -#include - -#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" - - -#define BUFFER_SIZE 1024 - -#define OUTSIDE_BUFFER -10 -#define OUTSIDE_FILE -11 - -static int fd; -static int file_size; - -static char buffer[BUFFER_SIZE+1]; -static int buffer_pos; /* Position of the buffer in the file */ - -static char display_lines; /* number of lines on the display */ -static char display_columns; /* number of columns on the display */ -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 */ - -/* - * Known issue: The caching algorithm will fail (display incoherent data) if - * the total space of the lines that are displayed on the screen exceeds the - * buffer size (only happens with very long lines). - */ - -static void display_line_count(void) -{ -#ifdef HAVE_LCD_BITMAP - int w,h; - lcd_getstringsize("M", &w, &h); - display_lines = LCD_HEIGHT / h; - display_columns = LCD_WIDTH / w; -#else - display_lines = 2; - display_columns = 11; -#endif -} - -static int find_next_line(int pos) -{ - int i; - - if (pos==OUTSIDE_BUFFER || pos==OUTSIDE_FILE) - return pos; - - i = pos; - if (buffer_pos+i>=file_size) { - return OUTSIDE_FILE; - } - while (1) { - i++; - if (buffer_pos+i==file_size) { - return i; - } - if (i>=BUFFER_SIZE) { - return OUTSIDE_BUFFER; - } - if (buffer[i]==0) { - return i; - } - } -} - -static int find_prev_line(int pos) -{ - int i; - - if (pos==OUTSIDE_BUFFER || pos==OUTSIDE_FILE) - return pos; - - i = pos; - if (buffer_pos+i<0) { - return OUTSIDE_FILE; - } - while (1) { - i--; - if (buffer_pos+i<0) { - return i; - } - if (i<0) { - return OUTSIDE_BUFFER; - } - if (buffer[i]==0) { - return i; - } - } -} - -static void viewer_draw(int col) -{ - int i, j; - char* str; - int line_pos; - - lcd_clear_display(); - - line_pos = begin_line_pos; - - for (i=0; i <= end_line - begin_line; i++) { - if (line_pos == OUTSIDE_BUFFER || - line_pos == OUTSIDE_FILE) - break; - str = buffer + line_pos + 1; - for (j=0; j=file_size-BUFFER_SIZE) - pos = file_size-BUFFER_SIZE; - if (pos<0) - pos = 0; - - lseek(fd, pos, SEEK_SET); - numread = read(fd, buffer, BUFFER_SIZE); - - begin_line_pos -= pos - buffer_pos; - end_line_pos -= pos - buffer_pos; - buffer_pos = pos; - - buffer[numread] = 0; - for(i=0;i ) \___| < | \_\ ( <_> > < < - * 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 */ -- cgit v1.2.3