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
This commit is contained in:
Björn Stenberg 2003-06-29 16:33:04 +00:00
parent 9bcbe3fd72
commit ba371fb595
29 changed files with 1869 additions and 1889 deletions

View File

@ -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)

View File

@ -24,19 +24,38 @@
#include <stdio.h>
#include <stdbool.h>
#include "lcd.h"
#include "menu.h"
#include "demo_menu.h"
#include "button.h"
#include "kernel.h"
#include "sprintf.h"
#include "lang.h"
#include "plugin.h"
extern bool bounce(void);
extern bool snow(void);
extern bool cube(void);
extern bool oscillograph(void);
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;
}
static bool oscillograph(void)
{
if (plugin_load("/.rockbox/rocks/oscillograph.rock",NULL)==PLUGIN_USB_CONNECTED)
return true;
return false;
}
bool demo_menu(void)
{

View File

@ -25,18 +25,31 @@
#include <stdio.h>
#include <stdbool.h>
#include "lcd.h"
#include "menu.h"
#include "games_menu.h"
#include "button.h"
#include "kernel.h"
#include "sprintf.h"
#include "sokoban.h"
#include "wormlet.h"
#include "lang.h"
#include "plugin.h"
extern bool tetris(void);
static bool tetris(void)
{
if (plugin_load("/.rockbox/rocks/tetris.rock",NULL)==PLUGIN_USB_CONNECTED)
return true;
return false;
}
static bool sokoban(void)
{
if (plugin_load("/.rockbox/rocks/sokoban.rock",NULL)==PLUGIN_USB_CONNECTED)
return true;
return false;
}
static bool wormlet(void)
{
if (plugin_load("/.rockbox/rocks/wormlet.rock",NULL)==PLUGIN_USB_CONNECTED)
return true;
return false;
}
bool games_menu(void)
{

View File

@ -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:

View File

@ -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

221
apps/plugin.c Normal file
View File

@ -0,0 +1,221 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2002 Björn Stenberg
*
* All files in this archive are subject to the GNU General Public License.
* See the file COPYING in the source tree root for full license agreement.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#include <stdbool.h>
#include <string.h>
#include <stdio.h>
#include "button.h"
#include "lcd.h"
#include "dir.h"
#include "file.h"
#include "kernel.h"
#include "sprintf.h"
#include "screens.h"
#include "misc.h"
#include "mas.h"
#include "plugin.h"
#include "lang.h"
#ifdef SIMULATOR
#include <dlfcn.h>
#define PREFIX(_x_) x11_ ## _x_
#else
#define PREFIX(_x_) _x_
#endif
static int plugin_test(int api_version, int model);
static struct plugin_api rockbox_api = {
PLUGIN_API_VERSION,
plugin_test,
/* lcd */
lcd_clear_display,
lcd_puts,
lcd_puts_scroll,
lcd_stop_scroll,
#ifdef HAVE_LCD_CHARCELLS
lcd_define_pattern,
#else
lcd_putsxy,
lcd_bitmap,
lcd_drawline,
lcd_clearline,
lcd_drawpixel,
lcd_clearpixel,
lcd_setfont,
lcd_clearrect,
lcd_fillrect,
lcd_drawrect,
lcd_invertrect,
lcd_getstringsize,
lcd_update,
lcd_update_rect,
#ifndef SIMULATOR
lcd_roll,
#endif
#endif
/* button */
button_get,
button_get_w_tmo,
/* file */
PREFIX(open),
PREFIX(close),
read,
lseek,
PREFIX(creat),
write,
remove,
rename,
ftruncate,
PREFIX(filesize),
fprintf,
read_line,
/* dir */
PREFIX(opendir),
PREFIX(closedir),
PREFIX(readdir),
/* kernel */
PREFIX(sleep),
usb_screen,
&current_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;
}

161
apps/plugin.h Normal file
View File

@ -0,0 +1,161 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2002 Björn Stenberg
*
* All files in this archive are subject to the GNU General Public License.
* See the file COPYING in the source tree root for full license agreement.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#ifndef _PLUGIN_H_
#define _PLUGIN_H_
/* instruct simulator code to not redefine any symbols when compiling plugins.
(the PLUGIN macro is defined in apps/plugins/Makefile) */
#ifdef PLUGIN
#define NO_REDEFINES_PLEASE
#endif
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include "config.h"
#include "dir.h"
#include "kernel.h"
#include "button.h"
#include "font.h"
#include "system.h"
#include "lcd.h"
/* increase this every time the api struct changes */
#define PLUGIN_API_VERSION 1
/* plugin return codes */
enum plugin_status {
PLUGIN_OK = 0,
PLUGIN_USB_CONNECTED,
PLUGIN_WRONG_API_VERSION = -1,
PLUGIN_WRONG_MODEL = -2,
PLUGIN_ERROR = -3,
};
/* different (incompatible) plugin models */
enum model {
PLAYER,
RECORDER
};
#ifdef HAVE_LCD_CHARCELLS
#define MODEL PLAYER
#else
#define MODEL RECORDER
#endif
/* compatibility test macro */
#define TEST_PLUGIN_API(_api_) \
do { \
int _rc_ = _api_->plugin_test(PLUGIN_API_VERSION, MODEL); \
if (_rc_<0) \
return _rc_; \
} while(0)
struct plugin_api {
/* these two fields must always be first, to ensure
TEST_PLUGIN_API will always work */
int version;
int (*plugin_test)(int api_version, int model);
/* lcd */
void (*lcd_clear_display)(void);
void (*lcd_puts)(int x, int y, unsigned char *string);
void (*lcd_puts_scroll)(int x, int y, unsigned char* string);
void (*lcd_stop_scroll)(void);
#ifdef HAVE_LCD_CHARCELLS
void (*lcd_define_pattern)(int which,char *pattern);
#else
void (*lcd_putsxy)(int x, int y, unsigned char *string);
void (*lcd_bitmap)(unsigned char *src, int x, int y,
int nx, int ny, bool clear);
void (*lcd_drawline)(int x1, int y1, int x2, int y2);
void (*lcd_clearline)(int x1, int y1, int x2, int y2);
void (*lcd_drawpixel)(int x, int y);
void (*lcd_clearpixel)(int x, int y);
void (*lcd_setfont)(int font);
void (*lcd_clearrect)(int x, int y, int nx, int ny);
void (*lcd_fillrect)(int x, int y, int nx, int ny);
void (*lcd_drawrect)(int x, int y, int nx, int ny);
void (*lcd_invertrect)(int x, int y, int nx, int ny);
int (*lcd_getstringsize)(unsigned char *str, int *w, int *h);
void (*lcd_update)(void);
void (*lcd_update_rect)(int x, int y, int width, int height);
#ifndef SIMULATOR
void (*lcd_roll)(int pixels);
#endif
#endif
/* button */
int (*button_get)(bool block);
int (*button_get_w_tmo)(int ticks);
/* file */
int (*open)(const char* pathname, int flags);
int (*close)(int fd);
int (*read)(int fd, void* buf, int count);
int (*lseek)(int fd, int offset, int whence);
int (*creat)(const char *pathname, int mode);
int (*write)(int fd, void* buf, int count);
int (*remove)(const char* pathname);
int (*rename)(const char* path, const char* newname);
int (*ftruncate)(int fd, unsigned int size);
int (*filesize)(int fd);
int (*fprintf)(int fd, const char *fmt, ...);
int (*read_line)(int fd, char* buffer, int buffer_size);
/* dir */
DIR* (*opendir)(char* name);
int (*closedir)(DIR* dir);
struct dirent* (*readdir)(DIR* dir);
/* kernel */
void (*sleep)(int ticks);
void (*usb_screen)(void);
long* current_tick;
/* strings and memory */
int (*snprintf)(char *buf, size_t size, const char *fmt, ...);
char* (*strcpy)(char *dst, const char *src);
size_t (*strlen)(const char *str);
void* (*memset)(void *dst, int c, size_t length);
void* (*memcpy)(void *out, const void *in, size_t n);
/* sound */
#ifndef SIMULATOR
#ifdef HAVE_MAS3587F
int (*mas_codec_readreg)(int reg);
#endif
#endif
/* misc */
void (*srand)(unsigned int seed);
int (*rand)(void);
void (*splash)(int ticks, int keymask, bool center, char *fmt, ...);
};
/* defined by the plugin loader (plugin.c) */
int plugin_load(char* plugin, void* parameter);
/* defined by the plugin */
enum plugin_status plugin_start(struct plugin_api* rockbox, void* parameter)
__attribute__ ((section (".entry")));
#endif

45
apps/plugins/Makefile Normal file
View File

@ -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)

View File

@ -15,26 +15,10 @@
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
**************************************************************************/
#include "plugin.h"
#include "config.h"
#include "options.h"
#ifdef USE_DEMOS
#include "lcd.h"
#include "button.h"
#include "kernel.h"
#include "menu.h"
#include "sprintf.h"
#include "rtc.h"
#include "font.h"
#include "screens.h"
#ifdef SIMULATOR
#include <stdio.h>
#endif
#include <string.h>
#ifdef HAVE_LCD_BITMAP
#define SS_TITLE "Bouncer"
#define SS_TITLE_FONT 2
@ -45,6 +29,7 @@
#define XSPEED 3
#define YADD -4
static struct plugin_api* rb;
static unsigned char table[]={
26,28,30,33,35,37,39,40,42,43,45,46,46,47,47,47,47,47,46,46,45,43,42,40,39,37,35,33,30,28,26,24,21,19,17,14,12,10,8,7,5,4,2,1,1,0,0,0,0,0,1,1,2,4,5,7,8,10,12,14,17,19,21,23,
@ -186,6 +171,7 @@ struct counter values[]={
{"ydistt", -6},
};
#ifdef USE_CLOCK
static unsigned char yminute[]={
53,53,52,52,51,50,49,47,46,44,42,40,38,36,34,32,29,27,25,23,21,19,17,16,14,13,12,11,11,10,10,10,11,11,12,13,14,16,17,19,21,23,25,27,29,31,34,36,38,40,42,44,46,47,49,50,51,52,52,53,
};
@ -216,23 +202,24 @@ static void addclock(void)
if(pos >= 60)
pos -= 60;
lcd_drawline(LCD_WIDTH/2, LCD_HEIGHT/2, xminute[pos], yminute[pos]);
rb->lcd_drawline(LCD_WIDTH/2, LCD_HEIGHT/2, xminute[pos], yminute[pos]);
hour = hour*5 + minute/12;
pos = 90-hour;
if(pos >= 60)
pos -= 60;
lcd_drawline(LCD_WIDTH/2, LCD_HEIGHT/2, xhour[pos], yhour[pos]);
rb->lcd_drawline(LCD_WIDTH/2, LCD_HEIGHT/2, xhour[pos], yhour[pos]);
/* draw a circle */
for(i=0; i < 60; i+=3) {
lcd_drawline( xminute[i],
rb->lcd_drawline( xminute[i],
yminute[i],
xminute[(i+1)%60],
yminute[(i+1)%60]);
}
}
#endif
static int scrollit(void)
{
@ -243,31 +230,33 @@ static int scrollit(void)
unsigned int i;
int textpos=0;
char rock[]="Rockbox! Pure pleasure. Pure fun. Oooh. What fun! ;-) ";
char* rock="Rockbox! Pure pleasure. Pure fun. Oooh. What fun! ;-) ";
int letter;
lcd_clear_display();
rb->lcd_clear_display();
while(1)
{
b = button_get_w_tmo(HZ/10);
b = rb->button_get_w_tmo(HZ/10);
if ( b == (BUTTON_OFF|BUTTON_REL) )
return 0;
else if ( b == (BUTTON_ON|BUTTON_REL) )
return 1;
lcd_clear_display();
rb->lcd_clear_display();
for(i=0, yy=y, xx=x; i< LETTERS_ON_SCREEN; i++) {
letter = rock[(i+textpos) % (sizeof(rock)-1) ];
lcd_bitmap((char *)char_gen_12x16[letter-0x20],
rb->lcd_bitmap((char *)char_gen_12x16[letter-0x20],
xx, table[yy&63],
11, 16, false);
yy += YADD;
xx+= LCD_WIDTH/LETTERS_ON_SCREEN;
}
#ifdef USE_CLOCK
addclock();
lcd_update();
#endif
rb->lcd_update();
x-= XSPEED;
@ -292,21 +281,21 @@ static int loopit(void)
unsigned int ysanke=0;
unsigned int xsanke=0;
char rock[]="ROCKbox";
char* rock="ROCKbox";
int show=0;
int timeout=0;
char buffer[30];
lcd_clear_display();
rb->lcd_clear_display();
while(1)
{
b = button_get_w_tmo(HZ/10);
b = rb->button_get_w_tmo(HZ/10);
if ( b == (BUTTON_OFF|BUTTON_REL) )
return 0;
if ( b == SYS_USB_CONNECTED) {
usb_screen();
rb->usb_screen();
return 0;
}
@ -318,10 +307,10 @@ static int loopit(void)
y+= speed[ysanke&15] + values[NUM_YADD].num;
x+= speed[xsanke&15] + values[NUM_XADD].num;
lcd_clear_display();
rb->lcd_clear_display();
#ifdef USE_CLOCK
addclock();
#endif
if(timeout) {
switch(b) {
case BUTTON_LEFT:
@ -339,18 +328,18 @@ static int loopit(void)
show=NUM_LAST-1;
break;
}
snprintf(buffer, 30, "%s: %d",
values[show].what, values[show].num);
lcd_putsxy(0, 56, buffer);
rb->snprintf(buffer, 30, "%s: %d",
values[show].what, values[show].num);
rb->lcd_putsxy(0, 56, buffer);
timeout--;
}
for(i=0, yy=y, xx=x;
i<sizeof(rock)-1;
i++, yy+=values[NUM_YDIST].num, xx+=values[NUM_XDIST].num)
lcd_bitmap((char *)char_gen_12x16[rock[i]-0x20],
rb->lcd_bitmap((char *)char_gen_12x16[rock[i]-0x20],
xtable[xx%71], table[yy&63],
11, 16, false);
lcd_update();
rb->lcd_update();
ysanke+= values[NUM_YSANKE].num;
xsanke+= values[NUM_XSANKE].num;
@ -358,15 +347,19 @@ static int loopit(void)
}
bool bounce(void)
enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
{
int w, h;
char *off = "[Off] to stop";
int len = strlen(SS_TITLE);
int len;
lcd_setfont(FONT_SYSFIXED);
TEST_PLUGIN_API(api);
(void)(parameter);
rb = api;
lcd_getstringsize(SS_TITLE,&w, &h);
len = rb->strlen(SS_TITLE);
rb->lcd_setfont(FONT_SYSFIXED);
rb->lcd_getstringsize(SS_TITLE,&w, &h);
/* Get horizontel centering for text */
len *= w;
@ -380,11 +373,11 @@ bool bounce(void)
else
h /= 2;
lcd_clear_display();
lcd_putsxy(LCD_WIDTH/2-len, (LCD_HEIGHT/2)-h, SS_TITLE);
rb->lcd_clear_display();
rb->lcd_putsxy(LCD_WIDTH/2-len, (LCD_HEIGHT/2)-h, SS_TITLE);
len = 1;
lcd_getstringsize(off, &w, &h);
rb->lcd_getstringsize(off, &w, &h);
/* Get horizontel centering for text */
len *= w;
@ -398,10 +391,9 @@ bool bounce(void)
else
h /= 2;
lcd_putsxy(LCD_WIDTH/2-len, LCD_HEIGHT-(2*h), off);
lcd_update();
sleep(HZ);
rb->lcd_putsxy(LCD_WIDTH/2-len, LCD_HEIGHT-(2*h), off);
rb->lcd_update();
rb->sleep(HZ);
do {
h= loopit();
@ -409,7 +401,7 @@ bool bounce(void)
h = scrollit();
} while(h);
lcd_setfont(FONT_UI);
rb->lcd_setfont(FONT_UI);
return false;
}

View File

@ -16,22 +16,10 @@
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
***************************************************************************/
#include "plugin.h"
#include "config.h"
#include "options.h"
#ifdef USE_DEMOS
#include <stdlib.h>
#include "lcd.h"
#include "config.h"
#include "kernel.h"
#include "menu.h"
#include "button.h"
#include "sprintf.h"
#include "screens.h"
#include "font.h"
#ifdef HAVE_LCD_BITMAP
/* Loops that the values are displayed */
#define DISP_TIME 30
@ -80,6 +68,8 @@ static int sin_table[91] =
10000
};
static struct plugin_api* rb;
static long sin(int val)
{
/* Speed improvement through sukzessive lookup */
@ -214,7 +204,7 @@ static void cube_init(void)
static void line(int a, int b)
{
lcd_drawline(point2D[a].x, point2D[a].y, point2D[b].x, point2D[b].y);
rb->lcd_drawline(point2D[a].x, point2D[a].y, point2D[b].x, point2D[b].y);
}
static void cube_draw(void)
@ -234,7 +224,8 @@ static void cube_draw(void)
line(3,6);
}
bool cube(void)
enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
{
int t_disp=0;
char buffer[30];
@ -247,27 +238,31 @@ bool cube(void)
int zs=1;
bool highspeed=0;
bool exit=0;
lcd_setfont(FONT_SYSFIXED);
TEST_PLUGIN_API(api);
(void)(parameter);
rb = api;
rb->lcd_setfont(FONT_SYSFIXED);
cube_init();
while(!exit)
{
if (!highspeed)
sleep(4);
rb->sleep(4);
lcd_clear_display();
rb->lcd_clear_display();
cube_rotate(xa,ya,za);
cube_viewport();
cube_draw();
if (t_disp>0)
{
t_disp--;
snprintf(buffer, 30, "x:%d y:%d z:%d h:%d",xs,ys,zs,highspeed);
lcd_putsxy(0, 56, buffer);
rb->snprintf(buffer, 30, "x:%d y:%d z:%d h:%d",xs,ys,zs,highspeed);
rb->lcd_putsxy(0, 56, buffer);
}
lcd_update();
rb->lcd_update();
xa+=xs;
if (xa>359)
@ -285,7 +280,7 @@ bool cube(void)
if (za<0)
za+=360;
switch(button_get(false))
switch(rb->button_get(false))
{
case BUTTON_RIGHT:
xs+=1;
@ -332,22 +327,12 @@ bool cube(void)
break;
case SYS_USB_CONNECTED:
usb_screen();
lcd_setfont(FONT_UI);
return true;
rb->usb_screen();
return PLUGIN_USB_CONNECTED;
}
}
lcd_setfont(FONT_UI);
return false;
return PLUGIN_OK;
}
#endif /* USE_DEMOS */
/* -----------------------------------------------------------------
* vim: et sw=4 ts=8 sts=4 tw=78
*/
#endif

48
apps/plugins/helloworld.c Normal file
View File

@ -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;
}

View File

@ -16,17 +16,11 @@
* KIND, either express or implied.
*
****************************************************************************/
#include "plugin.h"
#ifdef HAVE_LCD_BITMAP
#ifndef SIMULATOR /* don't want this code in the simulator */
#include <stdlib.h>
#include <sprintf.h>
#include "menu.h"
#include "lcd.h"
#include "button.h"
#include "mas.h"
#include "system.h"
/* The different drawing modes */
#define DRAW_MODE_FILLED 0
#define DRAW_MODE_OUTLINE 1
@ -47,7 +41,7 @@ static int drawMode = DRAW_MODE_FILLED;
* hardware scrolling of the display. The user can change
* speed
*/
bool oscillograph(void)
enum plugin_status plugin_start(struct plugin_api* rb, void* parameter)
{
/* stores current volume value left */
int left;
@ -63,22 +57,25 @@ bool oscillograph(void)
bool exit = false;
TEST_PLUGIN_API(rb);
(void)parameter;
/* the main loop */
while (!exit) {
/* read the volume info from MAS */
left = mas_codec_readreg(0xC) / (MAX_PEAK / (LCD_WIDTH / 2 - 2));
right = mas_codec_readreg(0xD) / (MAX_PEAK / (LCD_WIDTH / 2 - 2));
left = rb->mas_codec_readreg(0xC) / (MAX_PEAK / (LCD_WIDTH / 2 - 2));
right = rb->mas_codec_readreg(0xD) / (MAX_PEAK / (LCD_WIDTH / 2 - 2));
/* delete current line */
lcd_clearline(0, y, LCD_WIDTH-1, y);
rb->lcd_clearline(0, y, LCD_WIDTH-1, y);
switch (drawMode) {
case DRAW_MODE_FILLED:
lcd_drawline(LCD_WIDTH / 2 + 1 , y,
LCD_WIDTH / 2 + 1 + right, y);
lcd_drawline(LCD_WIDTH / 2 - 1 , y,
LCD_WIDTH / 2 - 1 -left , y);
rb->lcd_drawline(LCD_WIDTH / 2 + 1 , y,
LCD_WIDTH / 2 + 1 + right, y);
rb->lcd_drawline(LCD_WIDTH / 2 - 1 , y,
LCD_WIDTH / 2 - 1 -left , y);
break;
case DRAW_MODE_OUTLINE:
@ -87,10 +84,10 @@ bool oscillograph(void)
/* Here real lines were neccessary because
anything else was ugly. */
lcd_drawline(LCD_WIDTH / 2 + right , y,
LCD_WIDTH / 2 + lastRight , lasty);
lcd_drawline(LCD_WIDTH / 2 - left , y,
LCD_WIDTH / 2 - lastLeft, lasty);
rb->lcd_drawline(LCD_WIDTH / 2 + right , y,
LCD_WIDTH / 2 + lastRight , lasty);
rb->lcd_drawline(LCD_WIDTH / 2 - left , y,
LCD_WIDTH / 2 - lastLeft, lasty);
/* have to store the old values for drawing lines
the next time */
@ -100,8 +97,8 @@ bool oscillograph(void)
case DRAW_MODE_PIXEL:
/* straight and simple */
lcd_drawpixel(LCD_WIDTH / 2 + right, y);
lcd_drawpixel(LCD_WIDTH / 2 - left, y);
rb->lcd_drawpixel(LCD_WIDTH / 2 + right, y);
rb->lcd_drawpixel(LCD_WIDTH / 2 - left, y);
break;
}
@ -114,19 +111,19 @@ bool oscillograph(void)
/* I roll before update because otherwise the new
line would appear at the wrong end of the display */
if (roll)
lcd_roll(y);
rb->lcd_roll(y);
/* now finally make the new sample visible */
lcd_update_rect(0, MAX(y-1, 0), LCD_WIDTH, 2);
rb->lcd_update_rect(0, MAX(y-1, 0), LCD_WIDTH, 2);
/* There are two mechanisms to alter speed:
1.) slowing down is achieved by increasing
the time waiting for user input. This
mechanism uses positive values.
the time waiting for user input. This
mechanism uses positive values.
2.) speeding up is achieved by leaving out
the user input check for (-speed) volume
samples. For this mechanism negative values
are used.
the user input check for (-speed) volume
samples. For this mechanism negative values
are used.
*/
if (speed >= 0 || ((speed < 0) && (y % (-speed) == 0))) {
@ -138,7 +135,7 @@ bool oscillograph(void)
it must be ensured that at least 1 is passed. */
/* react to user input */
switch (button_get_w_tmo(MAX(speed, 1))) {
switch (rb->button_get_w_tmo(MAX(speed, 1))) {
case BUTTON_UP:
speed++;
draw = true;
@ -151,7 +148,7 @@ bool oscillograph(void)
case BUTTON_PLAY:
/* pause the demo */
button_get(true);
rb->button_get(true);
break;
case BUTTON_F1:
@ -170,7 +167,7 @@ bool oscillograph(void)
That produces ugly results in DRAW_MODE_OUTLINE
mode. If rolling is enabled this change will
be reverted before the next update anyway.*/
lcd_roll(0);
rb->lcd_roll(0);
break;
case BUTTON_F3:
@ -181,27 +178,30 @@ bool oscillograph(void)
case BUTTON_OFF:
exit = true;
break;
case SYS_USB_CONNECTED:
rb->usb_screen();
return PLUGIN_USB_CONNECTED;
}
if (draw) {
char buf[16];
snprintf(buf, sizeof buf, "Speed: %d", -speed);
lcd_putsxy(0, (y + LCD_HEIGHT - 8) % LCD_HEIGHT, buf);
lcd_update_rect(0, (y + LCD_HEIGHT - 8) % LCD_HEIGHT,
LCD_WIDTH, 8);
rb->snprintf(buf, sizeof buf, "Speed: %d", -speed);
rb->lcd_putsxy(0, (y + LCD_HEIGHT - 8) % LCD_HEIGHT, buf);
rb->lcd_update_rect(0, (y + LCD_HEIGHT - 8) % LCD_HEIGHT,
LCD_WIDTH, 8);
}
}
}
/* restore to default roll position.
Looks funny if you forget to do this... */
lcd_roll(0);
lcd_update();
rb->lcd_roll(0);
rb->lcd_update();
/* standard return */
return false;
return PLUGIN_OK;
}
#endif /* #ifndef SIMULATOR */
#endif

26
apps/plugins/plugin.lds Normal file
View File

@ -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
}

View File

@ -15,17 +15,15 @@
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#include <stdlib.h>
#include "lcd.h"
#include "config.h"
#include "kernel.h"
#include "menu.h"
#include "button.h"
**************************************************************************/
#include "plugin.h"
#ifdef HAVE_LCD_BITMAP
#define NUM_PARTICLES 100
static short particles[NUM_PARTICLES][2];
static struct plugin_api* rb;
static bool particle_exists(int particle)
{
@ -42,7 +40,7 @@ static int create_particle(void)
for (i=0; i<NUM_PARTICLES; i++) {
if (!particle_exists(i)) {
particles[i][0]=(rand()%112);
particles[i][0]=(rb->rand()%112);
particles[i][1]=0;
return i;
}
@ -54,13 +52,13 @@ static void snow_move(void)
{
int i;
if (!(rand()%2))
if (!(rb->rand()%2))
create_particle();
for (i=0; i<NUM_PARTICLES; i++) {
if (particle_exists(i)) {
lcd_clearpixel(particles[i][0],particles[i][1]);
switch ((rand()%7)) {
rb->lcd_clearpixel(particles[i][0],particles[i][1]);
switch ((rb->rand()%7)) {
case 0:
particles[i][0]++;
break;
@ -77,7 +75,7 @@ static void snow_move(void)
break;
}
if (particle_exists(i))
lcd_drawpixel(particles[i][0],particles[i][1]);
rb->lcd_drawpixel(particles[i][0],particles[i][1]);
}
}
}
@ -90,28 +88,24 @@ static void snow_init(void)
particles[i][0]=-1;
particles[i][1]=-1;
}
lcd_clear_display();
rb->lcd_clear_display();
}
bool snow(void)
enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
{
snow_init();
TEST_PLUGIN_API(api);
(void)(parameter);
rb = api;
snow_init();
while (1) {
snow_move();
lcd_update();
sleep(HZ/20);
rb->lcd_update();
rb->sleep(HZ/20);
if (button_get(false) == BUTTON_OFF)
if (rb->button_get(false) == BUTTON_OFF)
return false;
}
}
#endif

868
apps/plugins/sokoban.c Normal file
View File

@ -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(&current_info.level, &undo->level, sizeof(undo->level));
rb->memcpy(&current_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, &current_info.level, sizeof(undo->level));
/* Store our player info */
rb->memcpy(&undo->location[0], &current_info.player, sizeof(undo->location[0]));
/* Now we need to store upto 2 blocks that may be affected.
* If player.spot is NULL, then there is no info stored
* for that block */
row = current_info.player.row;
col = current_info.player.col;
/* This must stay as _1_ because the first block (0) is the player */
for (i = 1; i < 3; i++) {
storable = true;
switch (button) {
case BUTTON_LEFT:
col--;
if (col < 0)
storable = false;
break;
case BUTTON_RIGHT:
col++;
if (col >= COLS)
storable = false;
break;
case BUTTON_UP:
row--;
if (row < 0)
storable = false;
break;
case BUTTON_DOWN:
row++;
if (row >= ROWS)
storable = false;
break;
default:
return;
}
if (storable) {
undo->location[i].col = col;
undo->location[i].row = row;
undo->location[i].spot = current_info.board[row][col];
} else {
undo->location[i].spot = '\0';
}
}
if (undo_info.count < MAX_UNDOS)
undo_info.count++;
}
static void init_boards(void)
{
current_info.level.level = 0;
current_info.level.moves = 0;
current_info.level.boxes_to_go = 0;
current_info.player.row = 0;
current_info.player.col = 0;
current_info.player.spot = ' ';
current_info.max_level = 0;
current_info.level_offset = 0;
current_info.loaded_level = 0;
init_undo();
}
static int get_level_count(void)
{
int fd = 0;
int lastlen = 0;
char buffer[COLS + 3]; /* COLS plus CR/LF and \0 */
if ((fd = rb->open(LEVELS_FILE, O_RDONLY)) < 0) {
rb->splash(0, 0, true, "Unable to open %s", LEVELS_FILE);
return -1;
}
while(1) {
int len = rb->read_line(fd, buffer, sizeof(buffer));
if(len <= 0)
break;
/* Two short lines in a row means new level */
if(len < 3 && lastlen < 3)
current_info.max_level++;
lastlen = len;
}
rb->close(fd);
return 0;
}
static int get_level(char *level, int level_size)
{
int fd = 0, i = 0;
int nread = 0;
int count = 0;
int lastlen = 0;
int level_ct = 1;
unsigned char buffer[SOKOBAN_LEVEL_SIZE * 2];
bool level_found = false;
/* open file */
if ((fd = rb->open(LEVELS_FILE, O_RDONLY)) < 0)
return -1;
/* Lets not reparse the full file if we can avoid it */
if (current_info.loaded_level < current_info.level.level) {
rb->lseek(fd, current_info.level_offset, SEEK_SET);
level_ct = current_info.loaded_level;
}
if(current_info.level.level > 1) {
while(!level_found) {
int len = rb->read_line(fd, buffer, SOKOBAN_LEVEL_SIZE);
if(len <= 0) {
rb->close(fd);
return -1;
}
/* Two short lines in a row means new level */
if(len < 3 && lastlen < 3) {
level_ct++;
if(level_ct == current_info.level.level)
level_found = true;
}
lastlen = len;
}
}
/* Remember the current offset */
current_info.level_offset = rb->lseek(fd, 0, SEEK_CUR);
/* read a full buffer chunk from here */
nread = rb->read(fd, buffer, sizeof(buffer)-1);
if (nread < 0)
return -1;
buffer[nread] = 0;
rb->close(fd);
/* If we read less then a level, error */
if (nread < level_size)
return -1;
/* Load our new level */
for(i=0, count=0; (count < nread) && (i<level_size);) {
if (buffer[count] != '\n' && buffer[count] != '\r')
level[i++] = buffer[count];
count++;
}
level[i] = 0;
current_info.loaded_level = current_info.level.level;
return 0;
}
/* return non-zero on error */
static int load_level(void)
{
short c = 0;
short r = 0;
short i = 0;
char level[ROWS*COLS+1];
int x = 0;
current_info.player.spot=' ';
current_info.level.boxes_to_go = 0;
current_info.level.moves = 0;
if (get_level(level, sizeof(level)) != 0)
return -1;
i = 0;
for (r = 0; r < ROWS; r++) {
x++;
for (c = 0; c < COLS; c++, i++) {
current_info.board[r][c] = level[i];
if (current_info.board[r][c] == '.')
current_info.level.boxes_to_go++;
else if (current_info.board[r][c] == '@') {
current_info.player.row = r;
current_info.player.col = c;
}
}
}
return 0;
}
static void update_screen(void)
{
short b = 0, c = 0;
short rows = 0, cols = 0;
char s[25];
short magnify = 4;
/* load the board to the screen */
for (rows=0 ; rows < ROWS ; rows++) {
for (cols = 0 ; cols < COLS ; cols++) {
c = cols * magnify;
b = rows * magnify;
switch(current_info.board[rows][cols]) {
case 'X': /* black space */
rb->lcd_drawrect(c, b, magnify, magnify);
rb->lcd_drawrect(c+1, b+1, 2, 2);
break;
case '#': /* this is a wall */
rb->lcd_drawpixel(c, b);
rb->lcd_drawpixel(c+2, b);
rb->lcd_drawpixel(c+1, b+1);
rb->lcd_drawpixel(c+3, b+1);
rb->lcd_drawpixel(c, b+2);
rb->lcd_drawpixel(c+2, b+2);
rb->lcd_drawpixel(c+1, b+3);
rb->lcd_drawpixel(c+3, b+3);
break;
case '.': /* this is a home location */
rb->lcd_drawrect(c+1, b+1, 2, 2);
break;
case '$': /* this is a box */
rb->lcd_drawrect(c, b, magnify, magnify);
break;
case '@': /* this is you */
rb->lcd_drawline(c+1, b, c+2, b);
rb->lcd_drawline(c, b+1, c+3, b+1);
rb->lcd_drawline(c+1, b+2, c+2, b+2);
rb->lcd_drawpixel(c, b+3);
rb->lcd_drawpixel(c+3, b+3);
break;
case '%': /* this is a box on a home spot */
rb->lcd_drawrect(c, b, magnify, magnify);
rb->lcd_drawrect(c+1, b+1, 2, 2);
break;
}
}
}
rb->snprintf(s, sizeof(s), "%d", current_info.level.level);
rb->lcd_putsxy(86, 22, s);
rb->snprintf(s, sizeof(s), "%d", current_info.level.moves);
rb->lcd_putsxy(86, 54, s);
rb->lcd_drawrect(80,0,32,32);
rb->lcd_drawrect(80,32,32,64);
rb->lcd_putsxy(81, 10, "Level");
rb->lcd_putsxy(81, 42, "Moves");
/* print out the screen */
rb->lcd_update();
}
static void draw_level(void)
{
load_level();
rb->lcd_clear_display();
update_screen();
}
static bool sokoban_loop(void)
{
char new_spot;
bool moved = true;
int i = 0, button = 0;
short r = 0, c = 0;
current_info.level.level = 1;
load_level();
update_screen();
while (1) {
moved = true;
r = current_info.player.row;
c = current_info.player.col;
button = rb->button_get(true);
add_undo(button);
switch(button)
{
case BUTTON_OFF:
/* get out of here */
return PLUGIN_OK;
case BUTTON_ON:
case BUTTON_ON | BUTTON_REPEAT:
/* this is UNDO */
undo();
rb->lcd_clear_display();
update_screen();
moved = false;
break;
case BUTTON_F3:
case BUTTON_F3 | BUTTON_REPEAT:
/* increase level */
init_undo();
current_info.level.boxes_to_go=0;
moved = true;
break;
case BUTTON_F1:
case BUTTON_F1 | BUTTON_REPEAT:
/* previous level */
init_undo();
if (current_info.level.level > 1)
current_info.level.level--;
draw_level();
moved = false;
break;
case BUTTON_F2:
case BUTTON_F2 | BUTTON_REPEAT:
/* same level */
init_undo();
draw_level();
moved = false;
break;
case BUTTON_LEFT:
switch(current_info.board[r][c-1])
{
case ' ': /* if it is a blank spot */
case '.': /* if it is a home spot */
new_spot = current_info.board[r][c-1];
current_info.board[r][c-1] = '@';
current_info.board[r][c] = current_info.player.spot;
current_info.player.spot = new_spot;
break;
case '$':
switch(current_info.board[r][c-2])
{
case ' ': /* going from blank to blank */
current_info.board[r][c-2] = current_info.board[r][c-1];
current_info.board[r][c-1] = current_info.board[r][c];
current_info.board[r][c] = current_info.player.spot;
current_info.player.spot = ' ';
break;
case '.': /* going from a blank to home */
current_info.board[r][c-2] = '%';
current_info.board[r][c-1] = current_info.board[r][c];
current_info.board[r][c] = current_info.player.spot;
current_info.player.spot = ' ';
current_info.level.boxes_to_go--;
break;
default:
moved = false;
break;
}
break;
case '%':
switch(current_info.board[r][c-2]) {
case ' ': /* we are going from a home to a blank */
current_info.board[r][c-2] = '$';
current_info.board[r][c-1] = current_info.board[r][c];
current_info.board[r][c] = current_info.player.spot;
current_info.player.spot = '.';
current_info.level.boxes_to_go++;
break;
case '.': /* if we are going from a home to home */
current_info.board[r][c-2] = '%';
current_info.board[r][c-1] = current_info.board[r][c];
current_info.board[r][c] = current_info.player.spot;
current_info.player.spot = '.';
break;
default:
moved = false;
break;
}
break;
default:
moved = false;
break;
}
if (moved)
current_info.player.col--;
break;
case BUTTON_RIGHT: /* if it is a blank spot */
switch(current_info.board[r][c+1]) {
case ' ':
case '.': /* if it is a home spot */
new_spot = current_info.board[r][c+1];
current_info.board[r][c+1] = '@';
current_info.board[r][c] = current_info.player.spot;
current_info.player.spot = new_spot;
break;
case '$':
switch(current_info.board[r][c+2]) {
case ' ': /* going from blank to blank */
current_info.board[r][c+2] = current_info.board[r][c+1];
current_info.board[r][c+1] = current_info.board[r][c];
current_info.board[r][c] = current_info.player.spot;
current_info.player.spot = ' ';
break;
case '.': /* going from a blank to home */
current_info.board[r][c+2] = '%';
current_info.board[r][c+1] = current_info.board[r][c];
current_info.board[r][c] = current_info.player.spot;
current_info.player.spot = ' ';
current_info.level.boxes_to_go--;
break;
default:
moved = false;
break;
}
break;
case '%':
switch(current_info.board[r][c+2]) {
case ' ': /* going from a home to a blank */
current_info.board[r][c+2] = '$';
current_info.board[r][c+1] = current_info.board[r][c];
current_info.board[r][c] = current_info.player.spot;
current_info.player.spot = '.';
current_info.level.boxes_to_go++;
break;
case '.':
current_info.board[r][c+2] = '%';
current_info.board[r][c+1] = current_info.board[r][c];
current_info.board[r][c] = current_info.player.spot;
current_info.player.spot = '.';
break;
default:
moved = false;
break;
}
break;
default:
moved = false;
break;
}
if (moved)
current_info.player.col++;
break;
case BUTTON_UP:
switch(current_info.board[r-1][c]) {
case ' ': /* if it is a blank spot */
case '.': /* if it is a home spot */
new_spot = current_info.board[r-1][c];
current_info.board[r-1][c] = '@';
current_info.board[r][c] = current_info.player.spot;
current_info.player.spot = new_spot;
break;
case '$':
switch(current_info.board[r-2][c]) {
case ' ': /* going from blank to blank */
current_info.board[r-2][c] = current_info.board[r-1][c];
current_info.board[r-1][c] = current_info.board[r][c];
current_info.board[r][c] = current_info.player.spot;
current_info.player.spot = ' ';
break;
case '.': /* going from a blank to home */
current_info.board[r-2][c] = '%';
current_info.board[r-1][c] = current_info.board[r][c];
current_info.board[r][c] = current_info.player.spot;
current_info.player.spot = ' ';
current_info.level.boxes_to_go--;
break;
default:
moved = false;
break;
}
break;
case '%':
switch(current_info.board[r-2][c]) {
case ' ': /* we are going from a home to a blank */
current_info.board[r-2][c] = '$';
current_info.board[r-1][c] = current_info.board[r][c];
current_info.board[r][c] = current_info.player.spot;
current_info.player.spot = '.';
current_info.level.boxes_to_go++;
break;
case '.': /* if we are going from a home to home */
current_info.board[r-2][c] = '%';
current_info.board[r-1][c] = current_info.board[r][c];
current_info.board[r][c] = current_info.player.spot;
current_info.player.spot = '.';
break;
default:
moved = false;
break;
}
break;
default:
moved = false;
break;
}
if (moved)
current_info.player.row--;
break;
case BUTTON_DOWN:
switch(current_info.board[r+1][c]) {
case ' ': /* if it is a blank spot */
case '.': /* if it is a home spot */
new_spot = current_info.board[r+1][c];
current_info.board[r+1][c] = '@';
current_info.board[r][c] = current_info.player.spot;
current_info.player.spot = new_spot;
break;
case '$':
switch(current_info.board[r+2][c]) {
case ' ': /* going from blank to blank */
current_info.board[r+2][c] = current_info.board[r+1][c];
current_info.board[r+1][c] = current_info.board[r][c];
current_info.board[r][c] = current_info.player.spot;
current_info.player.spot = ' ';
break;
case '.': /* going from a blank to home */
current_info.board[r+2][c] = '%';
current_info.board[r+1][c] = current_info.board[r][c];
current_info.board[r][c] = current_info.player.spot;
current_info.player.spot = ' ';
current_info.level.boxes_to_go--;
break;
default:
moved = false;
break;
}
break;
case '%':
switch(current_info.board[r+2][c]) {
case ' ': /* going from a home to a blank */
current_info.board[r+2][c] = '$';
current_info.board[r+1][c] = current_info.board[r][c];
current_info.board[r][c] = current_info.player.spot;
current_info.player.spot = '.';
current_info.level.boxes_to_go++;
break;
case '.': /* going from a home to home */
current_info.board[r+2][c] = '%';
current_info.board[r+1][c] = current_info.board[r][c];
current_info.board[r][c] = current_info.player.spot;
current_info.player.spot = '.';
break;
default:
moved = false;
break;
}
break;
default:
moved = false;
break;
}
if (moved)
current_info.player.row++;
break;
case SYS_USB_CONNECTED:
rb->usb_screen();
return PLUGIN_USB_CONNECTED;
default:
moved = false;
break;
}
if (moved) {
current_info.level.moves++;
rb->lcd_clear_display();
update_screen();
}
/* We have completed this level */
if (current_info.level.boxes_to_go == 0) {
current_info.level.level++;
/* clear undo stats */
init_undo();
rb->lcd_clear_display();
if (current_info.level.level > current_info.max_level) {
rb->lcd_putsxy(10, 20, "You WIN!!");
for (i = 0; i < 30000 ; i++) {
rb->lcd_invertrect(0, 0, 111, 63);
rb->lcd_update();
button = rb->button_get(false);
if (button && ((button & BUTTON_REL) != BUTTON_REL))
break;
}
return PLUGIN_OK;
}
load_level();
update_screen();
}
} /* end while */
return PLUGIN_OK;
}
enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
{
int w, h;
int len;
TEST_PLUGIN_API(api);
(void)(parameter);
rb = api;
rb->lcd_setfont(FONT_SYSFIXED);
rb->lcd_getstringsize(SOKOBAN_TITLE, &w, &h);
/* Get horizontel centering for text */
len = w;
if (len%2 != 0)
len =((len+1)/2)+(w/2);
else
len /= 2;
if (h%2 != 0)
h = (h/2)+1;
else
h /= 2;
rb->lcd_clear_display();
rb->lcd_putsxy(LCD_WIDTH/2-len,(LCD_HEIGHT/2)-h, SOKOBAN_TITLE);
rb->lcd_update();
rb->sleep(HZ*2);
rb->lcd_clear_display();
rb->lcd_putsxy(3, 6, "[OFF] To Stop");
rb->lcd_putsxy(3, 16, "[ON] To Undo");
rb->lcd_putsxy(3, 26, "[F1] - Level");
rb->lcd_putsxy(3, 36, "[F2] Same Level");
rb->lcd_putsxy(3, 46, "[F3] + Level");
rb->lcd_update();
rb->sleep(HZ*2);
rb->lcd_clear_display();
init_boards();
if (get_level_count() != 0) {
rb->splash(HZ*2,0,true,"Failed loading levels!");
return PLUGIN_OK;
}
return sokoban_loop();
}
#endif

View File

@ -17,24 +17,9 @@
* KIND, either express or implied.
*
****************************************************************************/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
#include "file.h"
#include "lcd.h"
#include "button.h"
#include "kernel.h"
#include "font.h"
#include "settings.h"
#include "icons.h"
#include "screens.h"
#include "status.h"
#include "plugin.h"
#define BUFFER_SIZE 1024
#define OUTSIDE_BUFFER -10
#define OUTSIDE_FILE -11
@ -50,6 +35,7 @@ static int begin_line; /* Index of the first line displayed on the lcd */
static int end_line; /* Index of the last line displayed on the lcd */
static int begin_line_pos; /* Position of the first_line in the bufffer */
static int end_line_pos; /* Position of the last_line in the buffer */
static struct plugin_api* rb;
/*
* Known issue: The caching algorithm will fail (display incoherent data) if
@ -61,7 +47,7 @@ static void display_line_count(void)
{
#ifdef HAVE_LCD_BITMAP
int w,h;
lcd_getstringsize("M", &w, &h);
rb->lcd_getstringsize("M", &w, &h);
display_lines = LCD_HEIGHT / h;
display_columns = LCD_WIDTH / w;
#else
@ -126,7 +112,7 @@ static void viewer_draw(int col)
char* str;
int line_pos;
lcd_clear_display();
rb->lcd_clear_display();
line_pos = begin_line_pos;
@ -137,11 +123,12 @@ static void viewer_draw(int col)
str = buffer + line_pos + 1;
for (j=0; j<col && *str!=0; ++j)
str++;
lcd_puts(0, i, str);
rb->lcd_puts(0, i, str);
line_pos = find_next_line(line_pos);
}
lcd_update();
#ifdef HAVE_LCD_BITMAP
rb->lcd_update();
#endif
}
static void fill_buffer(int pos)
@ -154,8 +141,8 @@ static void fill_buffer(int pos)
if (pos<0)
pos = 0;
lseek(fd, pos, SEEK_SET);
numread = read(fd, buffer, BUFFER_SIZE);
rb->lseek(fd, pos, SEEK_SET);
numread = rb->read(fd, buffer, BUFFER_SIZE);
begin_line_pos -= pos - buffer_pos;
end_line_pos -= pos - buffer_pos;
@ -181,11 +168,11 @@ static bool viewer_init(char* file)
int i;
int ret;
fd = open(file, O_RDONLY);
fd = rb->open(file, O_RDONLY);
if (fd==-1)
return false;
file_size = lseek(fd, 0, SEEK_END);
file_size = rb->lseek(fd, 0, SEEK_END);
buffer_pos = 0;
begin_line = 0;
@ -207,7 +194,7 @@ static bool viewer_init(char* file)
static void viewer_exit(void)
{
close(fd);
rb->close(fd);
}
static void viewer_scroll_down(void)
@ -264,7 +251,7 @@ static int pagescroll(int col)
int i;
while (!exit) {
switch (button_get(true)) {
switch (rb->button_get(true)) {
#ifdef HAVE_RECORDER_KEYPAD
case BUTTON_ON | BUTTON_UP:
case BUTTON_ON | BUTTON_UP | BUTTON_REPEAT:
@ -328,31 +315,30 @@ static int pagescroll(int col)
return col;
}
bool viewer_run(char* file)
enum plugin_status plugin_start(struct plugin_api* api, void* file)
{
bool exit=false;
int button;
int col = 0;
int ok;
#ifdef HAVE_LCD_BITMAP
/* no margins */
lcd_setmargins(0, 0);
#endif
TEST_PLUGIN_API(api);
rb = api;
if (!file)
return PLUGIN_ERROR;
ok = viewer_init(file);
if (!ok) {
lcd_clear_display();
lcd_puts(0, 0, "Error");
lcd_update();
sleep(HZ);
rb->splash(HZ, 0, false, "Error");
viewer_exit();
return false;
return PLUGIN_OK;
}
viewer_draw(col);
while (!exit) {
button = button_get(true);
button = rb->button_get(true);
switch ( button ) {
@ -420,13 +406,10 @@ bool viewer_run(char* file)
break;
case SYS_USB_CONNECTED:
usb_screen();
#ifdef HAVE_LCD_CHARCELLS
status_set_param(false);
#endif
rb->usb_screen();
viewer_exit();
return true;
return PLUGIN_USB_CONNECTED;
}
}
return false;
return PLUGIN_OK;
}

View File

@ -16,26 +16,9 @@
* KIND, either express or implied.
*
****************************************************************************/
#include "plugin.h"
#include "config.h"
#include "options.h"
#ifdef USE_GAMES
/* #define DEBUG_WORMLET */
#include <sprintf.h>
#include <stdlib.h>
#include <string.h>
#include "system.h"
#include "lcd.h"
#include "button.h"
#include "kernel.h"
#include "menu.h"
#include "rtc.h"
#include "lang.h"
#include "screens.h"
#include "font.h"
#ifdef HAVE_LCD_BITMAP
/* size of the field the worm lives in */
#define FIELD_RECT_X 1
@ -149,6 +132,9 @@ static int player3_dir = EAST;
control a worm */
static int players = 1;
/* the rockbox plugin api */
static struct plugin_api* rb;
#ifdef DEBUG_WORMLET
static void set_debug_out(char *str){
strcpy(debugout, str);
@ -507,8 +493,8 @@ static int make_food(int index) {
do {
/* make coordinates for a new food so that
the entire food lies within the FIELD */
x = rand() % (FIELD_RECT_WIDTH - FOOD_SIZE);
y = rand() % (FIELD_RECT_HEIGHT - FOOD_SIZE);
x = rb->rand() % (FIELD_RECT_WIDTH - FOOD_SIZE);
y = rb->rand() % (FIELD_RECT_HEIGHT - FOOD_SIZE);
tries ++;
/* Ensure that the new food doesn't collide with any
@ -549,7 +535,7 @@ static int make_food(int index) {
static void clear_food(int index)
{
/* remove the old food from the screen */
lcd_clearrect(foodx[index] + FIELD_RECT_X,
rb->lcd_clearrect(foodx[index] + FIELD_RECT_X,
foody[index] + FIELD_RECT_Y,
FOOD_SIZE, FOOD_SIZE);
}
@ -563,10 +549,10 @@ static void clear_food(int index)
static void draw_food(int index)
{
/* draw the food object */
lcd_fillrect(foodx[index] + FIELD_RECT_X,
rb->lcd_fillrect(foodx[index] + FIELD_RECT_X,
foody[index] + FIELD_RECT_Y,
FOOD_SIZE, FOOD_SIZE);
lcd_clearrect(foodx[index] + FIELD_RECT_X + 1,
rb->lcd_clearrect(foodx[index] + FIELD_RECT_X + 1,
foody[index] + FIELD_RECT_Y + 1,
FOOD_SIZE - 2, FOOD_SIZE - 2);
}
@ -588,8 +574,8 @@ static int make_argh(int index)
do {
/* make coordinates for a new argh so that
the entire food lies within the FIELD */
x = rand() % (FIELD_RECT_WIDTH - ARGH_SIZE);
y = rand() % (FIELD_RECT_HEIGHT - ARGH_SIZE);
x = rb->rand() % (FIELD_RECT_WIDTH - ARGH_SIZE);
y = rb->rand() % (FIELD_RECT_HEIGHT - ARGH_SIZE);
tries ++;
/* Ensure that the new argh doesn't intersect with any
@ -631,7 +617,7 @@ static int make_argh(int index)
static void draw_argh(int index)
{
/* draw the new argh */
lcd_fillrect(arghx[index] + FIELD_RECT_X,
rb->lcd_fillrect(arghx[index] + FIELD_RECT_X,
arghy[index] + FIELD_RECT_Y,
ARGH_SIZE, ARGH_SIZE);
}
@ -744,7 +730,7 @@ static void init_wormlet(void)
}
/* Needed when the game is restarted using BUTTON_ON */
lcd_clear_display();
rb->lcd_clear_display();
/* make and display some food and argh */
argh_count = MAX_FOOD;
@ -756,11 +742,11 @@ static void init_wormlet(void)
}
/* draw the game field */
lcd_invertrect(0, 0, FIELD_RECT_WIDTH + 2, FIELD_RECT_HEIGHT + 2);
lcd_invertrect(1, 1, FIELD_RECT_WIDTH, FIELD_RECT_HEIGHT);
rb->lcd_invertrect(0, 0, FIELD_RECT_WIDTH + 2, FIELD_RECT_HEIGHT + 2);
rb->lcd_invertrect(1, 1, FIELD_RECT_WIDTH, FIELD_RECT_HEIGHT);
/* make everything visible */
lcd_update();
rb->lcd_update();
}
@ -852,14 +838,14 @@ static void draw_worm(struct worm *w)
int x = w->x[w->head];
int y = w->y[w->head];
if (x >= 0 && x < FIELD_RECT_WIDTH && y >= 0 && y < FIELD_RECT_HEIGHT) {
lcd_drawpixel(x + FIELD_RECT_X, y + FIELD_RECT_Y);
rb->lcd_drawpixel(x + FIELD_RECT_X, y + FIELD_RECT_Y);
}
/* clear the space behind the worm */
x = w->x[w->tail] ;
y = w->y[w->tail] ;
if (x >= 0 && x < FIELD_RECT_WIDTH && y >= 0 && y < FIELD_RECT_HEIGHT) {
lcd_clearpixel(x + FIELD_RECT_X, y + FIELD_RECT_Y);
rb->lcd_clearpixel(x + FIELD_RECT_X, y + FIELD_RECT_Y);
}
}
@ -1166,10 +1152,10 @@ static void virtual_player(struct worm *w) {
static void score_board(void)
{
char buf[15];
char buf2[15];
char* buf2 = NULL;
int i;
int y = 0;
lcd_clearrect(FIELD_RECT_WIDTH + 2, 0, LCD_WIDTH - FIELD_RECT_WIDTH - 2, LCD_HEIGHT);
rb->lcd_clearrect(FIELD_RECT_WIDTH + 2, 0, LCD_WIDTH - FIELD_RECT_WIDTH - 2, LCD_HEIGHT);
for (i = 0; i < worm_count; i++) {
int score = get_score(&worms[i]);
@ -1180,54 +1166,52 @@ static void score_board(void)
}
}
/* length */
snprintf(buf, sizeof (buf),str(LANG_WORMLET_LENGTH), score);
/* length */
rb->snprintf(buf, sizeof (buf),"Len:%d", score);
/* worm state */
switch (check_collision(&worms[i])) {
case COLLISION_NONE:
if (worms[i].growing > 0){
snprintf(buf2, sizeof(buf2), str(LANG_WORMLET_GROWING));
}
case COLLISION_NONE:
if (worms[i].growing > 0)
buf2 = "Growing";
else {
if (worms[i].alive) {
snprintf(buf2, sizeof(buf2), str(LANG_WORMLET_HUNGRY));
} else {
snprintf(buf2, sizeof(buf2), str(LANG_WORMLET_WORMED));
}
if (worms[i].alive)
buf2 = "Hungry";
else
buf2 = "Wormed";
}
break;
break;
case COLLISION_WORM:
snprintf(buf2, sizeof(buf2), str(LANG_WORMLET_WORMED));
break;
case COLLISION_WORM:
buf2 = "Wormed";
break;
case COLLISION_FOOD:
snprintf(buf2, sizeof(buf2), str(LANG_WORMLET_GROWING));
break;
case COLLISION_FOOD:
buf2 = "Growing";
break;
case COLLISION_ARGH:
snprintf(buf2, sizeof(buf2), str(LANG_WORMLET_ARGH));
break;
case COLLISION_ARGH:
buf2 = "Argh";
break;
case COLLISION_FIELD:
snprintf(buf2, sizeof(buf2), str(LANG_WORMLET_CRASHED));
break;
}
lcd_putsxy(FIELD_RECT_WIDTH + 3, y , buf);
lcd_putsxy(FIELD_RECT_WIDTH + 3, y+8, buf2);
case COLLISION_FIELD:
buf2 = "Crashed";
break;
}
rb->lcd_putsxy(FIELD_RECT_WIDTH + 3, y , buf);
rb->lcd_putsxy(FIELD_RECT_WIDTH + 3, y+8, buf2);
if (!worms[i].alive){
lcd_invertrect(FIELD_RECT_WIDTH + 2, y,
LCD_WIDTH - FIELD_RECT_WIDTH - 2, 17);
rb->lcd_invertrect(FIELD_RECT_WIDTH + 2, y,
LCD_WIDTH - FIELD_RECT_WIDTH - 2, 17);
}
y += 19;
}
snprintf(buf , sizeof(buf), str(LANG_WORMLET_HIGHSCORE), highscore);
rb->snprintf(buf , sizeof(buf), "Hs: %d", highscore);
#ifndef DEBUG_WORMLET
lcd_putsxy(FIELD_RECT_WIDTH + 3, LCD_HEIGHT - 8, buf);
rb->lcd_putsxy(FIELD_RECT_WIDTH + 3, LCD_HEIGHT - 8, buf);
#else
lcd_putsxy(FIELD_RECT_WIDTH + 3, LCD_HEIGHT - 8, debugout);
rb->lcd_putsxy(FIELD_RECT_WIDTH + 3, LCD_HEIGHT - 8, debugout);
#endif
}
@ -1305,7 +1289,7 @@ static bool run(void)
/* initialize the board and so on */
init_wormlet();
cycle_start = current_tick;
cycle_start = *rb->current_tick;
/* change the direction of the worm */
while (button != BUTTON_OFF && ! wormDead)
{
@ -1358,7 +1342,7 @@ static bool run(void)
case BUTTON_PLAY:
do {
button = button_get(true);
button = rb->button_get(true);
} while (button != BUTTON_PLAY &&
button != BUTTON_OFF &&
button != BUTTON_ON);
@ -1377,7 +1361,7 @@ static bool run(void)
draw_worm(w);
}
score_board();
lcd_update();
rb->lcd_update();
if (button == BUTTON_ON) {
wormDead = true;
}
@ -1385,7 +1369,7 @@ static bool run(void)
/* here the wormlet game cycle ends
thus the current tick is stored
as end time */
cycle_end = current_tick;
cycle_end = *rb->current_tick;
/* The duration of the game cycle */
cycle_duration = cycle_end - cycle_start;
@ -1403,15 +1387,14 @@ static bool run(void)
max_cycle = cycle_duration;
ticks_to_max_cycle_reset = 20;
}
snprintf(buf, sizeof buf, "ticks %d", max_cycle);
rb->snprintf(buf, sizeof buf, "ticks %d", max_cycle);
set_debug_out(buf);
#endif
/* adjust the number of ticks to wait for a button.
This ensures that a complete game cycle including
user input runs in constant time */
button = button_get_w_tmo(SPEED - cycle_duration);
cycle_start = current_tick;
button = rb->button_get_w_tmo(SPEED - cycle_duration);
cycle_start = *rb->current_tick;
}
return wormDead;
}
@ -1425,7 +1408,7 @@ static bool run(void)
static void test_worm_food_collision(void) {
int collision_count = 0;
int i;
lcd_clear_display();
rb->lcd_clear_display();
init_worm(&worms[0], 10, 10);
add_growing(&worms[0], 10);
set_worm_dir(&worms[0], EAST);
@ -1451,12 +1434,12 @@ static void test_worm_food_collision(void) {
if (collision) {
collision_count++;
}
snprintf(buf, sizeof buf, "collisions: %d", collision_count);
lcd_putsxy(0, LCD_HEIGHT -8, buf);
lcd_update();
rb->snprintf(buf, sizeof buf, "collisions: %d", collision_count);
rb->lcd_putsxy(0, LCD_HEIGHT -8, buf);
rb->lcd_update();
}
if (collision_count != FOOD_SIZE) {
button_get(true);
rb->button_get(true);
}
@ -1470,12 +1453,12 @@ static void test_worm_food_collision(void) {
if (collision) {
collision_count ++;
}
snprintf(buf, sizeof buf, "collisions: %d", collision_count);
lcd_putsxy(0, LCD_HEIGHT -8, buf);
lcd_update();
rb->snprintf(buf, sizeof buf, "collisions: %d", collision_count);
rb->lcd_putsxy(0, LCD_HEIGHT -8, buf);
rb->lcd_update();
}
if (collision_count != FOOD_SIZE * 2) {
button_get(true);
rb->button_get(true);
}
}
@ -1498,7 +1481,7 @@ static void test_worm_argh_collision(void) {
int i;
int dir;
int collision_count = 0;
lcd_clear_display();
rb->lcd_clear_display();
init_worm(&worms[0], 10, 10);
add_growing(&worms[0], 40);
for (dir = 0; dir < 4; dir++) {
@ -1518,12 +1501,12 @@ static void test_worm_argh_collision(void) {
if (collision) {
collision_count ++;
}
snprintf(buf, sizeof buf, "collisions: %d", collision_count);
lcd_putsxy(0, LCD_HEIGHT -8, buf);
lcd_update();
rb->snprintf(buf, sizeof buf, "collisions: %d", collision_count);
rb->lcd_putsxy(0, LCD_HEIGHT -8, buf);
rb->lcd_update();
}
if (collision_count != ARGH_SIZE * 2) {
button_get(true);
rb->button_get(true);
}
arghy[0] = 12;
@ -1535,12 +1518,12 @@ static void test_worm_argh_collision(void) {
if (collision) {
collision_count ++;
}
snprintf(buf, sizeof buf, "collisions: %d", collision_count);
lcd_putsxy(0, LCD_HEIGHT -8, buf);
lcd_update();
rb->snprintf(buf, sizeof buf, "collisions: %d", collision_count);
rb->lcd_putsxy(0, LCD_HEIGHT -8, buf);
rb->lcd_update();
}
if (collision_count != ARGH_SIZE * 4) {
button_get(true);
rb->button_get(true);
}
}
@ -1560,11 +1543,11 @@ static int testline_in_rect(void) {
if (!line_in_rect(x1, y1, x2, y2, rx, ry, rw, rh) &&
!line_in_rect(x2, y2, x1, y1, rx, ry, rw, rh)) {
lcd_drawrect(rx, ry, rw, rh);
lcd_drawline(x1, y1, x2, y2);
lcd_update();
lcd_putsxy(0, 0, "failed 1");
button_get(true);
rb->lcd_drawrect(rx, ry, rw, rh);
rb->lcd_drawline(x1, y1, x2, y2);
rb->lcd_update();
rb->lcd_putsxy(0, 0, "failed 1");
rb->button_get(true);
testfailed = 1;
}
@ -1572,11 +1555,11 @@ static int testline_in_rect(void) {
y2 = 20;
if (!line_in_rect(x1, y1, x2, y2, rx, ry, rw, rh) &&
!line_in_rect(x2, y2, x1, y1, rx, ry, rw, rh)) {
lcd_drawrect(rx, ry, rw, rh);
lcd_drawline(x1, y1, x2, y2);
lcd_putsxy(0, 0, "failed 2");
lcd_update();
button_get(true);
rb->lcd_drawrect(rx, ry, rw, rh);
rb->lcd_drawline(x1, y1, x2, y2);
rb->lcd_putsxy(0, 0, "failed 2");
rb->lcd_update();
rb->button_get(true);
testfailed = 2;
}
@ -1584,11 +1567,11 @@ static int testline_in_rect(void) {
y1 = 30;
if (!line_in_rect(x1, y1, x2, y2, rx, ry, rw, rh) &&
!line_in_rect(x2, y2, x1, y1, rx, ry, rw, rh)) {
lcd_drawrect(rx, ry, rw, rh);
lcd_drawline(x1, y1, x2, y2);
lcd_putsxy(0, 0, "failed 3");
lcd_update();
button_get(true);
rb->lcd_drawrect(rx, ry, rw, rh);
rb->lcd_drawline(x1, y1, x2, y2);
rb->lcd_putsxy(0, 0, "failed 3");
rb->lcd_update();
rb->button_get(true);
testfailed = 3;
}
@ -1596,11 +1579,11 @@ static int testline_in_rect(void) {
y2 = 45;
if (!line_in_rect(x1, y1, x2, y2, rx, ry, rw, rh) &&
!line_in_rect(x2, y2, x1, y1, rx, ry, rw, rh)) {
lcd_drawrect(rx, ry, rw, rh);
lcd_drawline(x1, y1, x2, y2);
lcd_putsxy(0, 0, "failed 4");
lcd_update();
button_get(true);
rb->lcd_drawrect(rx, ry, rw, rh);
rb->lcd_drawline(x1, y1, x2, y2);
rb->lcd_putsxy(0, 0, "failed 4");
rb->lcd_update();
rb->button_get(true);
testfailed = 4;
}
@ -1608,11 +1591,11 @@ static int testline_in_rect(void) {
y1 = 50;
if (line_in_rect(x1, y1, x2, y2, rx, ry, rw, rh) ||
line_in_rect(x2, y2, x1, y1, rx, ry, rw, rh)) {
lcd_drawrect(rx, ry, rw, rh);
lcd_drawline(x1, y1, x2, y2);
lcd_putsxy(0, 0, "failed 5");
lcd_update();
button_get(true);
rb->lcd_drawrect(rx, ry, rw, rh);
rb->lcd_drawline(x1, y1, x2, y2);
rb->lcd_putsxy(0, 0, "failed 5");
rb->lcd_update();
rb->button_get(true);
testfailed = 5;
}
@ -1621,11 +1604,11 @@ static int testline_in_rect(void) {
y2 = 7;
if (line_in_rect(x1, y1, x2, y2, rx, ry, rw, rh) ||
line_in_rect(x2, y2, x1, y1, rx, ry, rw, rh)) {
lcd_drawrect(rx, ry, rw, rh);
lcd_drawline(x1, y1, x2, y2);
lcd_putsxy(0, 0, "failed 6");
lcd_update();
button_get(true);
rb->lcd_drawrect(rx, ry, rw, rh);
rb->lcd_drawline(x1, y1, x2, y2);
rb->lcd_putsxy(0, 0, "failed 6");
rb->lcd_update();
rb->button_get(true);
testfailed = 6;
}
@ -1636,11 +1619,11 @@ static int testline_in_rect(void) {
y2 = 20;
if (!line_in_rect(x1, y1, x2, y2, rx, ry, rw, rh) &&
!line_in_rect(x2, y2, x1, y1, rx, ry, rw, rh)) {
lcd_drawrect(rx, ry, rw, rh);
lcd_drawline(x1, y1, x2, y2);
lcd_putsxy(0, 0, "failed 7");
lcd_update();
button_get(true);
rb->lcd_drawrect(rx, ry, rw, rh);
rb->lcd_drawline(x1, y1, x2, y2);
rb->lcd_putsxy(0, 0, "failed 7");
rb->lcd_update();
rb->button_get(true);
testfailed = 7;
}
@ -1648,11 +1631,11 @@ static int testline_in_rect(void) {
x2 = 12;
if (!line_in_rect(x1, y1, x2, y2, rx, ry, rw, rh) &&
!line_in_rect(x2, y2, x1, y1, rx, ry, rw, rh)) {
lcd_drawrect(rx, ry, rw, rh);
lcd_drawline(x1, y1, x2, y2);
lcd_putsxy(0, 0, "failed 8");
lcd_update();
button_get(true);
rb->lcd_drawrect(rx, ry, rw, rh);
rb->lcd_drawline(x1, y1, x2, y2);
rb->lcd_putsxy(0, 0, "failed 8");
rb->lcd_update();
rb->button_get(true);
testfailed = 8;
}
@ -1660,11 +1643,11 @@ static int testline_in_rect(void) {
x1 = 25;
if (!line_in_rect(x1, y1, x2, y2, rx, ry, rw, rh) &&
!line_in_rect(x2, y2, x1, y1, rx, ry, rw, rh)) {
lcd_drawrect(rx, ry, rw, rh);
lcd_drawline(x1, y1, x2, y2);
lcd_putsxy(0, 0, "failed 9");
lcd_update();
button_get(true);
rb->lcd_drawrect(rx, ry, rw, rh);
rb->lcd_drawline(x1, y1, x2, y2);
rb->lcd_putsxy(0, 0, "failed 9");
rb->lcd_update();
rb->button_get(true);
testfailed = 9;
}
@ -1672,11 +1655,11 @@ static int testline_in_rect(void) {
x2 = 37;
if (!line_in_rect(x1, y1, x2, y2, rx, ry, rw, rh) &&
!line_in_rect(x2, y2, x1, y1, rx, ry, rw, rh)) {
lcd_drawrect(rx, ry, rw, rh);
lcd_drawline(x1, y1, x2, y2);
lcd_putsxy(0, 0, "failed 10");
lcd_update();
button_get(true);
rb->lcd_drawrect(rx, ry, rw, rh);
rb->lcd_drawline(x1, y1, x2, y2);
rb->lcd_putsxy(0, 0, "failed 10");
rb->lcd_update();
rb->button_get(true);
testfailed = 10;
}
@ -1684,11 +1667,11 @@ static int testline_in_rect(void) {
x1 = 42;
if (line_in_rect(x1, y1, x2, y2, rx, ry, rw, rh) ||
line_in_rect(x2, y2, x1, y1, rx, ry, rw, rh)) {
lcd_drawrect(rx, ry, rw, rh);
lcd_drawline(x1, y1, x2, y2);
lcd_putsxy(0, 0, "failed 11");
lcd_update();
button_get(true);
rb->lcd_drawrect(rx, ry, rw, rh);
rb->lcd_drawline(x1, y1, x2, y2);
rb->lcd_putsxy(0, 0, "failed 11");
rb->lcd_update();
rb->button_get(true);
testfailed = 11;
}
@ -1697,11 +1680,11 @@ static int testline_in_rect(void) {
x2 = 7;
if (line_in_rect(x1, y1, x2, y2, rx, ry, rw, rh) ||
line_in_rect(x2, y2, x1, y1, rx, ry, rw, rh)) {
lcd_drawrect(rx, ry, rw, rh);
lcd_drawline(x1, y1, x2, y2);
lcd_putsxy(0, 0, "failed 12");
lcd_update();
button_get(true);
rb->lcd_drawrect(rx, ry, rw, rh);
rb->lcd_drawline(x1, y1, x2, y2);
rb->lcd_putsxy(0, 0, "failed 12");
rb->lcd_update();
rb->button_get(true);
testfailed = 12;
}
@ -1717,11 +1700,11 @@ static int testline_in_rect(void) {
y2 = 20;
if (!(line_in_rect(x1, y1, x2, y2, rx, ry, rw, rh) &&
line_in_rect(x2, y2, x1, y1, rx, ry, rw, rh))) {
lcd_drawrect(rx, ry, rw, rh);
lcd_drawline(x1, y1, x2, y2);
lcd_putsxy(0, 0, "failed 13");
lcd_update();
button_get(true);
rb->lcd_drawrect(rx, ry, rw, rh);
rb->lcd_drawline(x1, y1, x2, y2);
rb->lcd_putsxy(0, 0, "failed 13");
rb->lcd_update();
rb->button_get(true);
testfailed = 13;
}
@ -1737,15 +1720,15 @@ static int testline_in_rect(void) {
y2 = 19;
if (!(line_in_rect(x1, y1, x2, y2, rx, ry, rw, rh) &&
line_in_rect(x2, y2, x1, y1, rx, ry, rw, rh))) {
lcd_drawline(x1, y1, x2, y2);
lcd_invertrect(rx, ry, rw, rh);
lcd_putsxy(0, 0, "failed 14");
lcd_update();
button_get(true);
rb->lcd_drawline(x1, y1, x2, y2);
rb->lcd_invertrect(rx, ry, rw, rh);
rb->lcd_putsxy(0, 0, "failed 14");
rb->lcd_update();
rb->button_get(true);
testfailed = 14;
}
lcd_clear_display();
rb->lcd_clear_display();
return testfailed;
}
@ -1759,7 +1742,7 @@ static int test_specific_worm_collision(void) {
int x = 0;
int y = 0;
char buf[20];
lcd_clear_display();
rb->lcd_clear_display();
init_worm(&worms[0], 10, 20);
add_growing(&worms[0], 20 - INITIAL_WORM_LENGTH);
@ -1779,14 +1762,14 @@ static int test_specific_worm_collision(void) {
if (specific_worm_collision(&worms[0], x, y) != -1) {
collisions ++;
}
lcd_invertpixel(x + FIELD_RECT_X, y + FIELD_RECT_Y);
snprintf(buf, sizeof buf, "collisions %d", collisions);
lcd_putsxy(0, LCD_HEIGHT - 8, buf);
lcd_update();
rb->lcd_invertpixel(x + FIELD_RECT_X, y + FIELD_RECT_Y);
rb->snprintf(buf, sizeof buf, "collisions %d", collisions);
rb->lcd_putsxy(0, LCD_HEIGHT - 8, buf);
rb->lcd_update();
}
}
if (collisions != 21) {
button_get(true);
rb->button_get(true);
}
return collisions;
}
@ -1798,7 +1781,7 @@ static void test_make_argh(void){
int failures = 0;
int last_failures = 0;
int i, worm_idx;
lcd_clear_display();
rb->lcd_clear_display();
worm_count = 3;
for (worm_idx = 0; worm_idx < worm_count; worm_idx++) {
@ -1818,37 +1801,37 @@ static void test_make_argh(void){
}
}
lcd_update();
rb->lcd_update();
for (seed = 0; hit < 20; seed += 2) {
char buf[20];
int x, y;
srand(seed);
x = rand() % (FIELD_RECT_WIDTH - ARGH_SIZE);
y = rand() % (FIELD_RECT_HEIGHT - ARGH_SIZE);
rb->srand(seed);
x = rb->rand() % (FIELD_RECT_WIDTH - ARGH_SIZE);
y = rb->rand() % (FIELD_RECT_HEIGHT - ARGH_SIZE);
for (worm_idx = 0; worm_idx < worm_count; worm_idx++){
if (expensive_worm_in_rect(&worms[worm_idx], x, y, ARGH_SIZE, ARGH_SIZE)) {
int tries = 0;
srand(seed);
rb->srand(seed);
tries = make_argh(0);
if ((x == arghx[0] && y == arghy[0]) || tries < 2) {
failures ++;
}
snprintf(buf, sizeof buf, "(%d;%d) fail%d try%d", x, y, failures, tries);
lcd_putsxy(0, LCD_HEIGHT - 8, buf);
lcd_update();
lcd_invertrect(x + FIELD_RECT_X, y+ FIELD_RECT_Y, ARGH_SIZE, ARGH_SIZE);
lcd_update();
rb->snprintf(buf, sizeof buf, "(%d;%d) fail%d try%d", x, y, failures, tries);
rb->lcd_putsxy(0, LCD_HEIGHT - 8, buf);
rb->lcd_update();
rb->lcd_invertrect(x + FIELD_RECT_X, y+ FIELD_RECT_Y, ARGH_SIZE, ARGH_SIZE);
rb->lcd_update();
draw_argh(0);
lcd_update();
lcd_invertrect(x + FIELD_RECT_X, y + FIELD_RECT_Y, ARGH_SIZE, ARGH_SIZE);
lcd_clearrect(arghx[0] + FIELD_RECT_X, arghy[0] + FIELD_RECT_Y, ARGH_SIZE, ARGH_SIZE);
rb->lcd_update();
rb->lcd_invertrect(x + FIELD_RECT_X, y + FIELD_RECT_Y, ARGH_SIZE, ARGH_SIZE);
rb->lcd_clearrect(arghx[0] + FIELD_RECT_X, arghy[0] + FIELD_RECT_Y, ARGH_SIZE, ARGH_SIZE);
if (failures > last_failures) {
button_get(true);
rb->button_get(true);
}
last_failures = failures;
hit ++;
@ -1860,7 +1843,7 @@ static void test_make_argh(void){
static void test_worm_argh_collision_in_moves(void) {
int hit_count = 0;
int i;
lcd_clear_display();
rb->lcd_clear_display();
init_worm(&worms[0], 10, 20);
arghx[0] = 20;
@ -1875,12 +1858,12 @@ static void test_worm_argh_collision_in_moves(void) {
if (worm_argh_collision_in_moves(&worms[0], 0, 5)){
hit_count ++;
}
snprintf(buf, sizeof buf, "in 5 moves hits: %d", hit_count);
lcd_putsxy(0, LCD_HEIGHT - 8, buf);
lcd_update();
rb->snprintf(buf, sizeof buf, "in 5 moves hits: %d", hit_count);
rb->lcd_putsxy(0, LCD_HEIGHT - 8, buf);
rb->lcd_update();
}
if (hit_count != ARGH_SIZE + 5) {
button_get(true);
rb->button_get(true);
}
}
#endif /* DEBUG_WORMLET */
@ -1888,14 +1871,18 @@ static void test_worm_argh_collision_in_moves(void) {
extern bool use_old_rect;
/**
* Main entry point from the menu to start the game control.
* Main entry point
*/
bool wormlet(void)
enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
{
bool worm_dead = false;
int button;
lcd_setfont(FONT_SYSFIXED);
TEST_PLUGIN_API(api);
(void)(parameter);
rb = api;
rb->lcd_setfont(FONT_SYSFIXED);
#ifdef DEBUG_WORMLET
testline_in_rect();
@ -1905,44 +1892,44 @@ bool wormlet(void)
test_worm_argh_collision();
test_specific_worm_collision();
#endif
lcd_setmargins(0,0);
/* Setup screen */
do {
char buf[20];
lcd_clear_display();
char* ptr;
rb->lcd_clear_display();
/* first line players */
snprintf(buf, sizeof buf, str(LANG_WORMLET_PLAYERS), players);
lcd_puts(0, 0, buf);
rb->snprintf(buf, sizeof buf, "%d Players UP/DN", players);
rb->lcd_puts(0, 0, buf);
/* second line worms */
snprintf(buf, sizeof buf, str(LANG_WORMLET_WORMS), worm_count);
lcd_puts(0, 1, buf);
rb->snprintf(buf, sizeof buf, "%d Worms L/R", worm_count);
rb->lcd_puts(0, 1, buf);
/* third line control */
if (players > 1) {
if (use_remote) {
snprintf(buf, sizeof buf, str(LANG_WORMLET_REMOTE_CTRL));
ptr = "Remote Control F1";
} else {
snprintf(buf, sizeof buf, str(LANG_WORMLET_NO_REM_CTRL));
ptr = "No Rem. Control F1";
}
} else {
if (players > 0) {
if (use_remote) {
snprintf(buf, sizeof buf, str(LANG_WORMLET_2_KEY_CTRL));
ptr = "2 Key Control F1";
} else {
snprintf(buf, sizeof buf, str(LANG_WORMLET_4_KEY_CTRL));
ptr = "4 Key Control F1";
}
} else {
snprintf(buf, sizeof buf, str(LANG_WORMLET_NO_CONTROL));
ptr = "Out Of Control";
}
}
lcd_puts(0, 2, buf);
lcd_update();
rb->lcd_puts(0, 2, ptr);
rb->lcd_update();
/* user selection */
button = button_get(true);
button = rb->button_get(true);
switch (button) {
case BUTTON_UP:
if (players < 3) {
@ -1981,14 +1968,13 @@ bool wormlet(void)
break;
case SYS_USB_CONNECTED:
usb_screen();
lcd_setfont(FONT_UI);
return true;
rb->usb_screen();
return PLUGIN_USB_CONNECTED;
}
} while (button != BUTTON_PLAY &&
button != BUTTON_OFF && button != BUTTON_ON);
lcd_clear_display();
rb->lcd_clear_display();
/* end of setup */
do {
@ -2008,7 +1994,7 @@ bool wormlet(void)
via BUTTON_OFF -> no need to wait for buttons. */
if (worm_dead) {
do {
button = button_get(true);
button = rb->button_get(true);
}
/* BUTTON_ON -> start new game */
/* BUTTON_OFF -> back to game menu */
@ -2017,20 +2003,7 @@ bool wormlet(void)
}
while (button != BUTTON_OFF);
lcd_setfont(FONT_UI);
return false;
return PLUGIN_OK;
}
#endif /* USE_GAMES */
#endif

View File

@ -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] =

View File

@ -29,6 +29,7 @@ enum icons_6x8 {
Folder, Directory, Playlist, Repeat,
Selected, Cursor, Wps, Mod_Ajz,
Font, Language, Text, Config,
Plugin,
LastIcon
};

View File

@ -1,891 +0,0 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2002 Eric Linenberg
* February 2003: Robert Hak performs a cleanup/rewrite/feature addition.
* Eric smiles. Bjorn cries. Linus say 'huh?'.
*
* All files in this archive are subject to the GNU General Public License.
* See the file COPYING in the source tree root for full license agreement.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#include "config.h"
#include "options.h"
#ifdef USE_GAMES
#include <sprintf.h>
#include "ctype.h"
#include "sokoban.h"
#include "lcd.h"
#include "button.h"
#include "kernel.h"
#include "menu.h"
#include "screens.h"
#include "font.h"
#include "file.h"
#include "misc.h"
#include "debug.h"
#ifdef SIMULATOR
#include <stdio.h>
#endif
#include <string.h>
#include "lang.h"
#include "sprintf.h"
#define SOKOBAN_TITLE "Sokoban"
#define SOKOBAN_TITLE_FONT 2
#define LEVELS_FILE "/.rockbox/sokoban/levels.txt"
#define ROWS 16
#define COLS 20
#define MAX_UNDOS 5
#define SOKOBAN_LEVEL_SIZE (ROWS*COLS)
static void init_undo(void);
static void undo(void);
static void add_undo(int button);
static int get_level(char *level, int level_size);
static int get_level_count(void);
static int load_level(void);
static void draw_level(void);
static void init_boards(void);
static void update_screen(void);
static bool sokoban_loop(void);
/* The Location, Undo and LevelInfo structs are OO-flavored.
* (oooh!-flavored as Schnueff puts it.) It makes more you have to know,
* but the overall data layout becomes more manageable. */
/* We use the same three values in 2 structs. Makeing them a struct
* hopefully ensures that if you change things in one, the other changes
* as well. */
struct LevelInfo {
short level;
short moves;
short boxes_to_go;
};
/* What a given location on the board looks like at a given time */
struct Location {
char spot;
short row;
short col;
};
/* A single level of undo. Each undo move can affect upto,
* but not more then, 3 spots on the board */
struct Undo {
struct LevelInfo level;
struct Location location[3];
};
/* Our full undo history */
static struct UndoInfo {
short count; /* How many undos are there in history */
short current; /* Which history is the current undo */
struct Undo history[MAX_UNDOS];
} undo_info;
/* Our playing board */
static struct BoardInfo {
char board[ROWS][COLS];
struct LevelInfo level;
struct Location player;
int max_level; /* How many levels do we have? */
int level_offset; /* Where in the level file is this level */
int loaded_level; /* Which level is in memory */
} current_info;
static void init_undo(void)
{
undo_info.count = 0;
undo_info.current = 0;
}
static void undo(void)
{
struct Undo *undo;
int i = 0;
short row, col;
if (undo_info.count == 0)
return;
/* Update board info */
undo = &undo_info.history[undo_info.current];
current_info.level = undo->level;
current_info.player = undo->location[0];
row = undo->location[0].row;
col = undo->location[0].col;
current_info.board[row][col] = '@';
/* Update the two other possible spots */
for (i = 1; i < 3; i++) {
if (undo->location[i].spot != '\0') {
row = undo->location[i].row;
col = undo->location[i].col;
current_info.board[row][col] = undo->location[i].spot;
undo->location[i].spot = '\0';
}
}
/* Remove this undo from the list */
if (undo_info.current == 0) {
if (undo_info.count > 1)
undo_info.current = MAX_UNDOS - 1;
} else {
undo_info.current--;
}
undo_info.count--;
return;
}
static void add_undo(int button)
{
struct Undo *undo;
int row, col, i;
bool storable;
if ((button != BUTTON_LEFT) && (button != BUTTON_RIGHT) &&
(button != BUTTON_UP) && (button != BUTTON_DOWN))
return;
if (undo_info.count != 0) {
if (undo_info.current < (MAX_UNDOS - 1))
undo_info.current++;
else
undo_info.current = 0;
}
/* Make what follows more readable */
undo = &undo_info.history[undo_info.current];
/* Store our level info */
undo->level = current_info.level;
/* Store our player info */
undo->location[0] = current_info.player;
/* Now we need to store upto 2 blocks that may be affected.
* If player.spot is NULL, then there is no info stored
* for that block */
row = current_info.player.row;
col = current_info.player.col;
/* This must stay as _1_ because the first block (0) is the player */
for (i = 1; i < 3; i++) {
storable = true;
switch (button) {
case BUTTON_LEFT:
col--;
if (col < 0)
storable = false;
break;
case BUTTON_RIGHT:
col++;
if (col >= COLS)
storable = false;
break;
case BUTTON_UP:
row--;
if (row < 0)
storable = false;
break;
case BUTTON_DOWN:
row++;
if (row >= ROWS)
storable = false;
break;
default:
return;
}
if (storable) {
undo->location[i].col = col;
undo->location[i].row = row;
undo->location[i].spot = current_info.board[row][col];
} else {
undo->location[i].spot = '\0';
}
}
if (undo_info.count < MAX_UNDOS)
undo_info.count++;
}
static void init_boards(void)
{
current_info.level.level = 0;
current_info.level.moves = 0;
current_info.level.boxes_to_go = 0;
current_info.player.row = 0;
current_info.player.col = 0;
current_info.player.spot = ' ';
current_info.max_level = 0;
current_info.level_offset = 0;
current_info.loaded_level = 0;
init_undo();
}
static int get_level_count(void)
{
int fd = 0;
int len, lastlen = 0;
char buffer[COLS + 3]; /* COLS plus CR/LF and \0 */
if ((fd = open(LEVELS_FILE, O_RDONLY)) < 0) {
splash(0, 0, true, "Unable to open %s", LEVELS_FILE);
return -1;
}
while(1) {
len = read_line(fd, buffer, sizeof(buffer));
if(len <= 0)
break;
/* Two short lines in a row means new level */
if(len < 3 && lastlen < 3)
current_info.max_level++;
lastlen = len;
}
DEBUGF("%d levels loaded\n", current_info.max_level);
close(fd);
return 0;
}
static int get_level(char *level, int level_size)
{
int fd = 0, i = 0;
int nread = 0;
int count = 0;
int len, lastlen = 0;
int level_ct = 1;
unsigned char buffer[SOKOBAN_LEVEL_SIZE * 2];
bool level_found = false;
/* open file */
if ((fd = open(LEVELS_FILE, O_RDONLY)) < 0)
return -1;
/* Lets not reparse the full file if we can avoid it */
if (current_info.loaded_level < current_info.level.level) {
lseek(fd, current_info.level_offset, SEEK_SET);
level_ct = current_info.loaded_level;
}
if(current_info.level.level > 1) {
while(!level_found) {
len = read_line(fd, buffer, SOKOBAN_LEVEL_SIZE);
if(len <= 0) {
close(fd);
return -1;
}
/* Two short lines in a row means new level */
if(len < 3 && lastlen < 3) {
level_ct++;
if(level_ct == current_info.level.level)
level_found = true;
}
lastlen = len;
}
}
/* Remember the current offset */
current_info.level_offset = lseek(fd, 0, SEEK_CUR);
/* read a full buffer chunk from here */
nread = read(fd, buffer, sizeof(buffer)-1);
if (nread < 0)
return -1;
buffer[nread] = 0;
close(fd);
/* If we read less then a level, error */
if (nread < level_size)
return -1;
/* Load our new level */
for(i=0, count=0; (count < nread) && (i<level_size);) {
if (buffer[count] != '\n' && buffer[count] != '\r')
level[i++] = buffer[count];
count++;
}
level[i] = 0;
current_info.loaded_level = current_info.level.level;
return 0;
}
/* return non-zero on error */
static int load_level(void)
{
short c = 0;
short r = 0;
short i = 0;
char level[ROWS*COLS+1];
int x = 0;
current_info.player.spot=' ';
current_info.level.boxes_to_go = 0;
current_info.level.moves = 0;
if (get_level(level, sizeof(level)) != 0)
return -1;
i = 0;
for (r = 0; r < ROWS; r++) {
x++;
for (c = 0; c < COLS; c++, i++) {
current_info.board[r][c] = level[i];
if (current_info.board[r][c] == '.')
current_info.level.boxes_to_go++;
else if (current_info.board[r][c] == '@') {
current_info.player.row = r;
current_info.player.col = c;
}
}
}
return 0;
}
static void update_screen(void)
{
short b = 0, c = 0;
short rows = 0, cols = 0;
char s[25];
short magnify = 4;
/* load the board to the screen */
for (rows=0 ; rows < ROWS ; rows++) {
for (cols = 0 ; cols < COLS ; cols++) {
c = cols * magnify;
b = rows * magnify;
switch(current_info.board[rows][cols]) {
case 'X': /* black space */
lcd_drawrect(c, b, magnify, magnify);
lcd_drawrect(c+1, b+1, 2, 2);
break;
case '#': /* this is a wall */
lcd_drawpixel(c, b);
lcd_drawpixel(c+2, b);
lcd_drawpixel(c+1, b+1);
lcd_drawpixel(c+3, b+1);
lcd_drawpixel(c, b+2);
lcd_drawpixel(c+2, b+2);
lcd_drawpixel(c+1, b+3);
lcd_drawpixel(c+3, b+3);
break;
case '.': /* this is a home location */
lcd_drawrect(c+1, b+1, 2, 2);
break;
case '$': /* this is a box */
lcd_drawrect(c, b, magnify, magnify);
break;
case '@': /* this is you */
lcd_drawline(c+1, b, c+2, b);
lcd_drawline(c, b+1, c+3, b+1);
lcd_drawline(c+1, b+2, c+2, b+2);
lcd_drawpixel(c, b+3);
lcd_drawpixel(c+3, b+3);
break;
case '%': /* this is a box on a home spot */
lcd_drawrect(c, b, magnify, magnify);
lcd_drawrect(c+1, b+1, 2, 2);
break;
}
}
}
snprintf(s, sizeof(s), "%d", current_info.level.level);
lcd_putsxy(86, 22, s);
snprintf(s, sizeof(s), "%d", current_info.level.moves);
lcd_putsxy(86, 54, s);
lcd_drawrect(80,0,32,32);
lcd_drawrect(80,32,32,64);
lcd_putsxy(81, 10, str(LANG_SOKOBAN_LEVEL));
lcd_putsxy(81, 42, str(LANG_SOKOBAN_MOVE));
/* print out the screen */
lcd_update();
}
static void draw_level(void)
{
load_level();
lcd_clear_display();
update_screen();
}
static bool sokoban_loop(void)
{
char new_spot;
bool moved = true;
int i = 0, button = 0;
short r = 0, c = 0;
current_info.level.level = 1;
load_level();
update_screen();
while (1) {
moved = true;
r = current_info.player.row;
c = current_info.player.col;
button = button_get(true);
add_undo(button);
switch(button)
{
case BUTTON_OFF:
/* get out of here */
return false;
case BUTTON_ON:
case BUTTON_ON | BUTTON_REPEAT:
/* this is UNDO */
undo();
lcd_clear_display();
update_screen();
moved = false;
break;
case BUTTON_F3:
case BUTTON_F3 | BUTTON_REPEAT:
/* increase level */
init_undo();
current_info.level.boxes_to_go=0;
moved = true;
break;
case BUTTON_F1:
case BUTTON_F1 | BUTTON_REPEAT:
/* previous level */
init_undo();
if (current_info.level.level > 1)
current_info.level.level--;
draw_level();
moved = false;
break;
case BUTTON_F2:
case BUTTON_F2 | BUTTON_REPEAT:
/* same level */
init_undo();
draw_level();
moved = false;
break;
case BUTTON_LEFT:
switch(current_info.board[r][c-1])
{
case ' ': /* if it is a blank spot */
case '.': /* if it is a home spot */
new_spot = current_info.board[r][c-1];
current_info.board[r][c-1] = '@';
current_info.board[r][c] = current_info.player.spot;
current_info.player.spot = new_spot;
break;
case '$':
switch(current_info.board[r][c-2])
{
case ' ': /* going from blank to blank */
current_info.board[r][c-2] = current_info.board[r][c-1];
current_info.board[r][c-1] = current_info.board[r][c];
current_info.board[r][c] = current_info.player.spot;
current_info.player.spot = ' ';
break;
case '.': /* going from a blank to home */
current_info.board[r][c-2] = '%';
current_info.board[r][c-1] = current_info.board[r][c];
current_info.board[r][c] = current_info.player.spot;
current_info.player.spot = ' ';
current_info.level.boxes_to_go--;
break;
default:
moved = false;
break;
}
break;
case '%':
switch(current_info.board[r][c-2]) {
case ' ': /* we are going from a home to a blank */
current_info.board[r][c-2] = '$';
current_info.board[r][c-1] = current_info.board[r][c];
current_info.board[r][c] = current_info.player.spot;
current_info.player.spot = '.';
current_info.level.boxes_to_go++;
break;
case '.': /* if we are going from a home to home */
current_info.board[r][c-2] = '%';
current_info.board[r][c-1] = current_info.board[r][c];
current_info.board[r][c] = current_info.player.spot;
current_info.player.spot = '.';
break;
default:
moved = false;
break;
}
break;
default:
moved = false;
break;
}
if (moved)
current_info.player.col--;
break;
case BUTTON_RIGHT: /* if it is a blank spot */
switch(current_info.board[r][c+1]) {
case ' ':
case '.': /* if it is a home spot */
new_spot = current_info.board[r][c+1];
current_info.board[r][c+1] = '@';
current_info.board[r][c] = current_info.player.spot;
current_info.player.spot = new_spot;
break;
case '$':
switch(current_info.board[r][c+2]) {
case ' ': /* going from blank to blank */
current_info.board[r][c+2] = current_info.board[r][c+1];
current_info.board[r][c+1] = current_info.board[r][c];
current_info.board[r][c] = current_info.player.spot;
current_info.player.spot = ' ';
break;
case '.': /* going from a blank to home */
current_info.board[r][c+2] = '%';
current_info.board[r][c+1] = current_info.board[r][c];
current_info.board[r][c] = current_info.player.spot;
current_info.player.spot = ' ';
current_info.level.boxes_to_go--;
break;
default:
moved = false;
break;
}
break;
case '%':
switch(current_info.board[r][c+2]) {
case ' ': /* going from a home to a blank */
current_info.board[r][c+2] = '$';
current_info.board[r][c+1] = current_info.board[r][c];
current_info.board[r][c] = current_info.player.spot;
current_info.player.spot = '.';
current_info.level.boxes_to_go++;
break;
case '.':
current_info.board[r][c+2] = '%';
current_info.board[r][c+1] = current_info.board[r][c];
current_info.board[r][c] = current_info.player.spot;
current_info.player.spot = '.';
break;
default:
moved = false;
break;
}
break;
default:
moved = false;
break;
}
if (moved)
current_info.player.col++;
break;
case BUTTON_UP:
switch(current_info.board[r-1][c]) {
case ' ': /* if it is a blank spot */
case '.': /* if it is a home spot */
new_spot = current_info.board[r-1][c];
current_info.board[r-1][c] = '@';
current_info.board[r][c] = current_info.player.spot;
current_info.player.spot = new_spot;
break;
case '$':
switch(current_info.board[r-2][c]) {
case ' ': /* going from blank to blank */
current_info.board[r-2][c] = current_info.board[r-1][c];
current_info.board[r-1][c] = current_info.board[r][c];
current_info.board[r][c] = current_info.player.spot;
current_info.player.spot = ' ';
break;
case '.': /* going from a blank to home */
current_info.board[r-2][c] = '%';
current_info.board[r-1][c] = current_info.board[r][c];
current_info.board[r][c] = current_info.player.spot;
current_info.player.spot = ' ';
current_info.level.boxes_to_go--;
break;
default:
moved = false;
break;
}
break;
case '%':
switch(current_info.board[r-2][c]) {
case ' ': /* we are going from a home to a blank */
current_info.board[r-2][c] = '$';
current_info.board[r-1][c] = current_info.board[r][c];
current_info.board[r][c] = current_info.player.spot;
current_info.player.spot = '.';
current_info.level.boxes_to_go++;
break;
case '.': /* if we are going from a home to home */
current_info.board[r-2][c] = '%';
current_info.board[r-1][c] = current_info.board[r][c];
current_info.board[r][c] = current_info.player.spot;
current_info.player.spot = '.';
break;
default:
moved = false;
break;
}
break;
default:
moved = false;
break;
}
if (moved)
current_info.player.row--;
break;
case BUTTON_DOWN:
switch(current_info.board[r+1][c]) {
case ' ': /* if it is a blank spot */
case '.': /* if it is a home spot */
new_spot = current_info.board[r+1][c];
current_info.board[r+1][c] = '@';
current_info.board[r][c] = current_info.player.spot;
current_info.player.spot = new_spot;
break;
case '$':
switch(current_info.board[r+2][c]) {
case ' ': /* going from blank to blank */
current_info.board[r+2][c] = current_info.board[r+1][c];
current_info.board[r+1][c] = current_info.board[r][c];
current_info.board[r][c] = current_info.player.spot;
current_info.player.spot = ' ';
break;
case '.': /* going from a blank to home */
current_info.board[r+2][c] = '%';
current_info.board[r+1][c] = current_info.board[r][c];
current_info.board[r][c] = current_info.player.spot;
current_info.player.spot = ' ';
current_info.level.boxes_to_go--;
break;
default:
moved = false;
break;
}
break;
case '%':
switch(current_info.board[r+2][c]) {
case ' ': /* going from a home to a blank */
current_info.board[r+2][c] = '$';
current_info.board[r+1][c] = current_info.board[r][c];
current_info.board[r][c] = current_info.player.spot;
current_info.player.spot = '.';
current_info.level.boxes_to_go++;
break;
case '.': /* going from a home to home */
current_info.board[r+2][c] = '%';
current_info.board[r+1][c] = current_info.board[r][c];
current_info.board[r][c] = current_info.player.spot;
current_info.player.spot = '.';
break;
default:
moved = false;
break;
}
break;
default:
moved = false;
break;
}
if (moved)
current_info.player.row++;
break;
case SYS_USB_CONNECTED:
usb_screen();
return true;
default:
moved = false;
break;
}
if (moved) {
current_info.level.moves++;
lcd_clear_display();
update_screen();
}
/* We have completed this level */
if (current_info.level.boxes_to_go == 0) {
current_info.level.level++;
/* clear undo stats */
init_undo();
lcd_clear_display();
if (current_info.level.level > current_info.max_level) {
lcd_putsxy(10, 20, str(LANG_SOKOBAN_WIN));
for (i = 0; i < 30000 ; i++) {
lcd_invertrect(0, 0, 111, 63);
lcd_update();
button = button_get(false);
if (button && ((button & BUTTON_REL) != BUTTON_REL))
break;
}
return false;
}
load_level();
update_screen();
}
} /* end while */
return false;
}
bool sokoban(void)
{
bool result;
int w, h;
int len;
lcd_setfont(FONT_SYSFIXED);
lcd_getstringsize(SOKOBAN_TITLE, &w, &h);
/* Get horizontel centering for text */
len = w;
if (len%2 != 0)
len =((len+1)/2)+(w/2);
else
len /= 2;
if (h%2 != 0)
h = (h/2)+1;
else
h /= 2;
lcd_clear_display();
lcd_putsxy(LCD_WIDTH/2-len,(LCD_HEIGHT/2)-h, SOKOBAN_TITLE);
lcd_update();
sleep(HZ*2);
lcd_clear_display();
lcd_putsxy(3, 6, str(LANG_SOKOBAN_QUIT));
lcd_putsxy(3, 16, str(LANG_SOKOBAN_ON));
lcd_putsxy(3, 26, str(LANG_SOKOBAN_F1));
lcd_putsxy(3, 36, str(LANG_SOKOBAN_F2));
lcd_putsxy(3, 46, str(LANG_SOKOBAN_F3));
lcd_update();
sleep(HZ*2);
lcd_clear_display();
init_boards();
if (get_level_count() != 0)
return false;
result = sokoban_loop();
lcd_setfont(FONT_UI);
return result;
}
#endif

View File

@ -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__ */

View File

@ -1,438 +0,0 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 1999 Mattis Wadman (nappe@sudac.org)
*
* Heavily modified for embedded use by Björn Stenberg (bjorn@haxx.se)
*
* All files in this archive are subject to the GNU General Public License.
* See the file COPYING in the source tree root for full license agreement.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#include "config.h"
#include "options.h"
#ifdef USE_GAMES
#include <stdbool.h>
#include <string.h>
#include "lcd.h"
#include "button.h"
#include "kernel.h"
#include "menu.h"
#include "screens.h"
#include "font.h"
#ifdef SIMULATOR
#include <stdio.h>
#endif
#include "sprintf.h"
#include "lang.h"
#define TETRIS_TITLE "Tetris!"
#define TETRIS_TITLE_FONT 1
#define TETRIS_TITLE_XLOC 43
#define TETRIS_TITLE_YLOC 15
static const int start_x = 5;
static const int start_y = 5;
static const int max_x = 4 * 17;
static const int max_y = 3 * 10;
static const short level_speeds[10] = {
1000, 900, 800, 700, 600, 500, 400, 300, 250, 200
};
static const int blocks = 7;
static const int block_frames[7] = {1,2,2,2,4,4,4};
static int current_x, current_y, current_f, current_b;
static int level, score;
static int next_b, next_f;
static short lines;
static char virtual[LCD_WIDTH * LCD_HEIGHT];
/*
block_data is built up the following way
first array index specifies the block number
second array index specifies the rotation of the block
third array index specifies:
0: x-coordinates of pixels
1: y-coordinates of pixels
fourth array index specifies the coordinate of a pixel
each block consists of four pixels whose relative coordinates are given
with block_data
*/
static const char block_data[7][4][2][4] =
{
{
{{0,1,0,1},{0,0,1,1}}
},
{
{{0,1,1,2},{1,1,0,0}},
{{0,0,1,1},{0,1,1,2}}
},
{
{{0,1,1,2},{0,0,1,1}},
{{1,1,0,0},{0,1,1,2}}
},
{
{{1,1,1,1},{0,1,2,3}},
{{0,1,2,3},{2,2,2,2}}
},
{
{{1,1,1,2},{2,1,0,0}},
{{0,1,2,2},{1,1,1,2}},
{{0,1,1,1},{2,2,1,0}},
{{0,0,1,2},{0,1,1,1}}
},
{
{{0,1,1,1},{0,0,1,2}},
{{0,1,2,2},{1,1,1,0}},
{{1,1,1,2},{0,1,2,2}},
{{0,0,1,2},{2,1,1,1}}
},
{
{{1,0,1,2},{0,1,1,1}},
{{2,1,1,1},{1,0,1,2}},
{{1,0,1,2},{2,1,1,1}},
{{0,1,1,1},{1,0,1,2}}
}
};
static int t_rand(int range)
{
return current_tick % range;
}
static void draw_frame(int fstart_x,int fstop_x,int fstart_y,int fstop_y)
{
lcd_drawline(fstart_x, fstart_y, fstop_x, fstart_y);
lcd_drawline(fstart_x, fstop_y, fstop_x, fstop_y);
lcd_drawline(fstart_x, fstart_y, fstart_x, fstop_y);
lcd_drawline(fstop_x, fstart_y, fstop_x, fstop_y);
lcd_drawline(fstart_x - 1, fstart_y + 1, fstart_x - 1, fstop_y + 1);
lcd_drawline(fstart_x - 1, fstop_y + 1, fstop_x - 1, fstop_y + 1);
}
static void draw_block(int x, int y, int block, int frame, bool clear)
{
int i, a, b;
for(i=0;i < 4;i++) {
if (clear)
{
for (a = 0; a < 3; a++)
for (b = 0; b < 4; b++)
lcd_clearpixel(start_x + x + block_data[block][frame][1][i] * 4 - b,
start_y + y + block_data[block][frame][0][i] * 3 + a);
}
else
{
for (a = 0; a < 3; a++)
for (b = 0; b < 4; b++)
lcd_drawpixel(start_x+x+block_data[block][frame][1][i] * 4 - b,
start_y+y+block_data[block][frame][0][i] * 3 + a);
}
}
}
static void to_virtual(void)
{
int i, a, b;
for(i = 0; i < 4; i++)
for (a = 0; a < 3; a++)
for (b = 0; b < 4; b++)
*(virtual +
(current_y + block_data[current_b][current_f][0][i] * 3 + a) *
max_x + current_x + block_data[current_b][current_f][1][i] *
4 - b) = current_b + 1;
}
static bool block_touch (int x, int y)
{
int a,b;
for (a = 0; a < 4; a++)
for (b = 0; b < 3; b++)
if (*(virtual + (y + b) * max_x + (x - a)) != 0)
return true;
return false;
}
static bool gameover(void)
{
int i;
int frame, block, y, x;
x = current_x;
y = current_y;
block = current_b;
frame = current_f;
for(i = 0; i < 4; i++){
/* Do we have blocks touching? */
if(block_touch(x + block_data[block][frame][1][i] * 4,
y + block_data[block][frame][0][i] * 3))
{
/* Are we at the top of the frame? */
if(x + block_data[block][frame][1][i] * 4 >= max_x - 16)
{
/* Game over ;) */
return true;
}
}
}
return false;
}
static bool valid_position(int x, int y, int block, int frame)
{
int i;
for(i=0;i < 4;i++)
if ((y + block_data[block][frame][0][i] * 3 > max_y - 3) ||
(x + block_data[block][frame][1][i] * 4 > max_x - 4) ||
(y + block_data[block][frame][0][i] * 3 < 0) ||
(x + block_data[block][frame][1][i] * 4 < 4) ||
block_touch (x + block_data[block][frame][1][i] * 4,
y + block_data[block][frame][0][i] * 3))
{
return false;
}
return true;
}
static void from_virtual(void)
{
int x,y;
for(y = 0; y < max_y; y++)
for(x = 1; x < max_x - 1; x++)
if(*(virtual + (y * max_x) + x) != 0)
lcd_drawpixel(start_x + x, start_y + y);
else
lcd_clearpixel(start_x + x, start_y + y);
}
static void move_block(int x,int y,int f)
{
int last_frame = current_f;
if(f != 0)
{
current_f += f;
if(current_f > block_frames[current_b]-1)
current_f = 0;
if(current_f < 0)
current_f = block_frames[current_b]-1;
}
if(valid_position(current_x + x, current_y + y, current_b, current_f))
{
draw_block(current_x,current_y,current_b,last_frame,true);
current_x += x;
current_y += y;
draw_block(current_x,current_y,current_b,current_f,false);
lcd_update();
}
else
current_f = last_frame;
}
static void new_block(void)
{
current_b = next_b;
current_f = next_f;
current_x = max_x - 16;
current_y = (int)12;
next_b = t_rand(blocks);
next_f = t_rand(block_frames[next_b]);
lcd_drawline (max_x + 7, start_y - 1, max_x + 29, start_y - 1);
lcd_drawline (max_x + 29, start_y, max_x + 29, start_y + 14);
lcd_drawline (max_x + 29, start_y + 14, max_x + 7, start_y + 14);
lcd_drawline (max_x + 7, start_y + 14, max_x + 7, start_y - 1);
lcd_drawline (max_x + 6, start_y + 15, max_x + 6, start_y);
lcd_drawline (max_x + 6, start_y + 15, max_x + 28, start_y + 15);
draw_block(max_x + 9, start_y - 4, current_b, current_f, true);
draw_block(max_x + 9, start_y - 4, next_b, next_f, false);
if(!valid_position(current_x, current_y, current_b, current_f))
{
draw_block(current_x, current_y, current_b, current_f, false);
lcd_update();
}
else
draw_block(current_x, current_y, current_b, current_f, false);
}
static int check_lines(void)
{
int x,y,i,j;
bool line;
int lines = 0;
for(x = 0; x < max_x; x++)
{
line = true;
for(y = 0; y < max_y; y++)
{
if(*(virtual + y * max_x + x) == 0)
{
line = false;
break;
}
}
if(line)
{
lines++;
/* move rows down */
for(i = x; i < max_x - 1; i++)
for (j = 0; j < max_y; j++)
*(virtual + j * max_x + i)=*(virtual + j * max_x + (i + 1));
x--; /* re-check this line */
}
}
return lines / 4;
}
static void move_down(void)
{
int l;
char s[25];
if(!valid_position(current_x - 4, current_y, current_b, current_f))
{
to_virtual();
l = check_lines();
if(l)
{
lines += l;
level = (int)lines/10;
if(level > 9)
level = 9;
from_virtual();
score += l*l;
}
snprintf (s, sizeof(s), "%d %s %d", lines,
str(LANG_TETRIS_LEVEL), level);
lcd_putsxy (2, 42, s);
new_block();
move_block(0,0,0);
}
else
move_block(-4,0,0);
}
static bool game_loop(void)
{
while(1)
{
int count = 0;
while(count * 300 < level_speeds[level])
{
switch(button_get_w_tmo(HZ/10))
{
case BUTTON_OFF:
return false;
case BUTTON_UP:
case BUTTON_UP | BUTTON_REPEAT:
move_block(0,-3,0);
break;
case BUTTON_DOWN:
case BUTTON_DOWN | BUTTON_REPEAT:
move_block(0,3,0);
break;
case BUTTON_RIGHT:
case BUTTON_RIGHT | BUTTON_REPEAT:
move_block(0,0,1);
break;
case BUTTON_LEFT:
case BUTTON_LEFT | BUTTON_REPEAT:
move_down();
break;
case SYS_USB_CONNECTED:
usb_screen();
return true;
}
count++;
}
if(gameover())
{
lcd_clearrect(0, 52, LCD_WIDTH, LCD_HEIGHT - 52);
lcd_putsxy (2, 52, str(LANG_TETRIS_LOSE));
lcd_update();
sleep(HZ * 3);
return false;
}
move_down();
}
return false;
}
static void init_tetris(void)
{
memset(&virtual, 0, sizeof(virtual));
current_x = 0;
current_y = 0;
current_f = 0;
current_b = 0;
level = 0;
lines = 0;
score = 0;
next_b = 0;
next_f = 0;
}
bool tetris(void)
{
char buf[20];
bool val;
/* Lets use the default font */
lcd_setfont(FONT_SYSFIXED);
init_tetris();
draw_frame(start_x, start_x + max_x - 1, start_y - 1, start_y + max_y);
snprintf(buf, sizeof(buf), "0 %s 0", str(LANG_TETRIS_LEVEL));
lcd_putsxy (2, 42, buf);
lcd_update();
next_b = t_rand(blocks);
next_f = t_rand(block_frames[next_b]);
new_block();
val = game_loop();
lcd_setfont(FONT_UI);
return val;
}
#endif

View File

@ -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__ */

View File

@ -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

View File

@ -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;

View File

@ -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);

View File

@ -1,24 +0,0 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2002 Jerome Kuptz
*
* All files in this archive are subject to the GNU General Public License.
* See the file COPYING in the source tree root for full license agreement.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#ifndef _VIEWER_H
#define _VIEWER_H
bool viewer_run(char* file);
#endif

View File

@ -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 = .;

View File

@ -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 */