summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBjörn Stenberg <bjorn@haxx.se>2003-06-29 16:33:04 +0000
committerBjörn Stenberg <bjorn@haxx.se>2003-06-29 16:33:04 +0000
commitba371fb595affd68c823926b85718d1d613dc7d3 (patch)
treecfda303d0603d623cdb12f3928905d3ae02f1d87
parent9bcbe3fd723d23a709873a0855f27b86bc5c96f1 (diff)
downloadrockbox-ba371fb595affd68c823926b85718d1d613dc7d3.tar.gz
rockbox-ba371fb595affd68c823926b85718d1d613dc7d3.zip
Added plugin loader. Moved games, demos and the text viewer to loadable plugins. Copy your *.rock files to /.rockbox/rocks/
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@3769 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--apps/Makefile8
-rw-r--r--apps/demo_menu.c37
-rw-r--r--apps/games_menu.c29
-rw-r--r--apps/lang/english.lang76
-rw-r--r--apps/player/icons.h3
-rw-r--r--apps/plugin.c221
-rw-r--r--apps/plugin.h161
-rw-r--r--apps/plugins/Makefile45
-rw-r--r--apps/plugins/bounce.c (renamed from apps/recorder/bounce.c)96
-rw-r--r--apps/plugins/cube.c (renamed from apps/recorder/cube.c)63
-rw-r--r--apps/plugins/helloworld.c48
-rw-r--r--apps/plugins/oscillograph.c (renamed from apps/recorder/oscillograph.c)82
-rw-r--r--apps/plugins/plugin.lds26
-rw-r--r--apps/plugins/snow.c (renamed from apps/recorder/snow.c)46
-rw-r--r--apps/plugins/sokoban.c868
-rw-r--r--apps/plugins/viewer.c (renamed from apps/viewer.c)71
-rw-r--r--apps/plugins/wormlet.c (renamed from apps/recorder/wormlet.c)427
-rw-r--r--apps/recorder/icons.c1
-rw-r--r--apps/recorder/icons.h1
-rw-r--r--apps/recorder/sokoban.c891
-rw-r--r--apps/recorder/sokoban.h28
-rw-r--r--apps/recorder/tetris.c438
-rw-r--r--apps/recorder/wormlet.h28
-rw-r--r--apps/screens.c1
-rw-r--r--apps/tree.c19
-rw-r--r--apps/tree.h1
-rw-r--r--apps/viewer.h24
-rw-r--r--firmware/app.lds15
-rw-r--r--firmware/drivers/lcd-player-charset.c4
29 files changed, 1869 insertions, 1889 deletions
diff --git a/apps/Makefile b/apps/Makefile
index 3e5fbdc2dd..9614050cda 100644
--- a/apps/Makefile
+++ b/apps/Makefile
@@ -20,7 +20,7 @@ DOCSDIR := ../docs
20 20
21INCLUDES= -I$(FIRMWARE)/include -I$(FIRMWARE)/export -I. -I$(OBJDIR) 21INCLUDES= -I$(FIRMWARE)/include -I$(FIRMWARE)/export -I. -I$(OBJDIR)
22 22
23CFLAGS = -O -W -Wall -m1 -nostdlib -ffreestanding -Wstrict-prototypes -fomit-frame-pointer -fschedule-insns $(INCLUDES) $(TARGET) $(DEFINES) -DAPPSVERSION=\"$(VERSION)\" $(EXTRA_DEFINES) -DMEM=${MEM} 23CFLAGS = -O -W -Wall -m1 -nostdlib -ffreestanding -Wstrict-prototypes -fomit-frame-pointer -fschedule-insns $(INCLUDES) $(TARGET) $(DEFINES) -DAPPSVERSION=\"$(VERSION)\" $(EXTRA_DEFINES) -DMEM=${MEM} -DPLUGIN=1
24AFLAGS += -small -relax 24AFLAGS += -small -relax
25 25
26# Check if this is a kind of Recorder 26# Check if this is a kind of Recorder
@@ -71,7 +71,10 @@ ifndef TOOLSDIR
71 TOOLSDIR=../tools 71 TOOLSDIR=../tools
72endif 72endif
73 73
74all : $(OBJDIR)/$(OUTNAME) 74all : $(OBJDIR)/$(OUTNAME) rocks
75
76rocks:
77 $(MAKE) -C plugins TARGET=$(TARGET) DEBUG=$(DEBUG) OBJDIR=$(OBJDIR) VERSION=$(VERSION) EXTRA_DEFINES="$(EXTRA_DEFINES)"
75 78
76$(OBJDIR)/librockbox.a: 79$(OBJDIR)/librockbox.a:
77 make -C $(FIRMWARE) TARGET=$(TARGET) DEBUG=$(DEBUG) OBJDIR=$(OBJDIR) 80 make -C $(FIRMWARE) TARGET=$(TARGET) DEBUG=$(DEBUG) OBJDIR=$(OBJDIR)
@@ -117,6 +120,7 @@ clean:
117 $(OBJDIR)/lang.o $(OBJDIR)/build.lang $(OBJDIR)/lang.[ch] \ 120 $(OBJDIR)/lang.o $(OBJDIR)/build.lang $(OBJDIR)/lang.[ch] \
118 $(OBJDIR)/credits.raw $(LINKFILE) 121 $(OBJDIR)/credits.raw $(LINKFILE)
119 -$(RM) -r $(OBJDIR)/$(DEPS) 122 -$(RM) -r $(OBJDIR)/$(DEPS)
123 $(MAKE) -C plugins clean
120 124
121DEPS:=.deps 125DEPS:=.deps
122DEPDIRS:=$(DEPS) 126DEPDIRS:=$(DEPS)
diff --git a/apps/demo_menu.c b/apps/demo_menu.c
index f6934e49be..be8e44522c 100644
--- a/apps/demo_menu.c
+++ b/apps/demo_menu.c
@@ -24,19 +24,38 @@
24 24
25#include <stdio.h> 25#include <stdio.h>
26#include <stdbool.h> 26#include <stdbool.h>
27#include "lcd.h"
28#include "menu.h" 27#include "menu.h"
29#include "demo_menu.h" 28#include "demo_menu.h"
30#include "button.h"
31#include "kernel.h"
32#include "sprintf.h"
33
34#include "lang.h" 29#include "lang.h"
30#include "plugin.h"
31
32static bool bounce(void)
33{
34 if (plugin_load("/.rockbox/rocks/bounce.rock",NULL)==PLUGIN_USB_CONNECTED)
35 return true;
36 return false;
37}
38
39static bool snow(void)
40{
41 if (plugin_load("/.rockbox/rocks/snow.rock",NULL) == PLUGIN_USB_CONNECTED)
42 return true;
43 return false;
44}
45
46static bool cube(void)
47{
48 if (plugin_load("/.rockbox/rocks/cube.rock",NULL) == PLUGIN_USB_CONNECTED)
49 return true;
50 return false;
51}
35 52
36extern bool bounce(void); 53static bool oscillograph(void)
37extern bool snow(void); 54{
38extern bool cube(void); 55 if (plugin_load("/.rockbox/rocks/oscillograph.rock",NULL)==PLUGIN_USB_CONNECTED)
39extern bool oscillograph(void); 56 return true;
57 return false;
58}
40 59
41bool demo_menu(void) 60bool demo_menu(void)
42{ 61{
diff --git a/apps/games_menu.c b/apps/games_menu.c
index 0c37203f4e..780c4b7415 100644
--- a/apps/games_menu.c
+++ b/apps/games_menu.c
@@ -25,18 +25,31 @@
25 25
26#include <stdio.h> 26#include <stdio.h>
27#include <stdbool.h> 27#include <stdbool.h>
28#include "lcd.h"
29#include "menu.h" 28#include "menu.h"
30#include "games_menu.h" 29#include "games_menu.h"
31#include "button.h"
32#include "kernel.h"
33#include "sprintf.h"
34
35#include "sokoban.h"
36#include "wormlet.h"
37#include "lang.h" 30#include "lang.h"
31#include "plugin.h"
38 32
39extern bool tetris(void); 33static bool tetris(void)
34{
35 if (plugin_load("/.rockbox/rocks/tetris.rock",NULL)==PLUGIN_USB_CONNECTED)
36 return true;
37 return false;
38}
39
40static bool sokoban(void)
41{
42 if (plugin_load("/.rockbox/rocks/sokoban.rock",NULL)==PLUGIN_USB_CONNECTED)
43 return true;
44 return false;
45}
46
47static bool wormlet(void)
48{
49 if (plugin_load("/.rockbox/rocks/wormlet.rock",NULL)==PLUGIN_USB_CONNECTED)
50 return true;
51 return false;
52}
40 53
41bool games_menu(void) 54bool games_menu(void)
42{ 55{
diff --git a/apps/lang/english.lang b/apps/lang/english.lang
index 12249ee048..1d7b3088a6 100644
--- a/apps/lang/english.lang
+++ b/apps/lang/english.lang
@@ -677,37 +677,37 @@ new:
677 677
678id: LANG_SOKOBAN_LEVEL 678id: LANG_SOKOBAN_LEVEL
679desc: must be smaller than 6 characters 679desc: must be smaller than 6 characters
680eng: "Level" 680eng: ""
681new: 681new:
682 682
683id: LANG_SOKOBAN_MOVE 683id: LANG_SOKOBAN_MOVE
684desc: must be smaller than 6 characters 684desc: must be smaller than 6 characters
685eng: "Moves" 685eng: ""
686new: 686new:
687 687
688id: LANG_SOKOBAN_WIN 688id: LANG_SOKOBAN_WIN
689desc: displayed when you win 689desc: displayed when you win
690eng: "YOU WIN!!" 690eng: ""
691new: 691new:
692 692
693id: LANG_SOKOBAN_QUIT 693id: LANG_SOKOBAN_QUIT
694desc: how to quit game 694desc: how to quit game
695eng: "[OFF] To Stop" 695eng: ""
696new: 696new:
697 697
698id: LANG_SOKOBAN_F1 698id: LANG_SOKOBAN_F1
699desc: what does F1 do 699desc: what does F1 do
700eng: "[F1] - Level" 700eng: ""
701new: 701new:
702 702
703id: LANG_SOKOBAN_F2 703id: LANG_SOKOBAN_F2
704desc: what does F2 do 704desc: what does F2 do
705eng: "[F2] Same Level" 705eng: ""
706new: 706new:
707 707
708id: LANG_SOKOBAN_F3 708id: LANG_SOKOBAN_F3
709desc: what does F3 do 709desc: what does F3 do
710eng: "[F3] + Level" 710eng: ""
711new: 711new:
712 712
713# Next ids are for Worlmet Game. 713# Next ids are for Worlmet Game.
@@ -717,37 +717,37 @@ new:
717 717
718id: LANG_WORMLET_LENGTH 718id: LANG_WORMLET_LENGTH
719desc: wormlet game 719desc: wormlet game
720eng: "Len:%d" 720eng: ""
721new: 721new:
722 722
723id: LANG_WORMLET_GROWING 723id: LANG_WORMLET_GROWING
724desc: wormlet game 724desc: wormlet game
725eng: "Growing" 725eng: ""
726new: 726new:
727 727
728id: LANG_WORMLET_HUNGRY 728id: LANG_WORMLET_HUNGRY
729desc: wormlet game 729desc: wormlet game
730eng: "Hungry" 730eng: ""
731new: 731new:
732 732
733id: LANG_WORMLET_WORMED 733id: LANG_WORMLET_WORMED
734desc: wormlet game 734desc: wormlet game
735eng: "Wormed" 735eng: ""
736new: 736new:
737 737
738id: LANG_WORMLET_ARGH 738id: LANG_WORMLET_ARGH
739desc: wormlet game 739desc: wormlet game
740eng: "Argh" 740eng: ""
741new: 741new:
742 742
743id: LANG_WORMLET_CRASHED 743id: LANG_WORMLET_CRASHED
744desc: wormlet game 744desc: wormlet game
745eng: "Crashed" 745eng: ""
746new: 746new:
747 747
748id: LANG_WORMLET_HIGHSCORE 748id: LANG_WORMLET_HIGHSCORE
749desc: wormlet game 749desc: wormlet game
750eng: "Hs: %d" 750eng: ""
751new: 751new:
752 752
753# Length restrictions for wormlet config screen strings (LANG_CS_XXX) 753# Length restrictions for wormlet config screen strings (LANG_CS_XXX)
@@ -756,49 +756,49 @@ new:
756 756
757id: LANG_WORMLET_PLAYERS 757id: LANG_WORMLET_PLAYERS
758desc: wormlet game 758desc: wormlet game
759eng: "%d Players UP/DN" 759eng: ""
760new: 760new:
761 761
762id: LANG_WORMLET_WORMS 762id: LANG_WORMLET_WORMS
763desc: wormlet game 763desc: wormlet game
764eng: "%d Worms L/R" 764eng: ""
765new: 765new:
766 766
767id: LANG_WORMLET_REMOTE_CTRL 767id: LANG_WORMLET_REMOTE_CTRL
768desc: wormlet game 768desc: wormlet game
769eng: "Remote Control F1" 769eng: ""
770new: 770new:
771 771
772id: LANG_WORMLET_NO_REM_CTRL 772id: LANG_WORMLET_NO_REM_CTRL
773desc: wormlet game 773desc: wormlet game
774eng: "No Rem. Control F1" 774eng: ""
775new: 775new:
776 776
777id: LANG_WORMLET_2_KEY_CTRL 777id: LANG_WORMLET_2_KEY_CTRL
778desc: wormlet game 778desc: wormlet game
779eng: "2 Key Control F1" 779eng: ""
780new: 780new:
781 781
782id: LANG_WORMLET_4_KEY_CTRL 782id: LANG_WORMLET_4_KEY_CTRL
783desc: wormlet game 783desc: wormlet game
784eng: "4 Key Control F1" 784eng: ""
785new: 785new:
786 786
787id: LANG_WORMLET_NO_CONTROL 787id: LANG_WORMLET_NO_CONTROL
788desc: wormlet game 788desc: wormlet game
789eng: "Out Of Control" 789eng: ""
790new: 790new:
791 791
792# Wormlet game ids ended 792# Wormlet game ids ended
793 793
794id: LANG_TETRIS_LOSE 794id: LANG_TETRIS_LOSE
795desc: tetris game 795desc: tetris game
796eng: "You Lose!" 796eng: ""
797new: 797new:
798 798
799id: LANG_TETRIS_LEVEL 799id: LANG_TETRIS_LEVEL
800desc: tetris game 800desc: tetris game
801eng: "Rows - Level" 801eng: ""
802new: 802new:
803 803
804id: LANG_POWEROFF_IDLE 804id: LANG_POWEROFF_IDLE
@@ -1569,3 +1569,33 @@ id: LANG_CANCEL_WITH_ANY_RECORDER
1569desc: Generic recorder string to use to cancel 1569desc: Generic recorder string to use to cancel
1570eng: "Any Other = No" 1570eng: "Any Other = No"
1571new: 1571new:
1572
1573##
1574## Strings used in the plugin loader:
1575##
1576
1577id: LANG_PLUGIN_CANT_OPEN
1578desc: Plugin open error message
1579eng: "Can't open %s"
1580new:
1581
1582id: LANG_READ_FAILED
1583desc: There was an error reading a file
1584eng: "Failed reading %s"
1585new:
1586
1587id: LANG_PLUGIN_WRONG_MODEL
1588desc: The plugin is not compatible with the archos model trying to run it
1589eng: "Incompatible model"
1590new:
1591
1592id: LANG_PLUGIN_WRONG_VERSION
1593desc: The plugin is not compatible with the rockbox version trying to run it
1594eng: "Incompatible version"
1595new:
1596
1597id: LANG_PLUGIN_ERROR
1598desc: The plugin return an error code
1599eng: "Plugin returned error"
1600new:
1601
diff --git a/apps/player/icons.h b/apps/player/icons.h
index 1c9c68d66c..c96f821cfa 100644
--- a/apps/player/icons.h
+++ b/apps/player/icons.h
@@ -26,7 +26,8 @@
26 26
27enum { 27enum {
28 Unknown=0x90, 28 Unknown=0x90,
29 Folder=0x18, Mod_Ajz, Language, File, Wps, Playlist, Text, Config 29 Plugin = 0x17,
30 Folder, Mod_Ajz, Language, File, Wps, Playlist, Text, Config,
30}; 31};
31 32
32#endif 33#endif
diff --git a/apps/plugin.c b/apps/plugin.c
new file mode 100644
index 0000000000..6366580a56
--- /dev/null
+++ b/apps/plugin.c
@@ -0,0 +1,221 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2002 Björn Stenberg
11 *
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19#include <stdbool.h>
20#include <string.h>
21#include <stdio.h>
22#include "button.h"
23#include "lcd.h"
24#include "dir.h"
25#include "file.h"
26#include "kernel.h"
27#include "sprintf.h"
28#include "screens.h"
29#include "misc.h"
30#include "mas.h"
31#include "plugin.h"
32#include "lang.h"
33
34#ifdef SIMULATOR
35#include <dlfcn.h>
36#define PREFIX(_x_) x11_ ## _x_
37#else
38#define PREFIX(_x_) _x_
39#endif
40
41static int plugin_test(int api_version, int model);
42
43static struct plugin_api rockbox_api = {
44 PLUGIN_API_VERSION,
45
46 plugin_test,
47
48 /* lcd */
49 lcd_clear_display,
50 lcd_puts,
51 lcd_puts_scroll,
52 lcd_stop_scroll,
53#ifdef HAVE_LCD_CHARCELLS
54 lcd_define_pattern,
55#else
56 lcd_putsxy,
57 lcd_bitmap,
58 lcd_drawline,
59 lcd_clearline,
60 lcd_drawpixel,
61 lcd_clearpixel,
62 lcd_setfont,
63 lcd_clearrect,
64 lcd_fillrect,
65 lcd_drawrect,
66 lcd_invertrect,
67 lcd_getstringsize,
68 lcd_update,
69 lcd_update_rect,
70#ifndef SIMULATOR
71 lcd_roll,
72#endif
73#endif
74
75 /* button */
76 button_get,
77 button_get_w_tmo,
78
79 /* file */
80 PREFIX(open),
81 PREFIX(close),
82 read,
83 lseek,
84 PREFIX(creat),
85 write,
86 remove,
87 rename,
88 ftruncate,
89 PREFIX(filesize),
90 fprintf,
91 read_line,
92
93 /* dir */
94 PREFIX(opendir),
95 PREFIX(closedir),
96 PREFIX(readdir),
97
98 /* kernel */
99 PREFIX(sleep),
100 usb_screen,
101 &current_tick,
102
103 /* strings and memory */
104 snprintf,
105 strcpy,
106 strlen,
107 memset,
108 memcpy,
109
110 /* sound */
111#ifndef SIMULATOR
112#ifdef HAVE_MAS3587F
113 mas_codec_readreg,
114#endif
115#endif
116
117 /* misc */
118 srand,
119 rand,
120 splash,
121};
122
123int plugin_load(char* plugin, void* parameter)
124{
125 enum plugin_status (*plugin_start)(struct plugin_api* api, void* param);
126 int rc;
127 char buf[64];
128#ifdef SIMULATOR
129 void* pd;
130 char path[256];
131#else
132 extern unsigned char pluginbuf[];
133 int fd;
134#endif
135
136 lcd_clear_display();
137#ifdef HAVE_LCD_BITMAP
138 lcd_setmargins(0,0);
139 lcd_update();
140#endif
141#ifdef SIMULATOR
142 snprintf(path, sizeof path, "archos%s", plugin);
143 pd = dlopen(path, RTLD_NOW);
144 if (!pd) {
145 snprintf(buf, sizeof buf, "Can't open %s", plugin);
146 splash(HZ*2, 0, true, buf);
147 dlclose(pd);
148 return -1;
149 }
150
151 plugin_start = dlsym(pd, "plugin_start");
152 if (!plugin_start) {
153 plugin_start = dlsym(pd, "_plugin_start");
154 if (!plugin_start) {
155 splash(HZ*2, 0, true, "Can't find entry point");
156 dlclose(pd);
157 return -1;
158 }
159 }
160#else
161 fd = open(plugin, O_RDONLY);
162 if (fd < 0) {
163 snprintf(buf, sizeof buf, str(LANG_PLUGIN_CANT_OPEN), plugin);
164 splash(HZ*2, 0, true, buf);
165 return fd;
166 }
167
168 plugin_start = (void*)&pluginbuf;
169 rc = read(fd, plugin_start, 0x8000);
170 close(fd);
171 if (rc < 0) {
172 /* read error */
173 snprintf(buf, sizeof buf, str(LANG_READ_FAILED), plugin);
174 splash(HZ*2, 0, true, buf);
175 return -1;
176 }
177 if (rc == 0) {
178 /* loaded a 0-byte plugin, implying it's not for this model */
179 splash(HZ*2, 0, true, str(LANG_PLUGIN_WRONG_MODEL));
180 return -1;
181 }
182#endif
183
184 rc = plugin_start(&rockbox_api, parameter);
185 switch (rc) {
186 case PLUGIN_OK:
187 break;
188
189 case PLUGIN_USB_CONNECTED:
190 return PLUGIN_USB_CONNECTED;
191
192 case PLUGIN_WRONG_API_VERSION:
193 splash(HZ*2, 0, true, str(LANG_PLUGIN_WRONG_VERSION));
194 break;
195
196 case PLUGIN_WRONG_MODEL:
197 splash(HZ*2, 0, true, str(LANG_PLUGIN_WRONG_MODEL));
198 break;
199
200 default:
201 splash(HZ*2, 0, true, str(LANG_PLUGIN_ERROR));
202 break;
203 }
204
205#ifdef SIMULATOR
206 dlclose(pd);
207#endif
208
209 return PLUGIN_OK;
210}
211
212int plugin_test(int api_version, int model)
213{
214 if (api_version != PLUGIN_API_VERSION)
215 return PLUGIN_WRONG_API_VERSION;
216
217 if (model != MODEL)
218 return PLUGIN_WRONG_MODEL;
219
220 return PLUGIN_OK;
221}
diff --git a/apps/plugin.h b/apps/plugin.h
new file mode 100644
index 0000000000..3b79edefc6
--- /dev/null
+++ b/apps/plugin.h
@@ -0,0 +1,161 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2002 Björn Stenberg
11 *
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19#ifndef _PLUGIN_H_
20#define _PLUGIN_H_
21
22/* instruct simulator code to not redefine any symbols when compiling plugins.
23 (the PLUGIN macro is defined in apps/plugins/Makefile) */
24#ifdef PLUGIN
25#define NO_REDEFINES_PLEASE
26#endif
27
28#include <stdbool.h>
29#include <stdio.h>
30#include <stdlib.h>
31#include "config.h"
32#include "dir.h"
33#include "kernel.h"
34#include "button.h"
35#include "font.h"
36#include "system.h"
37#include "lcd.h"
38
39/* increase this every time the api struct changes */
40#define PLUGIN_API_VERSION 1
41
42/* plugin return codes */
43enum plugin_status {
44 PLUGIN_OK = 0,
45 PLUGIN_USB_CONNECTED,
46
47 PLUGIN_WRONG_API_VERSION = -1,
48 PLUGIN_WRONG_MODEL = -2,
49 PLUGIN_ERROR = -3,
50};
51
52/* different (incompatible) plugin models */
53enum model {
54 PLAYER,
55 RECORDER
56};
57
58#ifdef HAVE_LCD_CHARCELLS
59#define MODEL PLAYER
60#else
61#define MODEL RECORDER
62#endif
63
64/* compatibility test macro */
65#define TEST_PLUGIN_API(_api_) \
66do { \
67 int _rc_ = _api_->plugin_test(PLUGIN_API_VERSION, MODEL); \
68 if (_rc_<0) \
69 return _rc_; \
70} while(0)
71
72struct plugin_api {
73 /* these two fields must always be first, to ensure
74 TEST_PLUGIN_API will always work */
75 int version;
76 int (*plugin_test)(int api_version, int model);
77
78 /* lcd */
79 void (*lcd_clear_display)(void);
80 void (*lcd_puts)(int x, int y, unsigned char *string);
81 void (*lcd_puts_scroll)(int x, int y, unsigned char* string);
82 void (*lcd_stop_scroll)(void);
83#ifdef HAVE_LCD_CHARCELLS
84 void (*lcd_define_pattern)(int which,char *pattern);
85#else
86 void (*lcd_putsxy)(int x, int y, unsigned char *string);
87 void (*lcd_bitmap)(unsigned char *src, int x, int y,
88 int nx, int ny, bool clear);
89 void (*lcd_drawline)(int x1, int y1, int x2, int y2);
90 void (*lcd_clearline)(int x1, int y1, int x2, int y2);
91 void (*lcd_drawpixel)(int x, int y);
92 void (*lcd_clearpixel)(int x, int y);
93 void (*lcd_setfont)(int font);
94 void (*lcd_clearrect)(int x, int y, int nx, int ny);
95 void (*lcd_fillrect)(int x, int y, int nx, int ny);
96 void (*lcd_drawrect)(int x, int y, int nx, int ny);
97 void (*lcd_invertrect)(int x, int y, int nx, int ny);
98 int (*lcd_getstringsize)(unsigned char *str, int *w, int *h);
99 void (*lcd_update)(void);
100 void (*lcd_update_rect)(int x, int y, int width, int height);
101#ifndef SIMULATOR
102 void (*lcd_roll)(int pixels);
103#endif
104#endif
105
106 /* button */
107 int (*button_get)(bool block);
108 int (*button_get_w_tmo)(int ticks);
109
110 /* file */
111 int (*open)(const char* pathname, int flags);
112 int (*close)(int fd);
113 int (*read)(int fd, void* buf, int count);
114 int (*lseek)(int fd, int offset, int whence);
115 int (*creat)(const char *pathname, int mode);
116 int (*write)(int fd, void* buf, int count);
117 int (*remove)(const char* pathname);
118 int (*rename)(const char* path, const char* newname);
119 int (*ftruncate)(int fd, unsigned int size);
120 int (*filesize)(int fd);
121 int (*fprintf)(int fd, const char *fmt, ...);
122 int (*read_line)(int fd, char* buffer, int buffer_size);
123
124 /* dir */
125 DIR* (*opendir)(char* name);
126 int (*closedir)(DIR* dir);
127 struct dirent* (*readdir)(DIR* dir);
128
129 /* kernel */
130 void (*sleep)(int ticks);
131 void (*usb_screen)(void);
132 long* current_tick;
133
134 /* strings and memory */
135 int (*snprintf)(char *buf, size_t size, const char *fmt, ...);
136 char* (*strcpy)(char *dst, const char *src);
137 size_t (*strlen)(const char *str);
138 void* (*memset)(void *dst, int c, size_t length);
139 void* (*memcpy)(void *out, const void *in, size_t n);
140
141 /* sound */
142#ifndef SIMULATOR
143#ifdef HAVE_MAS3587F
144 int (*mas_codec_readreg)(int reg);
145#endif
146#endif
147
148 /* misc */
149 void (*srand)(unsigned int seed);
150 int (*rand)(void);
151 void (*splash)(int ticks, int keymask, bool center, char *fmt, ...);
152};
153
154/* defined by the plugin loader (plugin.c) */
155int plugin_load(char* plugin, void* parameter);
156
157/* defined by the plugin */
158enum plugin_status plugin_start(struct plugin_api* rockbox, void* parameter)
159 __attribute__ ((section (".entry")));
160
161#endif
diff --git a/apps/plugins/Makefile b/apps/plugins/Makefile
new file mode 100644
index 0000000000..4c02207016
--- /dev/null
+++ b/apps/plugins/Makefile
@@ -0,0 +1,45 @@
1# __________ __ ___.
2# Open \______ \ ____ ____ | | _\_ |__ _______ ___
3# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
4# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
5# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
6# \/ \/ \/ \/ \/
7# $Id$
8#
9
10CC = sh-elf-gcc
11OC = sh-elf-objcopy
12
13FIRMWARE = ../../firmware
14
15INCLUDES = -I$(FIRMWARE)/include -I$(FIRMWARE)/export -I$(FIRMWARE)/common -I$(FIRMWARE)/drivers -I..
16CFLAGS = -O -W -Wall -m1 -nostdlib -ffreestanding -Wstrict-prototypes $(INCLUDES) $(TARGET) $(EXTRA_DEFINES)
17
18LINKFILE = plugin.lds
19
20SRC := $(wildcard *.c)
21ROCKS := $(SRC:%.c=$(OBJDIR)/%.rock)
22
23ifndef OBJDIR
24no_configure:
25 @echo "Don't run make here. Run the tools/configure script from your own build"
26 @echo "directory, then run make there."
27 @echo
28 @echo "More help on how to build rockbox can be found here:"
29 @echo "http://rockbox.haxx.se/docs/how_to_compile.html"
30endif
31
32$(OBJDIR)/%.elf: $(OBJDIR)/%.o $(LINKFILE)
33 $(CC) -O -nostdlib -o $@ $< -lgcc -T$(LINKFILE) -Wl,-Map,$*.map
34
35$(OBJDIR)/%.rock : $(OBJDIR)/%.elf
36 $(OC) -O binary $< $@
37
38$(OBJDIR)/%.o: %.c ../plugin.h Makefile
39 $(CC) $(CFLAGS) -c $< -o $@
40
41all: $(ROCKS)
42 @echo done
43
44clean:
45 -rm -f $(ROCKS)
diff --git a/apps/recorder/bounce.c b/apps/plugins/bounce.c
index ed4885bc39..0c53d49887 100644
--- a/apps/recorder/bounce.c
+++ b/apps/plugins/bounce.c
@@ -15,26 +15,10 @@
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied. 16 * KIND, either express or implied.
17 * 17 *
18 ****************************************************************************/ 18 **************************************************************************/
19#include "plugin.h"
19 20
20#include "config.h" 21#ifdef HAVE_LCD_BITMAP
21#include "options.h"
22
23#ifdef USE_DEMOS
24
25#include "lcd.h"
26#include "button.h"
27#include "kernel.h"
28#include "menu.h"
29#include "sprintf.h"
30#include "rtc.h"
31#include "font.h"
32#include "screens.h"
33
34#ifdef SIMULATOR
35#include <stdio.h>
36#endif
37#include <string.h>
38 22
39#define SS_TITLE "Bouncer" 23#define SS_TITLE "Bouncer"
40#define SS_TITLE_FONT 2 24#define SS_TITLE_FONT 2
@@ -45,6 +29,7 @@
45#define XSPEED 3 29#define XSPEED 3
46#define YADD -4 30#define YADD -4
47 31
32static struct plugin_api* rb;
48 33
49static unsigned char table[]={ 34static unsigned char table[]={
5026,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, 3526,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[]={
186 {"ydistt", -6}, 171 {"ydistt", -6},
187}; 172};
188 173
174#ifdef USE_CLOCK
189static unsigned char yminute[]={ 175static unsigned char yminute[]={
19053,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, 17653,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,
191}; 177};
@@ -216,23 +202,24 @@ static void addclock(void)
216 if(pos >= 60) 202 if(pos >= 60)
217 pos -= 60; 203 pos -= 60;
218 204
219 lcd_drawline(LCD_WIDTH/2, LCD_HEIGHT/2, xminute[pos], yminute[pos]); 205 rb->lcd_drawline(LCD_WIDTH/2, LCD_HEIGHT/2, xminute[pos], yminute[pos]);
220 206
221 hour = hour*5 + minute/12; 207 hour = hour*5 + minute/12;
222 pos = 90-hour; 208 pos = 90-hour;
223 if(pos >= 60) 209 if(pos >= 60)
224 pos -= 60; 210 pos -= 60;
225 211
226 lcd_drawline(LCD_WIDTH/2, LCD_HEIGHT/2, xhour[pos], yhour[pos]); 212 rb->lcd_drawline(LCD_WIDTH/2, LCD_HEIGHT/2, xhour[pos], yhour[pos]);
227 213
228 /* draw a circle */ 214 /* draw a circle */
229 for(i=0; i < 60; i+=3) { 215 for(i=0; i < 60; i+=3) {
230 lcd_drawline( xminute[i], 216 rb->lcd_drawline( xminute[i],
231 yminute[i], 217 yminute[i],
232 xminute[(i+1)%60], 218 xminute[(i+1)%60],
233 yminute[(i+1)%60]); 219 yminute[(i+1)%60]);
234 } 220 }
235} 221}
222#endif
236 223
237static int scrollit(void) 224static int scrollit(void)
238{ 225{
@@ -243,31 +230,33 @@ static int scrollit(void)
243 unsigned int i; 230 unsigned int i;
244 int textpos=0; 231 int textpos=0;
245 232
246 char rock[]="Rockbox! Pure pleasure. Pure fun. Oooh. What fun! ;-) "; 233 char* rock="Rockbox! Pure pleasure. Pure fun. Oooh. What fun! ;-) ";
247 int letter; 234 int letter;
248 235
249 lcd_clear_display(); 236 rb->lcd_clear_display();
250 while(1) 237 while(1)
251 { 238 {
252 b = button_get_w_tmo(HZ/10); 239 b = rb->button_get_w_tmo(HZ/10);
253 if ( b == (BUTTON_OFF|BUTTON_REL) ) 240 if ( b == (BUTTON_OFF|BUTTON_REL) )
254 return 0; 241 return 0;
255 else if ( b == (BUTTON_ON|BUTTON_REL) ) 242 else if ( b == (BUTTON_ON|BUTTON_REL) )
256 return 1; 243 return 1;
257 244
258 lcd_clear_display(); 245 rb->lcd_clear_display();
259 246
260 for(i=0, yy=y, xx=x; i< LETTERS_ON_SCREEN; i++) { 247 for(i=0, yy=y, xx=x; i< LETTERS_ON_SCREEN; i++) {
261 letter = rock[(i+textpos) % (sizeof(rock)-1) ]; 248 letter = rock[(i+textpos) % (sizeof(rock)-1) ];
262 249
263 lcd_bitmap((char *)char_gen_12x16[letter-0x20], 250 rb->lcd_bitmap((char *)char_gen_12x16[letter-0x20],
264 xx, table[yy&63], 251 xx, table[yy&63],
265 11, 16, false); 252 11, 16, false);
266 yy += YADD; 253 yy += YADD;
267 xx+= LCD_WIDTH/LETTERS_ON_SCREEN; 254 xx+= LCD_WIDTH/LETTERS_ON_SCREEN;
268 } 255 }
256#ifdef USE_CLOCK
269 addclock(); 257 addclock();
270 lcd_update(); 258#endif
259 rb->lcd_update();
271 260
272 x-= XSPEED; 261 x-= XSPEED;
273 262
@@ -292,21 +281,21 @@ static int loopit(void)
292 unsigned int ysanke=0; 281 unsigned int ysanke=0;
293 unsigned int xsanke=0; 282 unsigned int xsanke=0;
294 283
295 char rock[]="ROCKbox"; 284 char* rock="ROCKbox";
296 285
297 int show=0; 286 int show=0;
298 int timeout=0; 287 int timeout=0;
299 char buffer[30]; 288 char buffer[30];
300 289
301 lcd_clear_display(); 290 rb->lcd_clear_display();
302 while(1) 291 while(1)
303 { 292 {
304 b = button_get_w_tmo(HZ/10); 293 b = rb->button_get_w_tmo(HZ/10);
305 if ( b == (BUTTON_OFF|BUTTON_REL) ) 294 if ( b == (BUTTON_OFF|BUTTON_REL) )
306 return 0; 295 return 0;
307 296
308 if ( b == SYS_USB_CONNECTED) { 297 if ( b == SYS_USB_CONNECTED) {
309 usb_screen(); 298 rb->usb_screen();
310 return 0; 299 return 0;
311 } 300 }
312 301
@@ -318,10 +307,10 @@ static int loopit(void)
318 y+= speed[ysanke&15] + values[NUM_YADD].num; 307 y+= speed[ysanke&15] + values[NUM_YADD].num;
319 x+= speed[xsanke&15] + values[NUM_XADD].num; 308 x+= speed[xsanke&15] + values[NUM_XADD].num;
320 309
321 lcd_clear_display(); 310 rb->lcd_clear_display();
322 311#ifdef USE_CLOCK
323 addclock(); 312 addclock();
324 313#endif
325 if(timeout) { 314 if(timeout) {
326 switch(b) { 315 switch(b) {
327 case BUTTON_LEFT: 316 case BUTTON_LEFT:
@@ -339,18 +328,18 @@ static int loopit(void)
339 show=NUM_LAST-1; 328 show=NUM_LAST-1;
340 break; 329 break;
341 } 330 }
342 snprintf(buffer, 30, "%s: %d", 331 rb->snprintf(buffer, 30, "%s: %d",
343 values[show].what, values[show].num); 332 values[show].what, values[show].num);
344 lcd_putsxy(0, 56, buffer); 333 rb->lcd_putsxy(0, 56, buffer);
345 timeout--; 334 timeout--;
346 } 335 }
347 for(i=0, yy=y, xx=x; 336 for(i=0, yy=y, xx=x;
348 i<sizeof(rock)-1; 337 i<sizeof(rock)-1;
349 i++, yy+=values[NUM_YDIST].num, xx+=values[NUM_XDIST].num) 338 i++, yy+=values[NUM_YDIST].num, xx+=values[NUM_XDIST].num)
350 lcd_bitmap((char *)char_gen_12x16[rock[i]-0x20], 339 rb->lcd_bitmap((char *)char_gen_12x16[rock[i]-0x20],
351 xtable[xx%71], table[yy&63], 340 xtable[xx%71], table[yy&63],
352 11, 16, false); 341 11, 16, false);
353 lcd_update(); 342 rb->lcd_update();
354 343
355 ysanke+= values[NUM_YSANKE].num; 344 ysanke+= values[NUM_YSANKE].num;
356 xsanke+= values[NUM_XSANKE].num; 345 xsanke+= values[NUM_XSANKE].num;
@@ -358,15 +347,19 @@ static int loopit(void)
358} 347}
359 348
360 349
361bool bounce(void) 350enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
362{ 351{
363 int w, h; 352 int w, h;
364 char *off = "[Off] to stop"; 353 char *off = "[Off] to stop";
365 int len = strlen(SS_TITLE); 354 int len;
366 355
367 lcd_setfont(FONT_SYSFIXED); 356 TEST_PLUGIN_API(api);
357 (void)(parameter);
358 rb = api;
368 359
369 lcd_getstringsize(SS_TITLE,&w, &h); 360 len = rb->strlen(SS_TITLE);
361 rb->lcd_setfont(FONT_SYSFIXED);
362 rb->lcd_getstringsize(SS_TITLE,&w, &h);
370 363
371 /* Get horizontel centering for text */ 364 /* Get horizontel centering for text */
372 len *= w; 365 len *= w;
@@ -380,11 +373,11 @@ bool bounce(void)
380 else 373 else
381 h /= 2; 374 h /= 2;
382 375
383 lcd_clear_display(); 376 rb->lcd_clear_display();
384 lcd_putsxy(LCD_WIDTH/2-len, (LCD_HEIGHT/2)-h, SS_TITLE); 377 rb->lcd_putsxy(LCD_WIDTH/2-len, (LCD_HEIGHT/2)-h, SS_TITLE);
385 378
386 len = 1; 379 len = 1;
387 lcd_getstringsize(off, &w, &h); 380 rb->lcd_getstringsize(off, &w, &h);
388 381
389 /* Get horizontel centering for text */ 382 /* Get horizontel centering for text */
390 len *= w; 383 len *= w;
@@ -398,10 +391,9 @@ bool bounce(void)
398 else 391 else
399 h /= 2; 392 h /= 2;
400 393
401 lcd_putsxy(LCD_WIDTH/2-len, LCD_HEIGHT-(2*h), off); 394 rb->lcd_putsxy(LCD_WIDTH/2-len, LCD_HEIGHT-(2*h), off);
402 395 rb->lcd_update();
403 lcd_update(); 396 rb->sleep(HZ);
404 sleep(HZ);
405 397
406 do { 398 do {
407 h= loopit(); 399 h= loopit();
@@ -409,7 +401,7 @@ bool bounce(void)
409 h = scrollit(); 401 h = scrollit();
410 } while(h); 402 } while(h);
411 403
412 lcd_setfont(FONT_UI); 404 rb->lcd_setfont(FONT_UI);
413 405
414 return false; 406 return false;
415} 407}
diff --git a/apps/recorder/cube.c b/apps/plugins/cube.c
index ad3af91c87..996a1a81dd 100644
--- a/apps/recorder/cube.c
+++ b/apps/plugins/cube.c
@@ -16,22 +16,10 @@
16* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 16* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
17* KIND, either express or implied. 17* KIND, either express or implied.
18* 18*
19****************************************************************************/ 19***************************************************************************/
20#include "plugin.h"
20 21
21#include "config.h" 22#ifdef HAVE_LCD_BITMAP
22#include "options.h"
23
24#ifdef USE_DEMOS
25
26#include <stdlib.h>
27#include "lcd.h"
28#include "config.h"
29#include "kernel.h"
30#include "menu.h"
31#include "button.h"
32#include "sprintf.h"
33#include "screens.h"
34#include "font.h"
35 23
36/* Loops that the values are displayed */ 24/* Loops that the values are displayed */
37#define DISP_TIME 30 25#define DISP_TIME 30
@@ -80,6 +68,8 @@ static int sin_table[91] =
80 10000 68 10000
81}; 69};
82 70
71static struct plugin_api* rb;
72
83static long sin(int val) 73static long sin(int val)
84{ 74{
85 /* Speed improvement through sukzessive lookup */ 75 /* Speed improvement through sukzessive lookup */
@@ -214,7 +204,7 @@ static void cube_init(void)
214 204
215static void line(int a, int b) 205static void line(int a, int b)
216{ 206{
217 lcd_drawline(point2D[a].x, point2D[a].y, point2D[b].x, point2D[b].y); 207 rb->lcd_drawline(point2D[a].x, point2D[a].y, point2D[b].x, point2D[b].y);
218} 208}
219 209
220static void cube_draw(void) 210static void cube_draw(void)
@@ -234,7 +224,8 @@ static void cube_draw(void)
234 line(3,6); 224 line(3,6);
235} 225}
236 226
237bool cube(void) 227
228enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
238{ 229{
239 int t_disp=0; 230 int t_disp=0;
240 char buffer[30]; 231 char buffer[30];
@@ -247,27 +238,31 @@ bool cube(void)
247 int zs=1; 238 int zs=1;
248 bool highspeed=0; 239 bool highspeed=0;
249 bool exit=0; 240 bool exit=0;
250 241
251 lcd_setfont(FONT_SYSFIXED); 242 TEST_PLUGIN_API(api);
243 (void)(parameter);
244 rb = api;
245
246 rb->lcd_setfont(FONT_SYSFIXED);
252 247
253 cube_init(); 248 cube_init();
254 249
255 while(!exit) 250 while(!exit)
256 { 251 {
257 if (!highspeed) 252 if (!highspeed)
258 sleep(4); 253 rb->sleep(4);
259 254
260 lcd_clear_display(); 255 rb->lcd_clear_display();
261 cube_rotate(xa,ya,za); 256 cube_rotate(xa,ya,za);
262 cube_viewport(); 257 cube_viewport();
263 cube_draw(); 258 cube_draw();
264 if (t_disp>0) 259 if (t_disp>0)
265 { 260 {
266 t_disp--; 261 t_disp--;
267 snprintf(buffer, 30, "x:%d y:%d z:%d h:%d",xs,ys,zs,highspeed); 262 rb->snprintf(buffer, 30, "x:%d y:%d z:%d h:%d",xs,ys,zs,highspeed);
268 lcd_putsxy(0, 56, buffer); 263 rb->lcd_putsxy(0, 56, buffer);
269 } 264 }
270 lcd_update(); 265 rb->lcd_update();
271 266
272 xa+=xs; 267 xa+=xs;
273 if (xa>359) 268 if (xa>359)
@@ -285,7 +280,7 @@ bool cube(void)
285 if (za<0) 280 if (za<0)
286 za+=360; 281 za+=360;
287 282
288 switch(button_get(false)) 283 switch(rb->button_get(false))
289 { 284 {
290 case BUTTON_RIGHT: 285 case BUTTON_RIGHT:
291 xs+=1; 286 xs+=1;
@@ -332,22 +327,12 @@ bool cube(void)
332 break; 327 break;
333 328
334 case SYS_USB_CONNECTED: 329 case SYS_USB_CONNECTED:
335 usb_screen(); 330 rb->usb_screen();
336 lcd_setfont(FONT_UI); 331 return PLUGIN_USB_CONNECTED;
337 return true;
338 } 332 }
339 } 333 }
340 334
341 lcd_setfont(FONT_UI); 335 return PLUGIN_OK;
342
343 return false;
344} 336}
345 337
346#endif /* USE_DEMOS */ 338#endif
347
348/* -----------------------------------------------------------------
349 * vim: et sw=4 ts=8 sts=4 tw=78
350 */
351
352
353
diff --git a/apps/plugins/helloworld.c b/apps/plugins/helloworld.c
new file mode 100644
index 0000000000..ea347fbf79
--- /dev/null
+++ b/apps/plugins/helloworld.c
@@ -0,0 +1,48 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2002 Björn Stenberg
11 *
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19#include "plugin.h"
20
21/* welcome to the example rockbox plugin */
22
23/* here is a global api struct pointer. while not strictly necessary,
24 it's nice not to have to pass the api pointer in all function calls
25 in the plugin */
26static struct plugin_api* rb;
27
28/* this is the plugin entry point */
29enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
30{
31 /* this macro should be called as the first thing you do in the plugin.
32 it test that the api version and model the plugin was compiled for
33 matches the machine it is running on */
34 TEST_PLUGIN_API(api);
35
36 /* if you don't use the parameter, you can do like
37 this to avoid the compiler warning about it */
38 (void)parameter;
39
40 /* if you are using a global api pointer, don't forget to copy it!
41 otherwise you will get lovely "I04: IllInstr" errors... :-) */
42 rb = api;
43
44 /* now go ahead and have fun! */
45 rb->splash(HZ*2, 0, true, "Hello world!");
46
47 return PLUGIN_OK;
48}
diff --git a/apps/recorder/oscillograph.c b/apps/plugins/oscillograph.c
index bf94db168f..a34aa8bfa9 100644
--- a/apps/recorder/oscillograph.c
+++ b/apps/plugins/oscillograph.c
@@ -16,17 +16,11 @@
16 * KIND, either express or implied. 16 * KIND, either express or implied.
17 * 17 *
18 ****************************************************************************/ 18 ****************************************************************************/
19#include "plugin.h"
19 20
21#ifdef HAVE_LCD_BITMAP
20#ifndef SIMULATOR /* don't want this code in the simulator */ 22#ifndef SIMULATOR /* don't want this code in the simulator */
21 23
22#include <stdlib.h>
23#include <sprintf.h>
24#include "menu.h"
25#include "lcd.h"
26#include "button.h"
27#include "mas.h"
28#include "system.h"
29
30/* The different drawing modes */ 24/* The different drawing modes */
31#define DRAW_MODE_FILLED 0 25#define DRAW_MODE_FILLED 0
32#define DRAW_MODE_OUTLINE 1 26#define DRAW_MODE_OUTLINE 1
@@ -47,7 +41,7 @@ static int drawMode = DRAW_MODE_FILLED;
47 * hardware scrolling of the display. The user can change 41 * hardware scrolling of the display. The user can change
48 * speed 42 * speed
49 */ 43 */
50bool oscillograph(void) 44enum plugin_status plugin_start(struct plugin_api* rb, void* parameter)
51{ 45{
52 /* stores current volume value left */ 46 /* stores current volume value left */
53 int left; 47 int left;
@@ -63,22 +57,25 @@ bool oscillograph(void)
63 57
64 bool exit = false; 58 bool exit = false;
65 59
60 TEST_PLUGIN_API(rb);
61 (void)parameter;
62
66 /* the main loop */ 63 /* the main loop */
67 while (!exit) { 64 while (!exit) {
68 65
69 /* read the volume info from MAS */ 66 /* read the volume info from MAS */
70 left = mas_codec_readreg(0xC) / (MAX_PEAK / (LCD_WIDTH / 2 - 2)); 67 left = rb->mas_codec_readreg(0xC) / (MAX_PEAK / (LCD_WIDTH / 2 - 2));
71 right = mas_codec_readreg(0xD) / (MAX_PEAK / (LCD_WIDTH / 2 - 2)); 68 right = rb->mas_codec_readreg(0xD) / (MAX_PEAK / (LCD_WIDTH / 2 - 2));
72 69
73 /* delete current line */ 70 /* delete current line */
74 lcd_clearline(0, y, LCD_WIDTH-1, y); 71 rb->lcd_clearline(0, y, LCD_WIDTH-1, y);
75 72
76 switch (drawMode) { 73 switch (drawMode) {
77 case DRAW_MODE_FILLED: 74 case DRAW_MODE_FILLED:
78 lcd_drawline(LCD_WIDTH / 2 + 1 , y, 75 rb->lcd_drawline(LCD_WIDTH / 2 + 1 , y,
79 LCD_WIDTH / 2 + 1 + right, y); 76 LCD_WIDTH / 2 + 1 + right, y);
80 lcd_drawline(LCD_WIDTH / 2 - 1 , y, 77 rb->lcd_drawline(LCD_WIDTH / 2 - 1 , y,
81 LCD_WIDTH / 2 - 1 -left , y); 78 LCD_WIDTH / 2 - 1 -left , y);
82 break; 79 break;
83 80
84 case DRAW_MODE_OUTLINE: 81 case DRAW_MODE_OUTLINE:
@@ -87,10 +84,10 @@ bool oscillograph(void)
87 84
88 /* Here real lines were neccessary because 85 /* Here real lines were neccessary because
89 anything else was ugly. */ 86 anything else was ugly. */
90 lcd_drawline(LCD_WIDTH / 2 + right , y, 87 rb->lcd_drawline(LCD_WIDTH / 2 + right , y,
91 LCD_WIDTH / 2 + lastRight , lasty); 88 LCD_WIDTH / 2 + lastRight , lasty);
92 lcd_drawline(LCD_WIDTH / 2 - left , y, 89 rb->lcd_drawline(LCD_WIDTH / 2 - left , y,
93 LCD_WIDTH / 2 - lastLeft, lasty); 90 LCD_WIDTH / 2 - lastLeft, lasty);
94 91
95 /* have to store the old values for drawing lines 92 /* have to store the old values for drawing lines
96 the next time */ 93 the next time */
@@ -100,8 +97,8 @@ bool oscillograph(void)
100 97
101 case DRAW_MODE_PIXEL: 98 case DRAW_MODE_PIXEL:
102 /* straight and simple */ 99 /* straight and simple */
103 lcd_drawpixel(LCD_WIDTH / 2 + right, y); 100 rb->lcd_drawpixel(LCD_WIDTH / 2 + right, y);
104 lcd_drawpixel(LCD_WIDTH / 2 - left, y); 101 rb->lcd_drawpixel(LCD_WIDTH / 2 - left, y);
105 break; 102 break;
106 } 103 }
107 104
@@ -114,19 +111,19 @@ bool oscillograph(void)
114 /* I roll before update because otherwise the new 111 /* I roll before update because otherwise the new
115 line would appear at the wrong end of the display */ 112 line would appear at the wrong end of the display */
116 if (roll) 113 if (roll)
117 lcd_roll(y); 114 rb->lcd_roll(y);
118 115
119 /* now finally make the new sample visible */ 116 /* now finally make the new sample visible */
120 lcd_update_rect(0, MAX(y-1, 0), LCD_WIDTH, 2); 117 rb->lcd_update_rect(0, MAX(y-1, 0), LCD_WIDTH, 2);
121 118
122 /* There are two mechanisms to alter speed: 119 /* There are two mechanisms to alter speed:
123 1.) slowing down is achieved by increasing 120 1.) slowing down is achieved by increasing
124 the time waiting for user input. This 121 the time waiting for user input. This
125 mechanism uses positive values. 122 mechanism uses positive values.
126 2.) speeding up is achieved by leaving out 123 2.) speeding up is achieved by leaving out
127 the user input check for (-speed) volume 124 the user input check for (-speed) volume
128 samples. For this mechanism negative values 125 samples. For this mechanism negative values
129 are used. 126 are used.
130 */ 127 */
131 128
132 if (speed >= 0 || ((speed < 0) && (y % (-speed) == 0))) { 129 if (speed >= 0 || ((speed < 0) && (y % (-speed) == 0))) {
@@ -138,7 +135,7 @@ bool oscillograph(void)
138 it must be ensured that at least 1 is passed. */ 135 it must be ensured that at least 1 is passed. */
139 136
140 /* react to user input */ 137 /* react to user input */
141 switch (button_get_w_tmo(MAX(speed, 1))) { 138 switch (rb->button_get_w_tmo(MAX(speed, 1))) {
142 case BUTTON_UP: 139 case BUTTON_UP:
143 speed++; 140 speed++;
144 draw = true; 141 draw = true;
@@ -151,7 +148,7 @@ bool oscillograph(void)
151 148
152 case BUTTON_PLAY: 149 case BUTTON_PLAY:
153 /* pause the demo */ 150 /* pause the demo */
154 button_get(true); 151 rb->button_get(true);
155 break; 152 break;
156 153
157 case BUTTON_F1: 154 case BUTTON_F1:
@@ -170,7 +167,7 @@ bool oscillograph(void)
170 That produces ugly results in DRAW_MODE_OUTLINE 167 That produces ugly results in DRAW_MODE_OUTLINE
171 mode. If rolling is enabled this change will 168 mode. If rolling is enabled this change will
172 be reverted before the next update anyway.*/ 169 be reverted before the next update anyway.*/
173 lcd_roll(0); 170 rb->lcd_roll(0);
174 break; 171 break;
175 172
176 case BUTTON_F3: 173 case BUTTON_F3:
@@ -181,27 +178,30 @@ bool oscillograph(void)
181 case BUTTON_OFF: 178 case BUTTON_OFF:
182 exit = true; 179 exit = true;
183 break; 180 break;
181
182 case SYS_USB_CONNECTED:
183 rb->usb_screen();
184 return PLUGIN_USB_CONNECTED;
184 } 185 }
185 186
186 if (draw) { 187 if (draw) {
187 char buf[16]; 188 char buf[16];
188 snprintf(buf, sizeof buf, "Speed: %d", -speed); 189 rb->snprintf(buf, sizeof buf, "Speed: %d", -speed);
189 lcd_putsxy(0, (y + LCD_HEIGHT - 8) % LCD_HEIGHT, buf); 190 rb->lcd_putsxy(0, (y + LCD_HEIGHT - 8) % LCD_HEIGHT, buf);
190 lcd_update_rect(0, (y + LCD_HEIGHT - 8) % LCD_HEIGHT, 191 rb->lcd_update_rect(0, (y + LCD_HEIGHT - 8) % LCD_HEIGHT,
191 LCD_WIDTH, 8); 192 LCD_WIDTH, 8);
192 } 193 }
193 } 194 }
194 } 195 }
195 196
196 /* restore to default roll position. 197 /* restore to default roll position.
197 Looks funny if you forget to do this... */ 198 Looks funny if you forget to do this... */
198 lcd_roll(0); 199 rb->lcd_roll(0);
199 lcd_update(); 200 rb->lcd_update();
200 201
201 /* standard return */ 202 /* standard return */
202 return false; 203 return PLUGIN_OK;
203} 204}
204 205
205#endif /* #ifndef SIMULATOR */ 206#endif /* #ifndef SIMULATOR */
206 207#endif
207
diff --git a/apps/plugins/plugin.lds b/apps/plugins/plugin.lds
new file mode 100644
index 0000000000..be6b6fd0a6
--- /dev/null
+++ b/apps/plugins/plugin.lds
@@ -0,0 +1,26 @@
1OUTPUT_FORMAT(elf32-sh)
2
3MEMORY
4{
5 PLUGIN_RAM : ORIGIN = 0x091f8000, LENGTH = 0x8000
6}
7
8SECTIONS
9{
10 .text : {
11 *(.entry)
12 *(.text)
13 } > PLUGIN_RAM
14
15 .data : {
16 *(.data)
17 } > PLUGIN_RAM
18
19 .bss : {
20 *(.bss)
21 } > PLUGIN_RAM
22
23 .rodata : {
24 *(.rodata)
25 } > PLUGIN_RAM
26}
diff --git a/apps/recorder/snow.c b/apps/plugins/snow.c
index c4e952f21d..df9966eb38 100644
--- a/apps/recorder/snow.c
+++ b/apps/plugins/snow.c
@@ -15,17 +15,15 @@
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied. 16 * KIND, either express or implied.
17 * 17 *
18 ****************************************************************************/ 18 **************************************************************************/
19#include <stdlib.h> 19#include "plugin.h"
20#include "lcd.h" 20
21#include "config.h" 21#ifdef HAVE_LCD_BITMAP
22#include "kernel.h"
23#include "menu.h"
24#include "button.h"
25 22
26#define NUM_PARTICLES 100 23#define NUM_PARTICLES 100
27 24
28static short particles[NUM_PARTICLES][2]; 25static short particles[NUM_PARTICLES][2];
26static struct plugin_api* rb;
29 27
30static bool particle_exists(int particle) 28static bool particle_exists(int particle)
31{ 29{
@@ -42,7 +40,7 @@ static int create_particle(void)
42 40
43 for (i=0; i<NUM_PARTICLES; i++) { 41 for (i=0; i<NUM_PARTICLES; i++) {
44 if (!particle_exists(i)) { 42 if (!particle_exists(i)) {
45 particles[i][0]=(rand()%112); 43 particles[i][0]=(rb->rand()%112);
46 particles[i][1]=0; 44 particles[i][1]=0;
47 return i; 45 return i;
48 } 46 }
@@ -54,13 +52,13 @@ static void snow_move(void)
54{ 52{
55 int i; 53 int i;
56 54
57 if (!(rand()%2)) 55 if (!(rb->rand()%2))
58 create_particle(); 56 create_particle();
59 57
60 for (i=0; i<NUM_PARTICLES; i++) { 58 for (i=0; i<NUM_PARTICLES; i++) {
61 if (particle_exists(i)) { 59 if (particle_exists(i)) {
62 lcd_clearpixel(particles[i][0],particles[i][1]); 60 rb->lcd_clearpixel(particles[i][0],particles[i][1]);
63 switch ((rand()%7)) { 61 switch ((rb->rand()%7)) {
64 case 0: 62 case 0:
65 particles[i][0]++; 63 particles[i][0]++;
66 break; 64 break;
@@ -77,7 +75,7 @@ static void snow_move(void)
77 break; 75 break;
78 } 76 }
79 if (particle_exists(i)) 77 if (particle_exists(i))
80 lcd_drawpixel(particles[i][0],particles[i][1]); 78 rb->lcd_drawpixel(particles[i][0],particles[i][1]);
81 } 79 }
82 } 80 }
83} 81}
@@ -90,28 +88,24 @@ static void snow_init(void)
90 particles[i][0]=-1; 88 particles[i][0]=-1;
91 particles[i][1]=-1; 89 particles[i][1]=-1;
92 } 90 }
93 lcd_clear_display(); 91 rb->lcd_clear_display();
94} 92}
95 93
96bool snow(void) 94enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
97{ 95{
98 snow_init(); 96 TEST_PLUGIN_API(api);
97 (void)(parameter);
98 rb = api;
99 99
100 snow_init();
100 while (1) { 101 while (1) {
101 snow_move(); 102 snow_move();
102 lcd_update(); 103 rb->lcd_update();
103 sleep(HZ/20); 104 rb->sleep(HZ/20);
104 105
105 if (button_get(false) == BUTTON_OFF) 106 if (rb->button_get(false) == BUTTON_OFF)
106 return false; 107 return false;
107 } 108 }
108} 109}
109 110
110 111#endif
111
112
113
114
115
116
117
diff --git a/apps/plugins/sokoban.c b/apps/plugins/sokoban.c
new file mode 100644
index 0000000000..2387fa9517
--- /dev/null
+++ b/apps/plugins/sokoban.c
@@ -0,0 +1,868 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2002 Eric Linenberg
11 * February 2003: Robert Hak performs a cleanup/rewrite/feature addition.
12 * Eric smiles. Bjorn cries. Linus say 'huh?'.
13 *
14 * All files in this archive are subject to the GNU General Public License.
15 * See the file COPYING in the source tree root for full license agreement.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include "plugin.h"
22
23#ifdef HAVE_LCD_BITMAP
24
25#define SOKOBAN_TITLE "Sokoban"
26#define SOKOBAN_TITLE_FONT 2
27
28#define LEVELS_FILE "/.rockbox/sokoban/levels.txt"
29
30#define ROWS 16
31#define COLS 20
32#define MAX_UNDOS 5
33
34#define SOKOBAN_LEVEL_SIZE (ROWS*COLS)
35
36static void init_undo(void);
37static void undo(void);
38static void add_undo(int button);
39
40static int get_level(char *level, int level_size);
41static int get_level_count(void);
42static int load_level(void);
43static void draw_level(void);
44
45static void init_boards(void);
46static void update_screen(void);
47static bool sokoban_loop(void);
48
49/* The Location, Undo and LevelInfo structs are OO-flavored.
50 * (oooh!-flavored as Schnueff puts it.) It makes more you have to know,
51 * but the overall data layout becomes more manageable. */
52
53/* We use the same three values in 2 structs. Makeing them a struct
54 * hopefully ensures that if you change things in one, the other changes
55 * as well. */
56struct LevelInfo {
57 short level;
58 short moves;
59 short boxes_to_go;
60};
61
62/* What a given location on the board looks like at a given time */
63struct Location {
64 char spot;
65 short row;
66 short col;
67};
68
69/* A single level of undo. Each undo move can affect upto,
70 * but not more then, 3 spots on the board */
71struct Undo {
72 struct LevelInfo level;
73 struct Location location[3];
74};
75
76/* Our full undo history */
77static struct UndoInfo {
78 short count; /* How many undos are there in history */
79 short current; /* Which history is the current undo */
80 struct Undo history[MAX_UNDOS];
81} undo_info;
82
83/* Our playing board */
84static struct BoardInfo {
85 char board[ROWS][COLS];
86 struct LevelInfo level;
87 struct Location player;
88 int max_level; /* How many levels do we have? */
89 int level_offset; /* Where in the level file is this level */
90 int loaded_level; /* Which level is in memory */
91} current_info;
92
93static struct plugin_api* rb;
94
95static void init_undo(void)
96{
97 undo_info.count = 0;
98 undo_info.current = 0;
99}
100
101static void undo(void)
102{
103 struct Undo *undo;
104 int i = 0;
105 short row, col;
106
107 if (undo_info.count == 0)
108 return;
109
110 /* Update board info */
111 undo = &undo_info.history[undo_info.current];
112
113 rb->memcpy(&current_info.level, &undo->level, sizeof(undo->level));
114 rb->memcpy(&current_info.player, &undo->location[0], sizeof(undo->location[0]));
115
116 row = undo->location[0].row;
117 col = undo->location[0].col;
118 current_info.board[row][col] = '@';
119
120 /* Update the two other possible spots */
121 for (i = 1; i < 3; i++) {
122 if (undo->location[i].spot != '\0') {
123 row = undo->location[i].row;
124 col = undo->location[i].col;
125 current_info.board[row][col] = undo->location[i].spot;
126 undo->location[i].spot = '\0';
127 }
128 }
129
130 /* Remove this undo from the list */
131 if (undo_info.current == 0) {
132 if (undo_info.count > 1)
133 undo_info.current = MAX_UNDOS - 1;
134 } else {
135 undo_info.current--;
136 }
137
138 undo_info.count--;
139
140 return;
141}
142
143static void add_undo(int button)
144{
145 struct Undo *undo;
146 int row, col, i;
147 bool storable;
148
149 if ((button != BUTTON_LEFT) && (button != BUTTON_RIGHT) &&
150 (button != BUTTON_UP) && (button != BUTTON_DOWN))
151 return;
152
153 if (undo_info.count != 0) {
154 if (undo_info.current < (MAX_UNDOS - 1))
155 undo_info.current++;
156 else
157 undo_info.current = 0;
158 }
159
160 /* Make what follows more readable */
161 undo = &undo_info.history[undo_info.current];
162
163 /* Store our level info */
164 rb->memcpy(&undo->level, &current_info.level, sizeof(undo->level));
165
166 /* Store our player info */
167 rb->memcpy(&undo->location[0], &current_info.player, sizeof(undo->location[0]));
168
169 /* Now we need to store upto 2 blocks that may be affected.
170 * If player.spot is NULL, then there is no info stored
171 * for that block */
172
173 row = current_info.player.row;
174 col = current_info.player.col;
175
176 /* This must stay as _1_ because the first block (0) is the player */
177 for (i = 1; i < 3; i++) {
178 storable = true;
179
180 switch (button) {
181 case BUTTON_LEFT:
182 col--;
183 if (col < 0)
184 storable = false;
185 break;
186
187 case BUTTON_RIGHT:
188 col++;
189 if (col >= COLS)
190 storable = false;
191 break;
192
193 case BUTTON_UP:
194 row--;
195 if (row < 0)
196 storable = false;
197 break;
198
199 case BUTTON_DOWN:
200 row++;
201 if (row >= ROWS)
202 storable = false;
203 break;
204
205 default:
206 return;
207 }
208
209 if (storable) {
210 undo->location[i].col = col;
211 undo->location[i].row = row;
212 undo->location[i].spot = current_info.board[row][col];
213 } else {
214 undo->location[i].spot = '\0';
215 }
216 }
217
218 if (undo_info.count < MAX_UNDOS)
219 undo_info.count++;
220}
221
222static void init_boards(void)
223{
224 current_info.level.level = 0;
225 current_info.level.moves = 0;
226 current_info.level.boxes_to_go = 0;
227 current_info.player.row = 0;
228 current_info.player.col = 0;
229 current_info.player.spot = ' ';
230 current_info.max_level = 0;
231 current_info.level_offset = 0;
232 current_info.loaded_level = 0;
233
234 init_undo();
235}
236
237static int get_level_count(void)
238{
239 int fd = 0;
240 int lastlen = 0;
241 char buffer[COLS + 3]; /* COLS plus CR/LF and \0 */
242
243 if ((fd = rb->open(LEVELS_FILE, O_RDONLY)) < 0) {
244 rb->splash(0, 0, true, "Unable to open %s", LEVELS_FILE);
245 return -1;
246 }
247
248 while(1) {
249 int len = rb->read_line(fd, buffer, sizeof(buffer));
250 if(len <= 0)
251 break;
252
253 /* Two short lines in a row means new level */
254 if(len < 3 && lastlen < 3)
255 current_info.max_level++;
256
257 lastlen = len;
258 }
259
260 rb->close(fd);
261 return 0;
262}
263
264static int get_level(char *level, int level_size)
265{
266 int fd = 0, i = 0;
267 int nread = 0;
268 int count = 0;
269 int lastlen = 0;
270 int level_ct = 1;
271 unsigned char buffer[SOKOBAN_LEVEL_SIZE * 2];
272 bool level_found = false;
273
274 /* open file */
275 if ((fd = rb->open(LEVELS_FILE, O_RDONLY)) < 0)
276 return -1;
277
278 /* Lets not reparse the full file if we can avoid it */
279 if (current_info.loaded_level < current_info.level.level) {
280 rb->lseek(fd, current_info.level_offset, SEEK_SET);
281 level_ct = current_info.loaded_level;
282 }
283
284 if(current_info.level.level > 1) {
285 while(!level_found) {
286 int len = rb->read_line(fd, buffer, SOKOBAN_LEVEL_SIZE);
287 if(len <= 0) {
288 rb->close(fd);
289 return -1;
290 }
291
292 /* Two short lines in a row means new level */
293 if(len < 3 && lastlen < 3) {
294 level_ct++;
295 if(level_ct == current_info.level.level)
296 level_found = true;
297 }
298 lastlen = len;
299 }
300 }
301
302 /* Remember the current offset */
303 current_info.level_offset = rb->lseek(fd, 0, SEEK_CUR);
304
305 /* read a full buffer chunk from here */
306 nread = rb->read(fd, buffer, sizeof(buffer)-1);
307 if (nread < 0)
308 return -1;
309 buffer[nread] = 0;
310
311 rb->close(fd);
312
313 /* If we read less then a level, error */
314 if (nread < level_size)
315 return -1;
316
317 /* Load our new level */
318 for(i=0, count=0; (count < nread) && (i<level_size);) {
319 if (buffer[count] != '\n' && buffer[count] != '\r')
320 level[i++] = buffer[count];
321 count++;
322 }
323 level[i] = 0;
324
325 current_info.loaded_level = current_info.level.level;
326 return 0;
327}
328
329/* return non-zero on error */
330static int load_level(void)
331{
332 short c = 0;
333 short r = 0;
334 short i = 0;
335 char level[ROWS*COLS+1];
336 int x = 0;
337
338 current_info.player.spot=' ';
339 current_info.level.boxes_to_go = 0;
340 current_info.level.moves = 0;
341
342 if (get_level(level, sizeof(level)) != 0)
343 return -1;
344
345 i = 0;
346 for (r = 0; r < ROWS; r++) {
347 x++;
348 for (c = 0; c < COLS; c++, i++) {
349 current_info.board[r][c] = level[i];
350
351 if (current_info.board[r][c] == '.')
352 current_info.level.boxes_to_go++;
353
354 else if (current_info.board[r][c] == '@') {
355 current_info.player.row = r;
356 current_info.player.col = c;
357 }
358 }
359 }
360
361 return 0;
362}
363
364static void update_screen(void)
365{
366 short b = 0, c = 0;
367 short rows = 0, cols = 0;
368 char s[25];
369
370 short magnify = 4;
371
372 /* load the board to the screen */
373 for (rows=0 ; rows < ROWS ; rows++) {
374 for (cols = 0 ; cols < COLS ; cols++) {
375 c = cols * magnify;
376 b = rows * magnify;
377
378 switch(current_info.board[rows][cols]) {
379 case 'X': /* black space */
380 rb->lcd_drawrect(c, b, magnify, magnify);
381 rb->lcd_drawrect(c+1, b+1, 2, 2);
382 break;
383
384 case '#': /* this is a wall */
385 rb->lcd_drawpixel(c, b);
386 rb->lcd_drawpixel(c+2, b);
387 rb->lcd_drawpixel(c+1, b+1);
388 rb->lcd_drawpixel(c+3, b+1);
389 rb->lcd_drawpixel(c, b+2);
390 rb->lcd_drawpixel(c+2, b+2);
391 rb->lcd_drawpixel(c+1, b+3);
392 rb->lcd_drawpixel(c+3, b+3);
393 break;
394
395 case '.': /* this is a home location */
396 rb->lcd_drawrect(c+1, b+1, 2, 2);
397 break;
398
399 case '$': /* this is a box */
400 rb->lcd_drawrect(c, b, magnify, magnify);
401 break;
402
403 case '@': /* this is you */
404 rb->lcd_drawline(c+1, b, c+2, b);
405 rb->lcd_drawline(c, b+1, c+3, b+1);
406 rb->lcd_drawline(c+1, b+2, c+2, b+2);
407
408 rb->lcd_drawpixel(c, b+3);
409 rb->lcd_drawpixel(c+3, b+3);
410 break;
411
412 case '%': /* this is a box on a home spot */
413 rb->lcd_drawrect(c, b, magnify, magnify);
414 rb->lcd_drawrect(c+1, b+1, 2, 2);
415 break;
416 }
417 }
418 }
419
420
421 rb->snprintf(s, sizeof(s), "%d", current_info.level.level);
422 rb->lcd_putsxy(86, 22, s);
423 rb->snprintf(s, sizeof(s), "%d", current_info.level.moves);
424 rb->lcd_putsxy(86, 54, s);
425
426 rb->lcd_drawrect(80,0,32,32);
427 rb->lcd_drawrect(80,32,32,64);
428 rb->lcd_putsxy(81, 10, "Level");
429 rb->lcd_putsxy(81, 42, "Moves");
430
431 /* print out the screen */
432 rb->lcd_update();
433}
434
435static void draw_level(void)
436{
437 load_level();
438 rb->lcd_clear_display();
439 update_screen();
440}
441
442static bool sokoban_loop(void)
443{
444 char new_spot;
445 bool moved = true;
446 int i = 0, button = 0;
447 short r = 0, c = 0;
448
449 current_info.level.level = 1;
450
451 load_level();
452 update_screen();
453
454 while (1) {
455 moved = true;
456
457 r = current_info.player.row;
458 c = current_info.player.col;
459
460 button = rb->button_get(true);
461
462 add_undo(button);
463
464 switch(button)
465 {
466 case BUTTON_OFF:
467 /* get out of here */
468 return PLUGIN_OK;
469
470 case BUTTON_ON:
471 case BUTTON_ON | BUTTON_REPEAT:
472 /* this is UNDO */
473 undo();
474 rb->lcd_clear_display();
475 update_screen();
476 moved = false;
477 break;
478
479 case BUTTON_F3:
480 case BUTTON_F3 | BUTTON_REPEAT:
481 /* increase level */
482 init_undo();
483 current_info.level.boxes_to_go=0;
484 moved = true;
485 break;
486
487 case BUTTON_F1:
488 case BUTTON_F1 | BUTTON_REPEAT:
489 /* previous level */
490 init_undo();
491 if (current_info.level.level > 1)
492 current_info.level.level--;
493
494 draw_level();
495 moved = false;
496 break;
497
498 case BUTTON_F2:
499 case BUTTON_F2 | BUTTON_REPEAT:
500 /* same level */
501 init_undo();
502 draw_level();
503 moved = false;
504 break;
505
506 case BUTTON_LEFT:
507 switch(current_info.board[r][c-1])
508 {
509 case ' ': /* if it is a blank spot */
510 case '.': /* if it is a home spot */
511 new_spot = current_info.board[r][c-1];
512 current_info.board[r][c-1] = '@';
513 current_info.board[r][c] = current_info.player.spot;
514 current_info.player.spot = new_spot;
515 break;
516
517 case '$':
518 switch(current_info.board[r][c-2])
519 {
520 case ' ': /* going from blank to blank */
521 current_info.board[r][c-2] = current_info.board[r][c-1];
522 current_info.board[r][c-1] = current_info.board[r][c];
523 current_info.board[r][c] = current_info.player.spot;
524 current_info.player.spot = ' ';
525 break;
526
527 case '.': /* going from a blank to home */
528 current_info.board[r][c-2] = '%';
529 current_info.board[r][c-1] = current_info.board[r][c];
530 current_info.board[r][c] = current_info.player.spot;
531 current_info.player.spot = ' ';
532 current_info.level.boxes_to_go--;
533 break;
534
535 default:
536 moved = false;
537 break;
538 }
539 break;
540
541 case '%':
542 switch(current_info.board[r][c-2]) {
543 case ' ': /* we are going from a home to a blank */
544 current_info.board[r][c-2] = '$';
545 current_info.board[r][c-1] = current_info.board[r][c];
546 current_info.board[r][c] = current_info.player.spot;
547 current_info.player.spot = '.';
548 current_info.level.boxes_to_go++;
549 break;
550
551 case '.': /* if we are going from a home to home */
552 current_info.board[r][c-2] = '%';
553 current_info.board[r][c-1] = current_info.board[r][c];
554 current_info.board[r][c] = current_info.player.spot;
555 current_info.player.spot = '.';
556 break;
557
558 default:
559 moved = false;
560 break;
561 }
562 break;
563
564 default:
565 moved = false;
566 break;
567 }
568
569 if (moved)
570 current_info.player.col--;
571 break;
572
573 case BUTTON_RIGHT: /* if it is a blank spot */
574 switch(current_info.board[r][c+1]) {
575 case ' ':
576 case '.': /* if it is a home spot */
577 new_spot = current_info.board[r][c+1];
578 current_info.board[r][c+1] = '@';
579 current_info.board[r][c] = current_info.player.spot;
580 current_info.player.spot = new_spot;
581 break;
582
583 case '$':
584 switch(current_info.board[r][c+2]) {
585 case ' ': /* going from blank to blank */
586 current_info.board[r][c+2] = current_info.board[r][c+1];
587 current_info.board[r][c+1] = current_info.board[r][c];
588 current_info.board[r][c] = current_info.player.spot;
589 current_info.player.spot = ' ';
590 break;
591
592 case '.': /* going from a blank to home */
593 current_info.board[r][c+2] = '%';
594 current_info.board[r][c+1] = current_info.board[r][c];
595 current_info.board[r][c] = current_info.player.spot;
596 current_info.player.spot = ' ';
597 current_info.level.boxes_to_go--;
598 break;
599
600 default:
601 moved = false;
602 break;
603 }
604 break;
605
606 case '%':
607 switch(current_info.board[r][c+2]) {
608 case ' ': /* going from a home to a blank */
609 current_info.board[r][c+2] = '$';
610 current_info.board[r][c+1] = current_info.board[r][c];
611 current_info.board[r][c] = current_info.player.spot;
612 current_info.player.spot = '.';
613 current_info.level.boxes_to_go++;
614 break;
615
616 case '.':
617 current_info.board[r][c+2] = '%';
618 current_info.board[r][c+1] = current_info.board[r][c];
619 current_info.board[r][c] = current_info.player.spot;
620 current_info.player.spot = '.';
621 break;
622
623 default:
624 moved = false;
625 break;
626 }
627 break;
628
629 default:
630 moved = false;
631 break;
632 }
633
634 if (moved)
635 current_info.player.col++;
636 break;
637
638 case BUTTON_UP:
639 switch(current_info.board[r-1][c]) {
640 case ' ': /* if it is a blank spot */
641 case '.': /* if it is a home spot */
642 new_spot = current_info.board[r-1][c];
643 current_info.board[r-1][c] = '@';
644 current_info.board[r][c] = current_info.player.spot;
645 current_info.player.spot = new_spot;
646 break;
647
648 case '$':
649 switch(current_info.board[r-2][c]) {
650 case ' ': /* going from blank to blank */
651 current_info.board[r-2][c] = current_info.board[r-1][c];
652 current_info.board[r-1][c] = current_info.board[r][c];
653 current_info.board[r][c] = current_info.player.spot;
654 current_info.player.spot = ' ';
655 break;
656
657 case '.': /* going from a blank to home */
658 current_info.board[r-2][c] = '%';
659 current_info.board[r-1][c] = current_info.board[r][c];
660 current_info.board[r][c] = current_info.player.spot;
661 current_info.player.spot = ' ';
662 current_info.level.boxes_to_go--;
663 break;
664
665 default:
666 moved = false;
667 break;
668 }
669 break;
670
671 case '%':
672 switch(current_info.board[r-2][c]) {
673 case ' ': /* we are going from a home to a blank */
674 current_info.board[r-2][c] = '$';
675 current_info.board[r-1][c] = current_info.board[r][c];
676 current_info.board[r][c] = current_info.player.spot;
677 current_info.player.spot = '.';
678 current_info.level.boxes_to_go++;
679 break;
680
681 case '.': /* if we are going from a home to home */
682 current_info.board[r-2][c] = '%';
683 current_info.board[r-1][c] = current_info.board[r][c];
684 current_info.board[r][c] = current_info.player.spot;
685 current_info.player.spot = '.';
686 break;
687
688 default:
689 moved = false;
690 break;
691 }
692 break;
693
694 default:
695 moved = false;
696 break;
697 }
698
699 if (moved)
700 current_info.player.row--;
701 break;
702
703 case BUTTON_DOWN:
704 switch(current_info.board[r+1][c]) {
705 case ' ': /* if it is a blank spot */
706 case '.': /* if it is a home spot */
707 new_spot = current_info.board[r+1][c];
708 current_info.board[r+1][c] = '@';
709 current_info.board[r][c] = current_info.player.spot;
710 current_info.player.spot = new_spot;
711 break;
712
713 case '$':
714 switch(current_info.board[r+2][c]) {
715 case ' ': /* going from blank to blank */
716 current_info.board[r+2][c] = current_info.board[r+1][c];
717 current_info.board[r+1][c] = current_info.board[r][c];
718 current_info.board[r][c] = current_info.player.spot;
719 current_info.player.spot = ' ';
720 break;
721
722 case '.': /* going from a blank to home */
723 current_info.board[r+2][c] = '%';
724 current_info.board[r+1][c] = current_info.board[r][c];
725 current_info.board[r][c] = current_info.player.spot;
726 current_info.player.spot = ' ';
727 current_info.level.boxes_to_go--;
728 break;
729
730 default:
731 moved = false;
732 break;
733 }
734 break;
735
736 case '%':
737 switch(current_info.board[r+2][c]) {
738 case ' ': /* going from a home to a blank */
739 current_info.board[r+2][c] = '$';
740 current_info.board[r+1][c] = current_info.board[r][c];
741 current_info.board[r][c] = current_info.player.spot;
742 current_info.player.spot = '.';
743 current_info.level.boxes_to_go++;
744 break;
745
746 case '.': /* going from a home to home */
747 current_info.board[r+2][c] = '%';
748 current_info.board[r+1][c] = current_info.board[r][c];
749 current_info.board[r][c] = current_info.player.spot;
750 current_info.player.spot = '.';
751 break;
752
753 default:
754 moved = false;
755 break;
756 }
757 break;
758
759 default:
760 moved = false;
761 break;
762 }
763
764 if (moved)
765 current_info.player.row++;
766 break;
767
768 case SYS_USB_CONNECTED:
769 rb->usb_screen();
770 return PLUGIN_USB_CONNECTED;
771
772 default:
773 moved = false;
774 break;
775 }
776
777 if (moved) {
778 current_info.level.moves++;
779 rb->lcd_clear_display();
780 update_screen();
781 }
782
783 /* We have completed this level */
784 if (current_info.level.boxes_to_go == 0) {
785 current_info.level.level++;
786
787 /* clear undo stats */
788 init_undo();
789
790 rb->lcd_clear_display();
791
792 if (current_info.level.level > current_info.max_level) {
793 rb->lcd_putsxy(10, 20, "You WIN!!");
794
795 for (i = 0; i < 30000 ; i++) {
796 rb->lcd_invertrect(0, 0, 111, 63);
797 rb->lcd_update();
798
799 button = rb->button_get(false);
800 if (button && ((button & BUTTON_REL) != BUTTON_REL))
801 break;
802 }
803
804 return PLUGIN_OK;
805 }
806
807 load_level();
808 update_screen();
809 }
810
811 } /* end while */
812
813 return PLUGIN_OK;
814}
815
816
817enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
818{
819 int w, h;
820 int len;
821
822 TEST_PLUGIN_API(api);
823 (void)(parameter);
824 rb = api;
825
826 rb->lcd_setfont(FONT_SYSFIXED);
827 rb->lcd_getstringsize(SOKOBAN_TITLE, &w, &h);
828
829 /* Get horizontel centering for text */
830 len = w;
831 if (len%2 != 0)
832 len =((len+1)/2)+(w/2);
833 else
834 len /= 2;
835
836 if (h%2 != 0)
837 h = (h/2)+1;
838 else
839 h /= 2;
840
841 rb->lcd_clear_display();
842 rb->lcd_putsxy(LCD_WIDTH/2-len,(LCD_HEIGHT/2)-h, SOKOBAN_TITLE);
843 rb->lcd_update();
844 rb->sleep(HZ*2);
845
846 rb->lcd_clear_display();
847
848 rb->lcd_putsxy(3, 6, "[OFF] To Stop");
849 rb->lcd_putsxy(3, 16, "[ON] To Undo");
850 rb->lcd_putsxy(3, 26, "[F1] - Level");
851 rb->lcd_putsxy(3, 36, "[F2] Same Level");
852 rb->lcd_putsxy(3, 46, "[F3] + Level");
853
854 rb->lcd_update();
855 rb->sleep(HZ*2);
856 rb->lcd_clear_display();
857
858 init_boards();
859
860 if (get_level_count() != 0) {
861 rb->splash(HZ*2,0,true,"Failed loading levels!");
862 return PLUGIN_OK;
863 }
864
865 return sokoban_loop();
866}
867
868#endif
diff --git a/apps/viewer.c b/apps/plugins/viewer.c
index f653866626..f8dc309a6e 100644
--- a/apps/viewer.c
+++ b/apps/plugins/viewer.c
@@ -17,24 +17,9 @@
17 * KIND, either express or implied. 17 * KIND, either express or implied.
18 * 18 *
19 ****************************************************************************/ 19 ****************************************************************************/
20#include <stdio.h> 20#include "plugin.h"
21#include <string.h>
22#include <stdlib.h>
23#include <stdbool.h>
24
25#include "file.h"
26#include "lcd.h"
27#include "button.h"
28#include "kernel.h"
29#include "font.h"
30#include "settings.h"
31#include "icons.h"
32#include "screens.h"
33#include "status.h"
34
35 21
36#define BUFFER_SIZE 1024 22#define BUFFER_SIZE 1024
37
38#define OUTSIDE_BUFFER -10 23#define OUTSIDE_BUFFER -10
39#define OUTSIDE_FILE -11 24#define OUTSIDE_FILE -11
40 25
@@ -50,6 +35,7 @@ static int begin_line; /* Index of the first line displayed on the lcd */
50static int end_line; /* Index of the last line displayed on the lcd */ 35static int end_line; /* Index of the last line displayed on the lcd */
51static int begin_line_pos; /* Position of the first_line in the bufffer */ 36static int begin_line_pos; /* Position of the first_line in the bufffer */
52static int end_line_pos; /* Position of the last_line in the buffer */ 37static int end_line_pos; /* Position of the last_line in the buffer */
38static struct plugin_api* rb;
53 39
54/* 40/*
55 * Known issue: The caching algorithm will fail (display incoherent data) if 41 * Known issue: The caching algorithm will fail (display incoherent data) if
@@ -61,7 +47,7 @@ static void display_line_count(void)
61{ 47{
62#ifdef HAVE_LCD_BITMAP 48#ifdef HAVE_LCD_BITMAP
63 int w,h; 49 int w,h;
64 lcd_getstringsize("M", &w, &h); 50 rb->lcd_getstringsize("M", &w, &h);
65 display_lines = LCD_HEIGHT / h; 51 display_lines = LCD_HEIGHT / h;
66 display_columns = LCD_WIDTH / w; 52 display_columns = LCD_WIDTH / w;
67#else 53#else
@@ -126,7 +112,7 @@ static void viewer_draw(int col)
126 char* str; 112 char* str;
127 int line_pos; 113 int line_pos;
128 114
129 lcd_clear_display(); 115 rb->lcd_clear_display();
130 116
131 line_pos = begin_line_pos; 117 line_pos = begin_line_pos;
132 118
@@ -137,11 +123,12 @@ static void viewer_draw(int col)
137 str = buffer + line_pos + 1; 123 str = buffer + line_pos + 1;
138 for (j=0; j<col && *str!=0; ++j) 124 for (j=0; j<col && *str!=0; ++j)
139 str++; 125 str++;
140 lcd_puts(0, i, str); 126 rb->lcd_puts(0, i, str);
141 line_pos = find_next_line(line_pos); 127 line_pos = find_next_line(line_pos);
142 } 128 }
143 129#ifdef HAVE_LCD_BITMAP
144 lcd_update(); 130 rb->lcd_update();
131#endif
145} 132}
146 133
147static void fill_buffer(int pos) 134static void fill_buffer(int pos)
@@ -154,8 +141,8 @@ static void fill_buffer(int pos)
154 if (pos<0) 141 if (pos<0)
155 pos = 0; 142 pos = 0;
156 143
157 lseek(fd, pos, SEEK_SET); 144 rb->lseek(fd, pos, SEEK_SET);
158 numread = read(fd, buffer, BUFFER_SIZE); 145 numread = rb->read(fd, buffer, BUFFER_SIZE);
159 146
160 begin_line_pos -= pos - buffer_pos; 147 begin_line_pos -= pos - buffer_pos;
161 end_line_pos -= pos - buffer_pos; 148 end_line_pos -= pos - buffer_pos;
@@ -181,11 +168,11 @@ static bool viewer_init(char* file)
181 int i; 168 int i;
182 int ret; 169 int ret;
183 170
184 fd = open(file, O_RDONLY); 171 fd = rb->open(file, O_RDONLY);
185 if (fd==-1) 172 if (fd==-1)
186 return false; 173 return false;
187 174
188 file_size = lseek(fd, 0, SEEK_END); 175 file_size = rb->lseek(fd, 0, SEEK_END);
189 176
190 buffer_pos = 0; 177 buffer_pos = 0;
191 begin_line = 0; 178 begin_line = 0;
@@ -207,7 +194,7 @@ static bool viewer_init(char* file)
207 194
208static void viewer_exit(void) 195static void viewer_exit(void)
209{ 196{
210 close(fd); 197 rb->close(fd);
211} 198}
212 199
213static void viewer_scroll_down(void) 200static void viewer_scroll_down(void)
@@ -264,7 +251,7 @@ static int pagescroll(int col)
264 int i; 251 int i;
265 252
266 while (!exit) { 253 while (!exit) {
267 switch (button_get(true)) { 254 switch (rb->button_get(true)) {
268#ifdef HAVE_RECORDER_KEYPAD 255#ifdef HAVE_RECORDER_KEYPAD
269 case BUTTON_ON | BUTTON_UP: 256 case BUTTON_ON | BUTTON_UP:
270 case BUTTON_ON | BUTTON_UP | BUTTON_REPEAT: 257 case BUTTON_ON | BUTTON_UP | BUTTON_REPEAT:
@@ -328,31 +315,30 @@ static int pagescroll(int col)
328 315
329 return col; 316 return col;
330} 317}
331bool viewer_run(char* file) 318
319enum plugin_status plugin_start(struct plugin_api* api, void* file)
332{ 320{
333 bool exit=false; 321 bool exit=false;
334 int button; 322 int button;
335 int col = 0; 323 int col = 0;
336 int ok; 324 int ok;
337 325
338#ifdef HAVE_LCD_BITMAP 326 TEST_PLUGIN_API(api);
339 /* no margins */ 327 rb = api;
340 lcd_setmargins(0, 0); 328
341#endif 329 if (!file)
330 return PLUGIN_ERROR;
342 331
343 ok = viewer_init(file); 332 ok = viewer_init(file);
344 if (!ok) { 333 if (!ok) {
345 lcd_clear_display(); 334 rb->splash(HZ, 0, false, "Error");
346 lcd_puts(0, 0, "Error");
347 lcd_update();
348 sleep(HZ);
349 viewer_exit(); 335 viewer_exit();
350 return false; 336 return PLUGIN_OK;
351 } 337 }
352 338
353 viewer_draw(col); 339 viewer_draw(col);
354 while (!exit) { 340 while (!exit) {
355 button = button_get(true); 341 button = rb->button_get(true);
356 342
357 switch ( button ) { 343 switch ( button ) {
358 344
@@ -420,13 +406,10 @@ bool viewer_run(char* file)
420 break; 406 break;
421 407
422 case SYS_USB_CONNECTED: 408 case SYS_USB_CONNECTED:
423 usb_screen(); 409 rb->usb_screen();
424#ifdef HAVE_LCD_CHARCELLS
425 status_set_param(false);
426#endif
427 viewer_exit(); 410 viewer_exit();
428 return true; 411 return PLUGIN_USB_CONNECTED;
429 } 412 }
430 } 413 }
431 return false; 414 return PLUGIN_OK;
432} 415}
diff --git a/apps/recorder/wormlet.c b/apps/plugins/wormlet.c
index 2937a1bb83..be089cdb7c 100644
--- a/apps/recorder/wormlet.c
+++ b/apps/plugins/wormlet.c
@@ -16,26 +16,9 @@
16 * KIND, either express or implied. 16 * KIND, either express or implied.
17 * 17 *
18 ****************************************************************************/ 18 ****************************************************************************/
19#include "plugin.h"
19 20
20#include "config.h" 21#ifdef HAVE_LCD_BITMAP
21#include "options.h"
22
23#ifdef USE_GAMES
24
25/* #define DEBUG_WORMLET */
26
27#include <sprintf.h>
28#include <stdlib.h>
29#include <string.h>
30#include "system.h"
31#include "lcd.h"
32#include "button.h"
33#include "kernel.h"
34#include "menu.h"
35#include "rtc.h"
36#include "lang.h"
37#include "screens.h"
38#include "font.h"
39 22
40/* size of the field the worm lives in */ 23/* size of the field the worm lives in */
41#define FIELD_RECT_X 1 24#define FIELD_RECT_X 1
@@ -149,6 +132,9 @@ static int player3_dir = EAST;
149 control a worm */ 132 control a worm */
150static int players = 1; 133static int players = 1;
151 134
135/* the rockbox plugin api */
136static struct plugin_api* rb;
137
152#ifdef DEBUG_WORMLET 138#ifdef DEBUG_WORMLET
153static void set_debug_out(char *str){ 139static void set_debug_out(char *str){
154 strcpy(debugout, str); 140 strcpy(debugout, str);
@@ -507,8 +493,8 @@ static int make_food(int index) {
507 do { 493 do {
508 /* make coordinates for a new food so that 494 /* make coordinates for a new food so that
509 the entire food lies within the FIELD */ 495 the entire food lies within the FIELD */
510 x = rand() % (FIELD_RECT_WIDTH - FOOD_SIZE); 496 x = rb->rand() % (FIELD_RECT_WIDTH - FOOD_SIZE);
511 y = rand() % (FIELD_RECT_HEIGHT - FOOD_SIZE); 497 y = rb->rand() % (FIELD_RECT_HEIGHT - FOOD_SIZE);
512 tries ++; 498 tries ++;
513 499
514 /* Ensure that the new food doesn't collide with any 500 /* Ensure that the new food doesn't collide with any
@@ -549,7 +535,7 @@ static int make_food(int index) {
549static void clear_food(int index) 535static void clear_food(int index)
550{ 536{
551 /* remove the old food from the screen */ 537 /* remove the old food from the screen */
552 lcd_clearrect(foodx[index] + FIELD_RECT_X, 538 rb->lcd_clearrect(foodx[index] + FIELD_RECT_X,
553 foody[index] + FIELD_RECT_Y, 539 foody[index] + FIELD_RECT_Y,
554 FOOD_SIZE, FOOD_SIZE); 540 FOOD_SIZE, FOOD_SIZE);
555} 541}
@@ -563,10 +549,10 @@ static void clear_food(int index)
563static void draw_food(int index) 549static void draw_food(int index)
564{ 550{
565 /* draw the food object */ 551 /* draw the food object */
566 lcd_fillrect(foodx[index] + FIELD_RECT_X, 552 rb->lcd_fillrect(foodx[index] + FIELD_RECT_X,
567 foody[index] + FIELD_RECT_Y, 553 foody[index] + FIELD_RECT_Y,
568 FOOD_SIZE, FOOD_SIZE); 554 FOOD_SIZE, FOOD_SIZE);
569 lcd_clearrect(foodx[index] + FIELD_RECT_X + 1, 555 rb->lcd_clearrect(foodx[index] + FIELD_RECT_X + 1,
570 foody[index] + FIELD_RECT_Y + 1, 556 foody[index] + FIELD_RECT_Y + 1,
571 FOOD_SIZE - 2, FOOD_SIZE - 2); 557 FOOD_SIZE - 2, FOOD_SIZE - 2);
572} 558}
@@ -588,8 +574,8 @@ static int make_argh(int index)
588 do { 574 do {
589 /* make coordinates for a new argh so that 575 /* make coordinates for a new argh so that
590 the entire food lies within the FIELD */ 576 the entire food lies within the FIELD */
591 x = rand() % (FIELD_RECT_WIDTH - ARGH_SIZE); 577 x = rb->rand() % (FIELD_RECT_WIDTH - ARGH_SIZE);
592 y = rand() % (FIELD_RECT_HEIGHT - ARGH_SIZE); 578 y = rb->rand() % (FIELD_RECT_HEIGHT - ARGH_SIZE);
593 tries ++; 579 tries ++;
594 580
595 /* Ensure that the new argh doesn't intersect with any 581 /* Ensure that the new argh doesn't intersect with any
@@ -631,7 +617,7 @@ static int make_argh(int index)
631static void draw_argh(int index) 617static void draw_argh(int index)
632{ 618{
633 /* draw the new argh */ 619 /* draw the new argh */
634 lcd_fillrect(arghx[index] + FIELD_RECT_X, 620 rb->lcd_fillrect(arghx[index] + FIELD_RECT_X,
635 arghy[index] + FIELD_RECT_Y, 621 arghy[index] + FIELD_RECT_Y,
636 ARGH_SIZE, ARGH_SIZE); 622 ARGH_SIZE, ARGH_SIZE);
637} 623}
@@ -744,7 +730,7 @@ static void init_wormlet(void)
744 } 730 }
745 731
746 /* Needed when the game is restarted using BUTTON_ON */ 732 /* Needed when the game is restarted using BUTTON_ON */
747 lcd_clear_display(); 733 rb->lcd_clear_display();
748 734
749 /* make and display some food and argh */ 735 /* make and display some food and argh */
750 argh_count = MAX_FOOD; 736 argh_count = MAX_FOOD;
@@ -756,11 +742,11 @@ static void init_wormlet(void)
756 } 742 }
757 743
758 /* draw the game field */ 744 /* draw the game field */
759 lcd_invertrect(0, 0, FIELD_RECT_WIDTH + 2, FIELD_RECT_HEIGHT + 2); 745 rb->lcd_invertrect(0, 0, FIELD_RECT_WIDTH + 2, FIELD_RECT_HEIGHT + 2);
760 lcd_invertrect(1, 1, FIELD_RECT_WIDTH, FIELD_RECT_HEIGHT); 746 rb->lcd_invertrect(1, 1, FIELD_RECT_WIDTH, FIELD_RECT_HEIGHT);
761 747
762 /* make everything visible */ 748 /* make everything visible */
763 lcd_update(); 749 rb->lcd_update();
764} 750}
765 751
766 752
@@ -852,14 +838,14 @@ static void draw_worm(struct worm *w)
852 int x = w->x[w->head]; 838 int x = w->x[w->head];
853 int y = w->y[w->head]; 839 int y = w->y[w->head];
854 if (x >= 0 && x < FIELD_RECT_WIDTH && y >= 0 && y < FIELD_RECT_HEIGHT) { 840 if (x >= 0 && x < FIELD_RECT_WIDTH && y >= 0 && y < FIELD_RECT_HEIGHT) {
855 lcd_drawpixel(x + FIELD_RECT_X, y + FIELD_RECT_Y); 841 rb->lcd_drawpixel(x + FIELD_RECT_X, y + FIELD_RECT_Y);
856 } 842 }
857 843
858 /* clear the space behind the worm */ 844 /* clear the space behind the worm */
859 x = w->x[w->tail] ; 845 x = w->x[w->tail] ;
860 y = w->y[w->tail] ; 846 y = w->y[w->tail] ;
861 if (x >= 0 && x < FIELD_RECT_WIDTH && y >= 0 && y < FIELD_RECT_HEIGHT) { 847 if (x >= 0 && x < FIELD_RECT_WIDTH && y >= 0 && y < FIELD_RECT_HEIGHT) {
862 lcd_clearpixel(x + FIELD_RECT_X, y + FIELD_RECT_Y); 848 rb->lcd_clearpixel(x + FIELD_RECT_X, y + FIELD_RECT_Y);
863 } 849 }
864} 850}
865 851
@@ -1166,10 +1152,10 @@ static void virtual_player(struct worm *w) {
1166static void score_board(void) 1152static void score_board(void)
1167{ 1153{
1168 char buf[15]; 1154 char buf[15];
1169 char buf2[15]; 1155 char* buf2 = NULL;
1170 int i; 1156 int i;
1171 int y = 0; 1157 int y = 0;
1172 lcd_clearrect(FIELD_RECT_WIDTH + 2, 0, LCD_WIDTH - FIELD_RECT_WIDTH - 2, LCD_HEIGHT); 1158 rb->lcd_clearrect(FIELD_RECT_WIDTH + 2, 0, LCD_WIDTH - FIELD_RECT_WIDTH - 2, LCD_HEIGHT);
1173 for (i = 0; i < worm_count; i++) { 1159 for (i = 0; i < worm_count; i++) {
1174 int score = get_score(&worms[i]); 1160 int score = get_score(&worms[i]);
1175 1161
@@ -1180,54 +1166,52 @@ static void score_board(void)
1180 } 1166 }
1181 } 1167 }
1182 1168
1183 /* length */ 1169 /* length */
1184 snprintf(buf, sizeof (buf),str(LANG_WORMLET_LENGTH), score); 1170 rb->snprintf(buf, sizeof (buf),"Len:%d", score);
1185 1171
1186 /* worm state */ 1172 /* worm state */
1187 switch (check_collision(&worms[i])) { 1173 switch (check_collision(&worms[i])) {
1188 case COLLISION_NONE: 1174 case COLLISION_NONE:
1189 if (worms[i].growing > 0){ 1175 if (worms[i].growing > 0)
1190 snprintf(buf2, sizeof(buf2), str(LANG_WORMLET_GROWING)); 1176 buf2 = "Growing";
1191 }
1192 else { 1177 else {
1193 if (worms[i].alive) { 1178 if (worms[i].alive)
1194 snprintf(buf2, sizeof(buf2), str(LANG_WORMLET_HUNGRY)); 1179 buf2 = "Hungry";
1195 } else { 1180 else
1196 snprintf(buf2, sizeof(buf2), str(LANG_WORMLET_WORMED)); 1181 buf2 = "Wormed";
1197 }
1198 } 1182 }
1199 break; 1183 break;
1200 1184
1201 case COLLISION_WORM: 1185 case COLLISION_WORM:
1202 snprintf(buf2, sizeof(buf2), str(LANG_WORMLET_WORMED)); 1186 buf2 = "Wormed";
1203 break; 1187 break;
1204 1188
1205 case COLLISION_FOOD: 1189 case COLLISION_FOOD:
1206 snprintf(buf2, sizeof(buf2), str(LANG_WORMLET_GROWING)); 1190 buf2 = "Growing";
1207 break; 1191 break;
1208 1192
1209 case COLLISION_ARGH: 1193 case COLLISION_ARGH:
1210 snprintf(buf2, sizeof(buf2), str(LANG_WORMLET_ARGH)); 1194 buf2 = "Argh";
1211 break; 1195 break;
1212 1196
1213 case COLLISION_FIELD: 1197 case COLLISION_FIELD:
1214 snprintf(buf2, sizeof(buf2), str(LANG_WORMLET_CRASHED)); 1198 buf2 = "Crashed";
1215 break; 1199 break;
1216 } 1200 }
1217 lcd_putsxy(FIELD_RECT_WIDTH + 3, y , buf); 1201 rb->lcd_putsxy(FIELD_RECT_WIDTH + 3, y , buf);
1218 lcd_putsxy(FIELD_RECT_WIDTH + 3, y+8, buf2); 1202 rb->lcd_putsxy(FIELD_RECT_WIDTH + 3, y+8, buf2);
1219 1203
1220 if (!worms[i].alive){ 1204 if (!worms[i].alive){
1221 lcd_invertrect(FIELD_RECT_WIDTH + 2, y, 1205 rb->lcd_invertrect(FIELD_RECT_WIDTH + 2, y,
1222 LCD_WIDTH - FIELD_RECT_WIDTH - 2, 17); 1206 LCD_WIDTH - FIELD_RECT_WIDTH - 2, 17);
1223 } 1207 }
1224 y += 19; 1208 y += 19;
1225 } 1209 }
1226 snprintf(buf , sizeof(buf), str(LANG_WORMLET_HIGHSCORE), highscore); 1210 rb->snprintf(buf , sizeof(buf), "Hs: %d", highscore);
1227#ifndef DEBUG_WORMLET 1211#ifndef DEBUG_WORMLET
1228 lcd_putsxy(FIELD_RECT_WIDTH + 3, LCD_HEIGHT - 8, buf); 1212 rb->lcd_putsxy(FIELD_RECT_WIDTH + 3, LCD_HEIGHT - 8, buf);
1229#else 1213#else
1230 lcd_putsxy(FIELD_RECT_WIDTH + 3, LCD_HEIGHT - 8, debugout); 1214 rb->lcd_putsxy(FIELD_RECT_WIDTH + 3, LCD_HEIGHT - 8, debugout);
1231#endif 1215#endif
1232} 1216}
1233 1217
@@ -1305,7 +1289,7 @@ static bool run(void)
1305 /* initialize the board and so on */ 1289 /* initialize the board and so on */
1306 init_wormlet(); 1290 init_wormlet();
1307 1291
1308 cycle_start = current_tick; 1292 cycle_start = *rb->current_tick;
1309 /* change the direction of the worm */ 1293 /* change the direction of the worm */
1310 while (button != BUTTON_OFF && ! wormDead) 1294 while (button != BUTTON_OFF && ! wormDead)
1311 { 1295 {
@@ -1358,7 +1342,7 @@ static bool run(void)
1358 1342
1359 case BUTTON_PLAY: 1343 case BUTTON_PLAY:
1360 do { 1344 do {
1361 button = button_get(true); 1345 button = rb->button_get(true);
1362 } while (button != BUTTON_PLAY && 1346 } while (button != BUTTON_PLAY &&
1363 button != BUTTON_OFF && 1347 button != BUTTON_OFF &&
1364 button != BUTTON_ON); 1348 button != BUTTON_ON);
@@ -1377,7 +1361,7 @@ static bool run(void)
1377 draw_worm(w); 1361 draw_worm(w);
1378 } 1362 }
1379 score_board(); 1363 score_board();
1380 lcd_update(); 1364 rb->lcd_update();
1381 if (button == BUTTON_ON) { 1365 if (button == BUTTON_ON) {
1382 wormDead = true; 1366 wormDead = true;
1383 } 1367 }
@@ -1385,7 +1369,7 @@ static bool run(void)
1385 /* here the wormlet game cycle ends 1369 /* here the wormlet game cycle ends
1386 thus the current tick is stored 1370 thus the current tick is stored
1387 as end time */ 1371 as end time */
1388 cycle_end = current_tick; 1372 cycle_end = *rb->current_tick;
1389 1373
1390 /* The duration of the game cycle */ 1374 /* The duration of the game cycle */
1391 cycle_duration = cycle_end - cycle_start; 1375 cycle_duration = cycle_end - cycle_start;
@@ -1403,15 +1387,14 @@ static bool run(void)
1403 max_cycle = cycle_duration; 1387 max_cycle = cycle_duration;
1404 ticks_to_max_cycle_reset = 20; 1388 ticks_to_max_cycle_reset = 20;
1405 } 1389 }
1406 snprintf(buf, sizeof buf, "ticks %d", max_cycle); 1390 rb->snprintf(buf, sizeof buf, "ticks %d", max_cycle);
1407 set_debug_out(buf); 1391 set_debug_out(buf);
1408#endif 1392#endif
1409 /* adjust the number of ticks to wait for a button. 1393 /* adjust the number of ticks to wait for a button.
1410 This ensures that a complete game cycle including 1394 This ensures that a complete game cycle including
1411 user input runs in constant time */ 1395 user input runs in constant time */
1412 button = button_get_w_tmo(SPEED - cycle_duration); 1396 button = rb->button_get_w_tmo(SPEED - cycle_duration);
1413 cycle_start = current_tick; 1397 cycle_start = *rb->current_tick;
1414
1415 } 1398 }
1416 return wormDead; 1399 return wormDead;
1417} 1400}
@@ -1425,7 +1408,7 @@ static bool run(void)
1425static void test_worm_food_collision(void) { 1408static void test_worm_food_collision(void) {
1426 int collision_count = 0; 1409 int collision_count = 0;
1427 int i; 1410 int i;
1428 lcd_clear_display(); 1411 rb->lcd_clear_display();
1429 init_worm(&worms[0], 10, 10); 1412 init_worm(&worms[0], 10, 10);
1430 add_growing(&worms[0], 10); 1413 add_growing(&worms[0], 10);
1431 set_worm_dir(&worms[0], EAST); 1414 set_worm_dir(&worms[0], EAST);
@@ -1451,12 +1434,12 @@ static void test_worm_food_collision(void) {
1451 if (collision) { 1434 if (collision) {
1452 collision_count++; 1435 collision_count++;
1453 } 1436 }
1454 snprintf(buf, sizeof buf, "collisions: %d", collision_count); 1437 rb->snprintf(buf, sizeof buf, "collisions: %d", collision_count);
1455 lcd_putsxy(0, LCD_HEIGHT -8, buf); 1438 rb->lcd_putsxy(0, LCD_HEIGHT -8, buf);
1456 lcd_update(); 1439 rb->lcd_update();
1457 } 1440 }
1458 if (collision_count != FOOD_SIZE) { 1441 if (collision_count != FOOD_SIZE) {
1459 button_get(true); 1442 rb->button_get(true);
1460 } 1443 }
1461 1444
1462 1445
@@ -1470,12 +1453,12 @@ static void test_worm_food_collision(void) {
1470 if (collision) { 1453 if (collision) {
1471 collision_count ++; 1454 collision_count ++;
1472 } 1455 }
1473 snprintf(buf, sizeof buf, "collisions: %d", collision_count); 1456 rb->snprintf(buf, sizeof buf, "collisions: %d", collision_count);
1474 lcd_putsxy(0, LCD_HEIGHT -8, buf); 1457 rb->lcd_putsxy(0, LCD_HEIGHT -8, buf);
1475 lcd_update(); 1458 rb->lcd_update();
1476 } 1459 }
1477 if (collision_count != FOOD_SIZE * 2) { 1460 if (collision_count != FOOD_SIZE * 2) {
1478 button_get(true); 1461 rb->button_get(true);
1479 } 1462 }
1480 1463
1481} 1464}
@@ -1498,7 +1481,7 @@ static void test_worm_argh_collision(void) {
1498 int i; 1481 int i;
1499 int dir; 1482 int dir;
1500 int collision_count = 0; 1483 int collision_count = 0;
1501 lcd_clear_display(); 1484 rb->lcd_clear_display();
1502 init_worm(&worms[0], 10, 10); 1485 init_worm(&worms[0], 10, 10);
1503 add_growing(&worms[0], 40); 1486 add_growing(&worms[0], 40);
1504 for (dir = 0; dir < 4; dir++) { 1487 for (dir = 0; dir < 4; dir++) {
@@ -1518,12 +1501,12 @@ static void test_worm_argh_collision(void) {
1518 if (collision) { 1501 if (collision) {
1519 collision_count ++; 1502 collision_count ++;
1520 } 1503 }
1521 snprintf(buf, sizeof buf, "collisions: %d", collision_count); 1504 rb->snprintf(buf, sizeof buf, "collisions: %d", collision_count);
1522 lcd_putsxy(0, LCD_HEIGHT -8, buf); 1505 rb->lcd_putsxy(0, LCD_HEIGHT -8, buf);
1523 lcd_update(); 1506 rb->lcd_update();
1524 } 1507 }
1525 if (collision_count != ARGH_SIZE * 2) { 1508 if (collision_count != ARGH_SIZE * 2) {
1526 button_get(true); 1509 rb->button_get(true);
1527 } 1510 }
1528 1511
1529 arghy[0] = 12; 1512 arghy[0] = 12;
@@ -1535,12 +1518,12 @@ static void test_worm_argh_collision(void) {
1535 if (collision) { 1518 if (collision) {
1536 collision_count ++; 1519 collision_count ++;
1537 } 1520 }
1538 snprintf(buf, sizeof buf, "collisions: %d", collision_count); 1521 rb->snprintf(buf, sizeof buf, "collisions: %d", collision_count);
1539 lcd_putsxy(0, LCD_HEIGHT -8, buf); 1522 rb->lcd_putsxy(0, LCD_HEIGHT -8, buf);
1540 lcd_update(); 1523 rb->lcd_update();
1541 } 1524 }
1542 if (collision_count != ARGH_SIZE * 4) { 1525 if (collision_count != ARGH_SIZE * 4) {
1543 button_get(true); 1526 rb->button_get(true);
1544 } 1527 }
1545} 1528}
1546 1529
@@ -1560,11 +1543,11 @@ static int testline_in_rect(void) {
1560 1543
1561 if (!line_in_rect(x1, y1, x2, y2, rx, ry, rw, rh) && 1544 if (!line_in_rect(x1, y1, x2, y2, rx, ry, rw, rh) &&
1562 !line_in_rect(x2, y2, x1, y1, rx, ry, rw, rh)) { 1545 !line_in_rect(x2, y2, x1, y1, rx, ry, rw, rh)) {
1563 lcd_drawrect(rx, ry, rw, rh); 1546 rb->lcd_drawrect(rx, ry, rw, rh);
1564 lcd_drawline(x1, y1, x2, y2); 1547 rb->lcd_drawline(x1, y1, x2, y2);
1565 lcd_update(); 1548 rb->lcd_update();
1566 lcd_putsxy(0, 0, "failed 1"); 1549 rb->lcd_putsxy(0, 0, "failed 1");
1567 button_get(true); 1550 rb->button_get(true);
1568 testfailed = 1; 1551 testfailed = 1;
1569 } 1552 }
1570 1553
@@ -1572,11 +1555,11 @@ static int testline_in_rect(void) {
1572 y2 = 20; 1555 y2 = 20;
1573 if (!line_in_rect(x1, y1, x2, y2, rx, ry, rw, rh) && 1556 if (!line_in_rect(x1, y1, x2, y2, rx, ry, rw, rh) &&
1574 !line_in_rect(x2, y2, x1, y1, rx, ry, rw, rh)) { 1557 !line_in_rect(x2, y2, x1, y1, rx, ry, rw, rh)) {
1575 lcd_drawrect(rx, ry, rw, rh); 1558 rb->lcd_drawrect(rx, ry, rw, rh);
1576 lcd_drawline(x1, y1, x2, y2); 1559 rb->lcd_drawline(x1, y1, x2, y2);
1577 lcd_putsxy(0, 0, "failed 2"); 1560 rb->lcd_putsxy(0, 0, "failed 2");
1578 lcd_update(); 1561 rb->lcd_update();
1579 button_get(true); 1562 rb->button_get(true);
1580 testfailed = 2; 1563 testfailed = 2;
1581 } 1564 }
1582 1565
@@ -1584,11 +1567,11 @@ static int testline_in_rect(void) {
1584 y1 = 30; 1567 y1 = 30;
1585 if (!line_in_rect(x1, y1, x2, y2, rx, ry, rw, rh) && 1568 if (!line_in_rect(x1, y1, x2, y2, rx, ry, rw, rh) &&
1586 !line_in_rect(x2, y2, x1, y1, rx, ry, rw, rh)) { 1569 !line_in_rect(x2, y2, x1, y1, rx, ry, rw, rh)) {
1587 lcd_drawrect(rx, ry, rw, rh); 1570 rb->lcd_drawrect(rx, ry, rw, rh);
1588 lcd_drawline(x1, y1, x2, y2); 1571 rb->lcd_drawline(x1, y1, x2, y2);
1589 lcd_putsxy(0, 0, "failed 3"); 1572 rb->lcd_putsxy(0, 0, "failed 3");
1590 lcd_update(); 1573 rb->lcd_update();
1591 button_get(true); 1574 rb->button_get(true);
1592 testfailed = 3; 1575 testfailed = 3;
1593 } 1576 }
1594 1577
@@ -1596,11 +1579,11 @@ static int testline_in_rect(void) {
1596 y2 = 45; 1579 y2 = 45;
1597 if (!line_in_rect(x1, y1, x2, y2, rx, ry, rw, rh) && 1580 if (!line_in_rect(x1, y1, x2, y2, rx, ry, rw, rh) &&
1598 !line_in_rect(x2, y2, x1, y1, rx, ry, rw, rh)) { 1581 !line_in_rect(x2, y2, x1, y1, rx, ry, rw, rh)) {
1599 lcd_drawrect(rx, ry, rw, rh); 1582 rb->lcd_drawrect(rx, ry, rw, rh);
1600 lcd_drawline(x1, y1, x2, y2); 1583 rb->lcd_drawline(x1, y1, x2, y2);
1601 lcd_putsxy(0, 0, "failed 4"); 1584 rb->lcd_putsxy(0, 0, "failed 4");
1602 lcd_update(); 1585 rb->lcd_update();
1603 button_get(true); 1586 rb->button_get(true);
1604 testfailed = 4; 1587 testfailed = 4;
1605 } 1588 }
1606 1589
@@ -1608,11 +1591,11 @@ static int testline_in_rect(void) {
1608 y1 = 50; 1591 y1 = 50;
1609 if (line_in_rect(x1, y1, x2, y2, rx, ry, rw, rh) || 1592 if (line_in_rect(x1, y1, x2, y2, rx, ry, rw, rh) ||
1610 line_in_rect(x2, y2, x1, y1, rx, ry, rw, rh)) { 1593 line_in_rect(x2, y2, x1, y1, rx, ry, rw, rh)) {
1611 lcd_drawrect(rx, ry, rw, rh); 1594 rb->lcd_drawrect(rx, ry, rw, rh);
1612 lcd_drawline(x1, y1, x2, y2); 1595 rb->lcd_drawline(x1, y1, x2, y2);
1613 lcd_putsxy(0, 0, "failed 5"); 1596 rb->lcd_putsxy(0, 0, "failed 5");
1614 lcd_update(); 1597 rb->lcd_update();
1615 button_get(true); 1598 rb->button_get(true);
1616 testfailed = 5; 1599 testfailed = 5;
1617 } 1600 }
1618 1601
@@ -1621,11 +1604,11 @@ static int testline_in_rect(void) {
1621 y2 = 7; 1604 y2 = 7;
1622 if (line_in_rect(x1, y1, x2, y2, rx, ry, rw, rh) || 1605 if (line_in_rect(x1, y1, x2, y2, rx, ry, rw, rh) ||
1623 line_in_rect(x2, y2, x1, y1, rx, ry, rw, rh)) { 1606 line_in_rect(x2, y2, x1, y1, rx, ry, rw, rh)) {
1624 lcd_drawrect(rx, ry, rw, rh); 1607 rb->lcd_drawrect(rx, ry, rw, rh);
1625 lcd_drawline(x1, y1, x2, y2); 1608 rb->lcd_drawline(x1, y1, x2, y2);
1626 lcd_putsxy(0, 0, "failed 6"); 1609 rb->lcd_putsxy(0, 0, "failed 6");
1627 lcd_update(); 1610 rb->lcd_update();
1628 button_get(true); 1611 rb->button_get(true);
1629 testfailed = 6; 1612 testfailed = 6;
1630 } 1613 }
1631 1614
@@ -1636,11 +1619,11 @@ static int testline_in_rect(void) {
1636 y2 = 20; 1619 y2 = 20;
1637 if (!line_in_rect(x1, y1, x2, y2, rx, ry, rw, rh) && 1620 if (!line_in_rect(x1, y1, x2, y2, rx, ry, rw, rh) &&
1638 !line_in_rect(x2, y2, x1, y1, rx, ry, rw, rh)) { 1621 !line_in_rect(x2, y2, x1, y1, rx, ry, rw, rh)) {
1639 lcd_drawrect(rx, ry, rw, rh); 1622 rb->lcd_drawrect(rx, ry, rw, rh);
1640 lcd_drawline(x1, y1, x2, y2); 1623 rb->lcd_drawline(x1, y1, x2, y2);
1641 lcd_putsxy(0, 0, "failed 7"); 1624 rb->lcd_putsxy(0, 0, "failed 7");
1642 lcd_update(); 1625 rb->lcd_update();
1643 button_get(true); 1626 rb->button_get(true);
1644 testfailed = 7; 1627 testfailed = 7;
1645 } 1628 }
1646 1629
@@ -1648,11 +1631,11 @@ static int testline_in_rect(void) {
1648 x2 = 12; 1631 x2 = 12;
1649 if (!line_in_rect(x1, y1, x2, y2, rx, ry, rw, rh) && 1632 if (!line_in_rect(x1, y1, x2, y2, rx, ry, rw, rh) &&
1650 !line_in_rect(x2, y2, x1, y1, rx, ry, rw, rh)) { 1633 !line_in_rect(x2, y2, x1, y1, rx, ry, rw, rh)) {
1651 lcd_drawrect(rx, ry, rw, rh); 1634 rb->lcd_drawrect(rx, ry, rw, rh);
1652 lcd_drawline(x1, y1, x2, y2); 1635 rb->lcd_drawline(x1, y1, x2, y2);
1653 lcd_putsxy(0, 0, "failed 8"); 1636 rb->lcd_putsxy(0, 0, "failed 8");
1654 lcd_update(); 1637 rb->lcd_update();
1655 button_get(true); 1638 rb->button_get(true);
1656 testfailed = 8; 1639 testfailed = 8;
1657 } 1640 }
1658 1641
@@ -1660,11 +1643,11 @@ static int testline_in_rect(void) {
1660 x1 = 25; 1643 x1 = 25;
1661 if (!line_in_rect(x1, y1, x2, y2, rx, ry, rw, rh) && 1644 if (!line_in_rect(x1, y1, x2, y2, rx, ry, rw, rh) &&
1662 !line_in_rect(x2, y2, x1, y1, rx, ry, rw, rh)) { 1645 !line_in_rect(x2, y2, x1, y1, rx, ry, rw, rh)) {
1663 lcd_drawrect(rx, ry, rw, rh); 1646 rb->lcd_drawrect(rx, ry, rw, rh);
1664 lcd_drawline(x1, y1, x2, y2); 1647 rb->lcd_drawline(x1, y1, x2, y2);
1665 lcd_putsxy(0, 0, "failed 9"); 1648 rb->lcd_putsxy(0, 0, "failed 9");
1666 lcd_update(); 1649 rb->lcd_update();
1667 button_get(true); 1650 rb->button_get(true);
1668 testfailed = 9; 1651 testfailed = 9;
1669 } 1652 }
1670 1653
@@ -1672,11 +1655,11 @@ static int testline_in_rect(void) {
1672 x2 = 37; 1655 x2 = 37;
1673 if (!line_in_rect(x1, y1, x2, y2, rx, ry, rw, rh) && 1656 if (!line_in_rect(x1, y1, x2, y2, rx, ry, rw, rh) &&
1674 !line_in_rect(x2, y2, x1, y1, rx, ry, rw, rh)) { 1657 !line_in_rect(x2, y2, x1, y1, rx, ry, rw, rh)) {
1675 lcd_drawrect(rx, ry, rw, rh); 1658 rb->lcd_drawrect(rx, ry, rw, rh);
1676 lcd_drawline(x1, y1, x2, y2); 1659 rb->lcd_drawline(x1, y1, x2, y2);
1677 lcd_putsxy(0, 0, "failed 10"); 1660 rb->lcd_putsxy(0, 0, "failed 10");
1678 lcd_update(); 1661 rb->lcd_update();
1679 button_get(true); 1662 rb->button_get(true);
1680 testfailed = 10; 1663 testfailed = 10;
1681 } 1664 }
1682 1665
@@ -1684,11 +1667,11 @@ static int testline_in_rect(void) {
1684 x1 = 42; 1667 x1 = 42;
1685 if (line_in_rect(x1, y1, x2, y2, rx, ry, rw, rh) || 1668 if (line_in_rect(x1, y1, x2, y2, rx, ry, rw, rh) ||
1686 line_in_rect(x2, y2, x1, y1, rx, ry, rw, rh)) { 1669 line_in_rect(x2, y2, x1, y1, rx, ry, rw, rh)) {
1687 lcd_drawrect(rx, ry, rw, rh); 1670 rb->lcd_drawrect(rx, ry, rw, rh);
1688 lcd_drawline(x1, y1, x2, y2); 1671 rb->lcd_drawline(x1, y1, x2, y2);
1689 lcd_putsxy(0, 0, "failed 11"); 1672 rb->lcd_putsxy(0, 0, "failed 11");
1690 lcd_update(); 1673 rb->lcd_update();
1691 button_get(true); 1674 rb->button_get(true);
1692 testfailed = 11; 1675 testfailed = 11;
1693 } 1676 }
1694 1677
@@ -1697,11 +1680,11 @@ static int testline_in_rect(void) {
1697 x2 = 7; 1680 x2 = 7;
1698 if (line_in_rect(x1, y1, x2, y2, rx, ry, rw, rh) || 1681 if (line_in_rect(x1, y1, x2, y2, rx, ry, rw, rh) ||
1699 line_in_rect(x2, y2, x1, y1, rx, ry, rw, rh)) { 1682 line_in_rect(x2, y2, x1, y1, rx, ry, rw, rh)) {
1700 lcd_drawrect(rx, ry, rw, rh); 1683 rb->lcd_drawrect(rx, ry, rw, rh);
1701 lcd_drawline(x1, y1, x2, y2); 1684 rb->lcd_drawline(x1, y1, x2, y2);
1702 lcd_putsxy(0, 0, "failed 12"); 1685 rb->lcd_putsxy(0, 0, "failed 12");
1703 lcd_update(); 1686 rb->lcd_update();
1704 button_get(true); 1687 rb->button_get(true);
1705 testfailed = 12; 1688 testfailed = 12;
1706 } 1689 }
1707 1690
@@ -1717,11 +1700,11 @@ static int testline_in_rect(void) {
1717 y2 = 20; 1700 y2 = 20;
1718 if (!(line_in_rect(x1, y1, x2, y2, rx, ry, rw, rh) && 1701 if (!(line_in_rect(x1, y1, x2, y2, rx, ry, rw, rh) &&
1719 line_in_rect(x2, y2, x1, y1, rx, ry, rw, rh))) { 1702 line_in_rect(x2, y2, x1, y1, rx, ry, rw, rh))) {
1720 lcd_drawrect(rx, ry, rw, rh); 1703 rb->lcd_drawrect(rx, ry, rw, rh);
1721 lcd_drawline(x1, y1, x2, y2); 1704 rb->lcd_drawline(x1, y1, x2, y2);
1722 lcd_putsxy(0, 0, "failed 13"); 1705 rb->lcd_putsxy(0, 0, "failed 13");
1723 lcd_update(); 1706 rb->lcd_update();
1724 button_get(true); 1707 rb->button_get(true);
1725 testfailed = 13; 1708 testfailed = 13;
1726 } 1709 }
1727 1710
@@ -1737,15 +1720,15 @@ static int testline_in_rect(void) {
1737 y2 = 19; 1720 y2 = 19;
1738 if (!(line_in_rect(x1, y1, x2, y2, rx, ry, rw, rh) && 1721 if (!(line_in_rect(x1, y1, x2, y2, rx, ry, rw, rh) &&
1739 line_in_rect(x2, y2, x1, y1, rx, ry, rw, rh))) { 1722 line_in_rect(x2, y2, x1, y1, rx, ry, rw, rh))) {
1740 lcd_drawline(x1, y1, x2, y2); 1723 rb->lcd_drawline(x1, y1, x2, y2);
1741 lcd_invertrect(rx, ry, rw, rh); 1724 rb->lcd_invertrect(rx, ry, rw, rh);
1742 lcd_putsxy(0, 0, "failed 14"); 1725 rb->lcd_putsxy(0, 0, "failed 14");
1743 lcd_update(); 1726 rb->lcd_update();
1744 button_get(true); 1727 rb->button_get(true);
1745 testfailed = 14; 1728 testfailed = 14;
1746 } 1729 }
1747 1730
1748 lcd_clear_display(); 1731 rb->lcd_clear_display();
1749 1732
1750 return testfailed; 1733 return testfailed;
1751} 1734}
@@ -1759,7 +1742,7 @@ static int test_specific_worm_collision(void) {
1759 int x = 0; 1742 int x = 0;
1760 int y = 0; 1743 int y = 0;
1761 char buf[20]; 1744 char buf[20];
1762 lcd_clear_display(); 1745 rb->lcd_clear_display();
1763 init_worm(&worms[0], 10, 20); 1746 init_worm(&worms[0], 10, 20);
1764 add_growing(&worms[0], 20 - INITIAL_WORM_LENGTH); 1747 add_growing(&worms[0], 20 - INITIAL_WORM_LENGTH);
1765 1748
@@ -1779,14 +1762,14 @@ static int test_specific_worm_collision(void) {
1779 if (specific_worm_collision(&worms[0], x, y) != -1) { 1762 if (specific_worm_collision(&worms[0], x, y) != -1) {
1780 collisions ++; 1763 collisions ++;
1781 } 1764 }
1782 lcd_invertpixel(x + FIELD_RECT_X, y + FIELD_RECT_Y); 1765 rb->lcd_invertpixel(x + FIELD_RECT_X, y + FIELD_RECT_Y);
1783 snprintf(buf, sizeof buf, "collisions %d", collisions); 1766 rb->snprintf(buf, sizeof buf, "collisions %d", collisions);
1784 lcd_putsxy(0, LCD_HEIGHT - 8, buf); 1767 rb->lcd_putsxy(0, LCD_HEIGHT - 8, buf);
1785 lcd_update(); 1768 rb->lcd_update();
1786 } 1769 }
1787 } 1770 }
1788 if (collisions != 21) { 1771 if (collisions != 21) {
1789 button_get(true); 1772 rb->button_get(true);
1790 } 1773 }
1791 return collisions; 1774 return collisions;
1792} 1775}
@@ -1798,7 +1781,7 @@ static void test_make_argh(void){
1798 int failures = 0; 1781 int failures = 0;
1799 int last_failures = 0; 1782 int last_failures = 0;
1800 int i, worm_idx; 1783 int i, worm_idx;
1801 lcd_clear_display(); 1784 rb->lcd_clear_display();
1802 worm_count = 3; 1785 worm_count = 3;
1803 1786
1804 for (worm_idx = 0; worm_idx < worm_count; worm_idx++) { 1787 for (worm_idx = 0; worm_idx < worm_count; worm_idx++) {
@@ -1818,37 +1801,37 @@ static void test_make_argh(void){
1818 } 1801 }
1819 } 1802 }
1820 1803
1821 lcd_update(); 1804 rb->lcd_update();
1822 1805
1823 for (seed = 0; hit < 20; seed += 2) { 1806 for (seed = 0; hit < 20; seed += 2) {
1824 char buf[20]; 1807 char buf[20];
1825 int x, y; 1808 int x, y;
1826 srand(seed); 1809 rb->srand(seed);
1827 x = rand() % (FIELD_RECT_WIDTH - ARGH_SIZE); 1810 x = rb->rand() % (FIELD_RECT_WIDTH - ARGH_SIZE);
1828 y = rand() % (FIELD_RECT_HEIGHT - ARGH_SIZE); 1811 y = rb->rand() % (FIELD_RECT_HEIGHT - ARGH_SIZE);
1829 1812
1830 for (worm_idx = 0; worm_idx < worm_count; worm_idx++){ 1813 for (worm_idx = 0; worm_idx < worm_count; worm_idx++){
1831 if (expensive_worm_in_rect(&worms[worm_idx], x, y, ARGH_SIZE, ARGH_SIZE)) { 1814 if (expensive_worm_in_rect(&worms[worm_idx], x, y, ARGH_SIZE, ARGH_SIZE)) {
1832 int tries = 0; 1815 int tries = 0;
1833 srand(seed); 1816 rb->srand(seed);
1834 1817
1835 tries = make_argh(0); 1818 tries = make_argh(0);
1836 if ((x == arghx[0] && y == arghy[0]) || tries < 2) { 1819 if ((x == arghx[0] && y == arghy[0]) || tries < 2) {
1837 failures ++; 1820 failures ++;
1838 } 1821 }
1839 1822
1840 snprintf(buf, sizeof buf, "(%d;%d) fail%d try%d", x, y, failures, tries); 1823 rb->snprintf(buf, sizeof buf, "(%d;%d) fail%d try%d", x, y, failures, tries);
1841 lcd_putsxy(0, LCD_HEIGHT - 8, buf); 1824 rb->lcd_putsxy(0, LCD_HEIGHT - 8, buf);
1842 lcd_update(); 1825 rb->lcd_update();
1843 lcd_invertrect(x + FIELD_RECT_X, y+ FIELD_RECT_Y, ARGH_SIZE, ARGH_SIZE); 1826 rb->lcd_invertrect(x + FIELD_RECT_X, y+ FIELD_RECT_Y, ARGH_SIZE, ARGH_SIZE);
1844 lcd_update(); 1827 rb->lcd_update();
1845 draw_argh(0); 1828 draw_argh(0);
1846 lcd_update(); 1829 rb->lcd_update();
1847 lcd_invertrect(x + FIELD_RECT_X, y + FIELD_RECT_Y, ARGH_SIZE, ARGH_SIZE); 1830 rb->lcd_invertrect(x + FIELD_RECT_X, y + FIELD_RECT_Y, ARGH_SIZE, ARGH_SIZE);
1848 lcd_clearrect(arghx[0] + FIELD_RECT_X, arghy[0] + FIELD_RECT_Y, ARGH_SIZE, ARGH_SIZE); 1831 rb->lcd_clearrect(arghx[0] + FIELD_RECT_X, arghy[0] + FIELD_RECT_Y, ARGH_SIZE, ARGH_SIZE);
1849 1832
1850 if (failures > last_failures) { 1833 if (failures > last_failures) {
1851 button_get(true); 1834 rb->button_get(true);
1852 } 1835 }
1853 last_failures = failures; 1836 last_failures = failures;
1854 hit ++; 1837 hit ++;
@@ -1860,7 +1843,7 @@ static void test_make_argh(void){
1860static void test_worm_argh_collision_in_moves(void) { 1843static void test_worm_argh_collision_in_moves(void) {
1861 int hit_count = 0; 1844 int hit_count = 0;
1862 int i; 1845 int i;
1863 lcd_clear_display(); 1846 rb->lcd_clear_display();
1864 init_worm(&worms[0], 10, 20); 1847 init_worm(&worms[0], 10, 20);
1865 1848
1866 arghx[0] = 20; 1849 arghx[0] = 20;
@@ -1875,12 +1858,12 @@ static void test_worm_argh_collision_in_moves(void) {
1875 if (worm_argh_collision_in_moves(&worms[0], 0, 5)){ 1858 if (worm_argh_collision_in_moves(&worms[0], 0, 5)){
1876 hit_count ++; 1859 hit_count ++;
1877 } 1860 }
1878 snprintf(buf, sizeof buf, "in 5 moves hits: %d", hit_count); 1861 rb->snprintf(buf, sizeof buf, "in 5 moves hits: %d", hit_count);
1879 lcd_putsxy(0, LCD_HEIGHT - 8, buf); 1862 rb->lcd_putsxy(0, LCD_HEIGHT - 8, buf);
1880 lcd_update(); 1863 rb->lcd_update();
1881 } 1864 }
1882 if (hit_count != ARGH_SIZE + 5) { 1865 if (hit_count != ARGH_SIZE + 5) {
1883 button_get(true); 1866 rb->button_get(true);
1884 } 1867 }
1885} 1868}
1886#endif /* DEBUG_WORMLET */ 1869#endif /* DEBUG_WORMLET */
@@ -1888,14 +1871,18 @@ static void test_worm_argh_collision_in_moves(void) {
1888extern bool use_old_rect; 1871extern bool use_old_rect;
1889 1872
1890/** 1873/**
1891 * Main entry point from the menu to start the game control. 1874 * Main entry point
1892 */ 1875 */
1893bool wormlet(void) 1876enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
1894{ 1877{
1895 bool worm_dead = false; 1878 bool worm_dead = false;
1896 int button; 1879 int button;
1897 1880
1898 lcd_setfont(FONT_SYSFIXED); 1881 TEST_PLUGIN_API(api);
1882 (void)(parameter);
1883
1884 rb = api;
1885 rb->lcd_setfont(FONT_SYSFIXED);
1899 1886
1900#ifdef DEBUG_WORMLET 1887#ifdef DEBUG_WORMLET
1901 testline_in_rect(); 1888 testline_in_rect();
@@ -1905,44 +1892,44 @@ bool wormlet(void)
1905 test_worm_argh_collision(); 1892 test_worm_argh_collision();
1906 test_specific_worm_collision(); 1893 test_specific_worm_collision();
1907#endif 1894#endif
1908 lcd_setmargins(0,0);
1909 1895
1910 /* Setup screen */ 1896 /* Setup screen */
1911 do { 1897 do {
1912 char buf[20]; 1898 char buf[20];
1913 lcd_clear_display(); 1899 char* ptr;
1900 rb->lcd_clear_display();
1914 1901
1915 /* first line players */ 1902 /* first line players */
1916 snprintf(buf, sizeof buf, str(LANG_WORMLET_PLAYERS), players); 1903 rb->snprintf(buf, sizeof buf, "%d Players UP/DN", players);
1917 lcd_puts(0, 0, buf); 1904 rb->lcd_puts(0, 0, buf);
1918 1905
1919 /* second line worms */ 1906 /* second line worms */
1920 snprintf(buf, sizeof buf, str(LANG_WORMLET_WORMS), worm_count); 1907 rb->snprintf(buf, sizeof buf, "%d Worms L/R", worm_count);
1921 lcd_puts(0, 1, buf); 1908 rb->lcd_puts(0, 1, buf);
1922 1909
1923 /* third line control */ 1910 /* third line control */
1924 if (players > 1) { 1911 if (players > 1) {
1925 if (use_remote) { 1912 if (use_remote) {
1926 snprintf(buf, sizeof buf, str(LANG_WORMLET_REMOTE_CTRL)); 1913 ptr = "Remote Control F1";
1927 } else { 1914 } else {
1928 snprintf(buf, sizeof buf, str(LANG_WORMLET_NO_REM_CTRL)); 1915 ptr = "No Rem. Control F1";
1929 } 1916 }
1930 } else { 1917 } else {
1931 if (players > 0) { 1918 if (players > 0) {
1932 if (use_remote) { 1919 if (use_remote) {
1933 snprintf(buf, sizeof buf, str(LANG_WORMLET_2_KEY_CTRL)); 1920 ptr = "2 Key Control F1";
1934 } else { 1921 } else {
1935 snprintf(buf, sizeof buf, str(LANG_WORMLET_4_KEY_CTRL)); 1922 ptr = "4 Key Control F1";
1936 } 1923 }
1937 } else { 1924 } else {
1938 snprintf(buf, sizeof buf, str(LANG_WORMLET_NO_CONTROL)); 1925 ptr = "Out Of Control";
1939 } 1926 }
1940 } 1927 }
1941 lcd_puts(0, 2, buf); 1928 rb->lcd_puts(0, 2, ptr);
1942 lcd_update(); 1929 rb->lcd_update();
1943 1930
1944 /* user selection */ 1931 /* user selection */
1945 button = button_get(true); 1932 button = rb->button_get(true);
1946 switch (button) { 1933 switch (button) {
1947 case BUTTON_UP: 1934 case BUTTON_UP:
1948 if (players < 3) { 1935 if (players < 3) {
@@ -1981,14 +1968,13 @@ bool wormlet(void)
1981 break; 1968 break;
1982 1969
1983 case SYS_USB_CONNECTED: 1970 case SYS_USB_CONNECTED:
1984 usb_screen(); 1971 rb->usb_screen();
1985 lcd_setfont(FONT_UI); 1972 return PLUGIN_USB_CONNECTED;
1986 return true;
1987 } 1973 }
1988 } while (button != BUTTON_PLAY && 1974 } while (button != BUTTON_PLAY &&
1989 button != BUTTON_OFF && button != BUTTON_ON); 1975 button != BUTTON_OFF && button != BUTTON_ON);
1990 1976
1991 lcd_clear_display(); 1977 rb->lcd_clear_display();
1992 /* end of setup */ 1978 /* end of setup */
1993 1979
1994 do { 1980 do {
@@ -2008,7 +1994,7 @@ bool wormlet(void)
2008 via BUTTON_OFF -> no need to wait for buttons. */ 1994 via BUTTON_OFF -> no need to wait for buttons. */
2009 if (worm_dead) { 1995 if (worm_dead) {
2010 do { 1996 do {
2011 button = button_get(true); 1997 button = rb->button_get(true);
2012 } 1998 }
2013 /* BUTTON_ON -> start new game */ 1999 /* BUTTON_ON -> start new game */
2014 /* BUTTON_OFF -> back to game menu */ 2000 /* BUTTON_OFF -> back to game menu */
@@ -2017,20 +2003,7 @@ bool wormlet(void)
2017 } 2003 }
2018 while (button != BUTTON_OFF); 2004 while (button != BUTTON_OFF);
2019 2005
2020 lcd_setfont(FONT_UI); 2006 return PLUGIN_OK;
2021
2022 return false;
2023} 2007}
2024 2008
2025 2009#endif
2026#endif /* USE_GAMES */
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
diff --git a/apps/recorder/icons.c b/apps/recorder/icons.c
index af0352094f..25d34d7591 100644
--- a/apps/recorder/icons.c
+++ b/apps/recorder/icons.c
@@ -64,6 +64,7 @@ unsigned char bitmap_icons_6x8[LastIcon][6] =
64 { 0x3e, 0x2a, 0x3e, 0x2a, 0x2a, 0x3e }, /* Language file */ 64 { 0x3e, 0x2a, 0x3e, 0x2a, 0x2a, 0x3e }, /* Language file */
65 { 0x55, 0x55, 0x55, 0x55, 0x55, 0x55 }, /* Text file */ 65 { 0x55, 0x55, 0x55, 0x55, 0x55, 0x55 }, /* Text file */
66 { 0x4e, 0x51, 0x51, 0x40, 0x55, 0x55 }, /* Config file */ 66 { 0x4e, 0x51, 0x51, 0x40, 0x55, 0x55 }, /* Config file */
67 { 0x0a, 0x0a, 0x5f, 0x4e, 0x24, 0x18 }, /* Plugin file */
67}; 68};
68 69
69unsigned char bitmap_icons_7x8[][7] = 70unsigned char bitmap_icons_7x8[][7] =
diff --git a/apps/recorder/icons.h b/apps/recorder/icons.h
index a7858cd0ae..40418468f3 100644
--- a/apps/recorder/icons.h
+++ b/apps/recorder/icons.h
@@ -29,6 +29,7 @@ enum icons_6x8 {
29 Folder, Directory, Playlist, Repeat, 29 Folder, Directory, Playlist, Repeat,
30 Selected, Cursor, Wps, Mod_Ajz, 30 Selected, Cursor, Wps, Mod_Ajz,
31 Font, Language, Text, Config, 31 Font, Language, Text, Config,
32 Plugin,
32 LastIcon 33 LastIcon
33}; 34};
34 35
diff --git a/apps/recorder/sokoban.c b/apps/recorder/sokoban.c
deleted file mode 100644
index d28e32f430..0000000000
--- a/apps/recorder/sokoban.c
+++ /dev/null
@@ -1,891 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2002 Eric Linenberg
11 * February 2003: Robert Hak performs a cleanup/rewrite/feature addition.
12 * Eric smiles. Bjorn cries. Linus say 'huh?'.
13 *
14 * All files in this archive are subject to the GNU General Public License.
15 * See the file COPYING in the source tree root for full license agreement.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#include "config.h"
23#include "options.h"
24
25#ifdef USE_GAMES
26
27#include <sprintf.h>
28#include "ctype.h"
29#include "sokoban.h"
30#include "lcd.h"
31#include "button.h"
32#include "kernel.h"
33#include "menu.h"
34#include "screens.h"
35#include "font.h"
36#include "file.h"
37#include "misc.h"
38#include "debug.h"
39
40#ifdef SIMULATOR
41#include <stdio.h>
42#endif
43#include <string.h>
44#include "lang.h"
45#include "sprintf.h"
46
47#define SOKOBAN_TITLE "Sokoban"
48#define SOKOBAN_TITLE_FONT 2
49
50#define LEVELS_FILE "/.rockbox/sokoban/levels.txt"
51
52#define ROWS 16
53#define COLS 20
54#define MAX_UNDOS 5
55
56#define SOKOBAN_LEVEL_SIZE (ROWS*COLS)
57
58static void init_undo(void);
59static void undo(void);
60static void add_undo(int button);
61
62static int get_level(char *level, int level_size);
63static int get_level_count(void);
64static int load_level(void);
65static void draw_level(void);
66
67static void init_boards(void);
68static void update_screen(void);
69static bool sokoban_loop(void);
70
71/* The Location, Undo and LevelInfo structs are OO-flavored.
72 * (oooh!-flavored as Schnueff puts it.) It makes more you have to know,
73 * but the overall data layout becomes more manageable. */
74
75/* We use the same three values in 2 structs. Makeing them a struct
76 * hopefully ensures that if you change things in one, the other changes
77 * as well. */
78struct LevelInfo {
79 short level;
80 short moves;
81 short boxes_to_go;
82};
83
84/* What a given location on the board looks like at a given time */
85struct Location {
86 char spot;
87 short row;
88 short col;
89};
90
91/* A single level of undo. Each undo move can affect upto,
92 * but not more then, 3 spots on the board */
93struct Undo {
94 struct LevelInfo level;
95 struct Location location[3];
96};
97
98/* Our full undo history */
99static struct UndoInfo {
100 short count; /* How many undos are there in history */
101 short current; /* Which history is the current undo */
102 struct Undo history[MAX_UNDOS];
103} undo_info;
104
105/* Our playing board */
106static struct BoardInfo {
107 char board[ROWS][COLS];
108 struct LevelInfo level;
109 struct Location player;
110 int max_level; /* How many levels do we have? */
111 int level_offset; /* Where in the level file is this level */
112 int loaded_level; /* Which level is in memory */
113} current_info;
114
115
116static void init_undo(void)
117{
118 undo_info.count = 0;
119 undo_info.current = 0;
120}
121
122static void undo(void)
123{
124 struct Undo *undo;
125 int i = 0;
126 short row, col;
127
128 if (undo_info.count == 0)
129 return;
130
131 /* Update board info */
132 undo = &undo_info.history[undo_info.current];
133
134 current_info.level = undo->level;
135 current_info.player = undo->location[0];
136
137 row = undo->location[0].row;
138 col = undo->location[0].col;
139 current_info.board[row][col] = '@';
140
141 /* Update the two other possible spots */
142 for (i = 1; i < 3; i++) {
143 if (undo->location[i].spot != '\0') {
144 row = undo->location[i].row;
145 col = undo->location[i].col;
146 current_info.board[row][col] = undo->location[i].spot;
147 undo->location[i].spot = '\0';
148 }
149 }
150
151 /* Remove this undo from the list */
152 if (undo_info.current == 0) {
153 if (undo_info.count > 1)
154 undo_info.current = MAX_UNDOS - 1;
155 } else {
156 undo_info.current--;
157 }
158
159 undo_info.count--;
160
161 return;
162}
163
164static void add_undo(int button)
165{
166 struct Undo *undo;
167 int row, col, i;
168 bool storable;
169
170 if ((button != BUTTON_LEFT) && (button != BUTTON_RIGHT) &&
171 (button != BUTTON_UP) && (button != BUTTON_DOWN))
172 return;
173
174 if (undo_info.count != 0) {
175 if (undo_info.current < (MAX_UNDOS - 1))
176 undo_info.current++;
177 else
178 undo_info.current = 0;
179 }
180
181 /* Make what follows more readable */
182 undo = &undo_info.history[undo_info.current];
183
184 /* Store our level info */
185 undo->level = current_info.level;
186
187 /* Store our player info */
188 undo->location[0] = current_info.player;
189
190 /* Now we need to store upto 2 blocks that may be affected.
191 * If player.spot is NULL, then there is no info stored
192 * for that block */
193
194 row = current_info.player.row;
195 col = current_info.player.col;
196
197 /* This must stay as _1_ because the first block (0) is the player */
198 for (i = 1; i < 3; i++) {
199 storable = true;
200
201 switch (button) {
202 case BUTTON_LEFT:
203 col--;
204 if (col < 0)
205 storable = false;
206 break;
207
208 case BUTTON_RIGHT:
209 col++;
210 if (col >= COLS)
211 storable = false;
212 break;
213
214 case BUTTON_UP:
215 row--;
216 if (row < 0)
217 storable = false;
218 break;
219
220 case BUTTON_DOWN:
221 row++;
222 if (row >= ROWS)
223 storable = false;
224 break;
225
226 default:
227 return;
228 }
229
230 if (storable) {
231 undo->location[i].col = col;
232 undo->location[i].row = row;
233 undo->location[i].spot = current_info.board[row][col];
234 } else {
235 undo->location[i].spot = '\0';
236 }
237 }
238
239 if (undo_info.count < MAX_UNDOS)
240 undo_info.count++;
241}
242
243static void init_boards(void)
244{
245 current_info.level.level = 0;
246 current_info.level.moves = 0;
247 current_info.level.boxes_to_go = 0;
248 current_info.player.row = 0;
249 current_info.player.col = 0;
250 current_info.player.spot = ' ';
251 current_info.max_level = 0;
252 current_info.level_offset = 0;
253 current_info.loaded_level = 0;
254
255 init_undo();
256}
257
258static int get_level_count(void)
259{
260 int fd = 0;
261 int len, lastlen = 0;
262 char buffer[COLS + 3]; /* COLS plus CR/LF and \0 */
263
264 if ((fd = open(LEVELS_FILE, O_RDONLY)) < 0) {
265 splash(0, 0, true, "Unable to open %s", LEVELS_FILE);
266 return -1;
267 }
268
269 while(1) {
270 len = read_line(fd, buffer, sizeof(buffer));
271 if(len <= 0)
272 break;
273
274 /* Two short lines in a row means new level */
275 if(len < 3 && lastlen < 3)
276 current_info.max_level++;
277
278 lastlen = len;
279 }
280
281 DEBUGF("%d levels loaded\n", current_info.max_level);
282 close(fd);
283 return 0;
284}
285
286static int get_level(char *level, int level_size)
287{
288 int fd = 0, i = 0;
289 int nread = 0;
290 int count = 0;
291 int len, lastlen = 0;
292 int level_ct = 1;
293 unsigned char buffer[SOKOBAN_LEVEL_SIZE * 2];
294 bool level_found = false;
295
296 /* open file */
297 if ((fd = open(LEVELS_FILE, O_RDONLY)) < 0)
298 return -1;
299
300 /* Lets not reparse the full file if we can avoid it */
301 if (current_info.loaded_level < current_info.level.level) {
302 lseek(fd, current_info.level_offset, SEEK_SET);
303 level_ct = current_info.loaded_level;
304 }
305
306 if(current_info.level.level > 1) {
307 while(!level_found) {
308 len = read_line(fd, buffer, SOKOBAN_LEVEL_SIZE);
309 if(len <= 0) {
310 close(fd);
311 return -1;
312 }
313
314 /* Two short lines in a row means new level */
315 if(len < 3 && lastlen < 3) {
316 level_ct++;
317 if(level_ct == current_info.level.level)
318 level_found = true;
319 }
320 lastlen = len;
321 }
322 }
323
324 /* Remember the current offset */
325 current_info.level_offset = lseek(fd, 0, SEEK_CUR);
326
327 /* read a full buffer chunk from here */
328 nread = read(fd, buffer, sizeof(buffer)-1);
329 if (nread < 0)
330 return -1;
331 buffer[nread] = 0;
332
333 close(fd);
334
335 /* If we read less then a level, error */
336 if (nread < level_size)
337 return -1;
338
339 /* Load our new level */
340 for(i=0, count=0; (count < nread) && (i<level_size);) {
341 if (buffer[count] != '\n' && buffer[count] != '\r')
342 level[i++] = buffer[count];
343 count++;
344 }
345 level[i] = 0;
346
347 current_info.loaded_level = current_info.level.level;
348 return 0;
349}
350
351/* return non-zero on error */
352static int load_level(void)
353{
354 short c = 0;
355 short r = 0;
356 short i = 0;
357 char level[ROWS*COLS+1];
358 int x = 0;
359
360 current_info.player.spot=' ';
361 current_info.level.boxes_to_go = 0;
362 current_info.level.moves = 0;
363
364 if (get_level(level, sizeof(level)) != 0)
365 return -1;
366
367 i = 0;
368 for (r = 0; r < ROWS; r++) {
369 x++;
370 for (c = 0; c < COLS; c++, i++) {
371 current_info.board[r][c] = level[i];
372
373 if (current_info.board[r][c] == '.')
374 current_info.level.boxes_to_go++;
375
376 else if (current_info.board[r][c] == '@') {
377 current_info.player.row = r;
378 current_info.player.col = c;
379 }
380 }
381 }
382
383 return 0;
384}
385
386static void update_screen(void)
387{
388 short b = 0, c = 0;
389 short rows = 0, cols = 0;
390 char s[25];
391
392 short magnify = 4;
393
394 /* load the board to the screen */
395 for (rows=0 ; rows < ROWS ; rows++) {
396 for (cols = 0 ; cols < COLS ; cols++) {
397 c = cols * magnify;
398 b = rows * magnify;
399
400 switch(current_info.board[rows][cols]) {
401 case 'X': /* black space */
402 lcd_drawrect(c, b, magnify, magnify);
403 lcd_drawrect(c+1, b+1, 2, 2);
404 break;
405
406 case '#': /* this is a wall */
407 lcd_drawpixel(c, b);
408 lcd_drawpixel(c+2, b);
409 lcd_drawpixel(c+1, b+1);
410 lcd_drawpixel(c+3, b+1);
411 lcd_drawpixel(c, b+2);
412 lcd_drawpixel(c+2, b+2);
413 lcd_drawpixel(c+1, b+3);
414 lcd_drawpixel(c+3, b+3);
415 break;
416
417 case '.': /* this is a home location */
418 lcd_drawrect(c+1, b+1, 2, 2);
419 break;
420
421 case '$': /* this is a box */
422 lcd_drawrect(c, b, magnify, magnify);
423 break;
424
425 case '@': /* this is you */
426 lcd_drawline(c+1, b, c+2, b);
427 lcd_drawline(c, b+1, c+3, b+1);
428 lcd_drawline(c+1, b+2, c+2, b+2);
429
430 lcd_drawpixel(c, b+3);
431 lcd_drawpixel(c+3, b+3);
432 break;
433
434 case '%': /* this is a box on a home spot */
435 lcd_drawrect(c, b, magnify, magnify);
436 lcd_drawrect(c+1, b+1, 2, 2);
437 break;
438 }
439 }
440 }
441
442
443 snprintf(s, sizeof(s), "%d", current_info.level.level);
444 lcd_putsxy(86, 22, s);
445 snprintf(s, sizeof(s), "%d", current_info.level.moves);
446 lcd_putsxy(86, 54, s);
447
448 lcd_drawrect(80,0,32,32);
449 lcd_drawrect(80,32,32,64);
450 lcd_putsxy(81, 10, str(LANG_SOKOBAN_LEVEL));
451 lcd_putsxy(81, 42, str(LANG_SOKOBAN_MOVE));
452
453 /* print out the screen */
454 lcd_update();
455}
456
457static void draw_level(void)
458{
459 load_level();
460 lcd_clear_display();
461 update_screen();
462}
463
464static bool sokoban_loop(void)
465{
466 char new_spot;
467 bool moved = true;
468 int i = 0, button = 0;
469 short r = 0, c = 0;
470
471 current_info.level.level = 1;
472
473 load_level();
474 update_screen();
475
476 while (1) {
477 moved = true;
478
479 r = current_info.player.row;
480 c = current_info.player.col;
481
482 button = button_get(true);
483
484 add_undo(button);
485
486 switch(button)
487 {
488 case BUTTON_OFF:
489 /* get out of here */
490 return false;
491
492 case BUTTON_ON:
493 case BUTTON_ON | BUTTON_REPEAT:
494 /* this is UNDO */
495 undo();
496 lcd_clear_display();
497 update_screen();
498 moved = false;
499 break;
500
501 case BUTTON_F3:
502 case BUTTON_F3 | BUTTON_REPEAT:
503 /* increase level */
504 init_undo();
505 current_info.level.boxes_to_go=0;
506 moved = true;
507 break;
508
509 case BUTTON_F1:
510 case BUTTON_F1 | BUTTON_REPEAT:
511 /* previous level */
512 init_undo();
513 if (current_info.level.level > 1)
514 current_info.level.level--;
515
516 draw_level();
517 moved = false;
518 break;
519
520 case BUTTON_F2:
521 case BUTTON_F2 | BUTTON_REPEAT:
522 /* same level */
523 init_undo();
524 draw_level();
525 moved = false;
526 break;
527
528 case BUTTON_LEFT:
529 switch(current_info.board[r][c-1])
530 {
531 case ' ': /* if it is a blank spot */
532 case '.': /* if it is a home spot */
533 new_spot = current_info.board[r][c-1];
534 current_info.board[r][c-1] = '@';
535 current_info.board[r][c] = current_info.player.spot;
536 current_info.player.spot = new_spot;
537 break;
538
539 case '$':
540 switch(current_info.board[r][c-2])
541 {
542 case ' ': /* going from blank to blank */
543 current_info.board[r][c-2] = current_info.board[r][c-1];
544 current_info.board[r][c-1] = current_info.board[r][c];
545 current_info.board[r][c] = current_info.player.spot;
546 current_info.player.spot = ' ';
547 break;
548
549 case '.': /* going from a blank to home */
550 current_info.board[r][c-2] = '%';
551 current_info.board[r][c-1] = current_info.board[r][c];
552 current_info.board[r][c] = current_info.player.spot;
553 current_info.player.spot = ' ';
554 current_info.level.boxes_to_go--;
555 break;
556
557 default:
558 moved = false;
559 break;
560 }
561 break;
562
563 case '%':
564 switch(current_info.board[r][c-2]) {
565 case ' ': /* we are going from a home to a blank */
566 current_info.board[r][c-2] = '$';
567 current_info.board[r][c-1] = current_info.board[r][c];
568 current_info.board[r][c] = current_info.player.spot;
569 current_info.player.spot = '.';
570 current_info.level.boxes_to_go++;
571 break;
572
573 case '.': /* if we are going from a home to home */
574 current_info.board[r][c-2] = '%';
575 current_info.board[r][c-1] = current_info.board[r][c];
576 current_info.board[r][c] = current_info.player.spot;
577 current_info.player.spot = '.';
578 break;
579
580 default:
581 moved = false;
582 break;
583 }
584 break;
585
586 default:
587 moved = false;
588 break;
589 }
590
591 if (moved)
592 current_info.player.col--;
593 break;
594
595 case BUTTON_RIGHT: /* if it is a blank spot */
596 switch(current_info.board[r][c+1]) {
597 case ' ':
598 case '.': /* if it is a home spot */
599 new_spot = current_info.board[r][c+1];
600 current_info.board[r][c+1] = '@';
601 current_info.board[r][c] = current_info.player.spot;
602 current_info.player.spot = new_spot;
603 break;
604
605 case '$':
606 switch(current_info.board[r][c+2]) {
607 case ' ': /* going from blank to blank */
608 current_info.board[r][c+2] = current_info.board[r][c+1];
609 current_info.board[r][c+1] = current_info.board[r][c];
610 current_info.board[r][c] = current_info.player.spot;
611 current_info.player.spot = ' ';
612 break;
613
614 case '.': /* going from a blank to home */
615 current_info.board[r][c+2] = '%';
616 current_info.board[r][c+1] = current_info.board[r][c];
617 current_info.board[r][c] = current_info.player.spot;
618 current_info.player.spot = ' ';
619 current_info.level.boxes_to_go--;
620 break;
621
622 default:
623 moved = false;
624 break;
625 }
626 break;
627
628 case '%':
629 switch(current_info.board[r][c+2]) {
630 case ' ': /* going from a home to a blank */
631 current_info.board[r][c+2] = '$';
632 current_info.board[r][c+1] = current_info.board[r][c];
633 current_info.board[r][c] = current_info.player.spot;
634 current_info.player.spot = '.';
635 current_info.level.boxes_to_go++;
636 break;
637
638 case '.':
639 current_info.board[r][c+2] = '%';
640 current_info.board[r][c+1] = current_info.board[r][c];
641 current_info.board[r][c] = current_info.player.spot;
642 current_info.player.spot = '.';
643 break;
644
645 default:
646 moved = false;
647 break;
648 }
649 break;
650
651 default:
652 moved = false;
653 break;
654 }
655
656 if (moved)
657 current_info.player.col++;
658 break;
659
660 case BUTTON_UP:
661 switch(current_info.board[r-1][c]) {
662 case ' ': /* if it is a blank spot */
663 case '.': /* if it is a home spot */
664 new_spot = current_info.board[r-1][c];
665 current_info.board[r-1][c] = '@';
666 current_info.board[r][c] = current_info.player.spot;
667 current_info.player.spot = new_spot;
668 break;
669
670 case '$':
671 switch(current_info.board[r-2][c]) {
672 case ' ': /* going from blank to blank */
673 current_info.board[r-2][c] = current_info.board[r-1][c];
674 current_info.board[r-1][c] = current_info.board[r][c];
675 current_info.board[r][c] = current_info.player.spot;
676 current_info.player.spot = ' ';
677 break;
678
679 case '.': /* going from a blank to home */
680 current_info.board[r-2][c] = '%';
681 current_info.board[r-1][c] = current_info.board[r][c];
682 current_info.board[r][c] = current_info.player.spot;
683 current_info.player.spot = ' ';
684 current_info.level.boxes_to_go--;
685 break;
686
687 default:
688 moved = false;
689 break;
690 }
691 break;
692
693 case '%':
694 switch(current_info.board[r-2][c]) {
695 case ' ': /* we are going from a home to a blank */
696 current_info.board[r-2][c] = '$';
697 current_info.board[r-1][c] = current_info.board[r][c];
698 current_info.board[r][c] = current_info.player.spot;
699 current_info.player.spot = '.';
700 current_info.level.boxes_to_go++;
701 break;
702
703 case '.': /* if we are going from a home to home */
704 current_info.board[r-2][c] = '%';
705 current_info.board[r-1][c] = current_info.board[r][c];
706 current_info.board[r][c] = current_info.player.spot;
707 current_info.player.spot = '.';
708 break;
709
710 default:
711 moved = false;
712 break;
713 }
714 break;
715
716 default:
717 moved = false;
718 break;
719 }
720
721 if (moved)
722 current_info.player.row--;
723 break;
724
725 case BUTTON_DOWN:
726 switch(current_info.board[r+1][c]) {
727 case ' ': /* if it is a blank spot */
728 case '.': /* if it is a home spot */
729 new_spot = current_info.board[r+1][c];
730 current_info.board[r+1][c] = '@';
731 current_info.board[r][c] = current_info.player.spot;
732 current_info.player.spot = new_spot;
733 break;
734
735 case '$':
736 switch(current_info.board[r+2][c]) {
737 case ' ': /* going from blank to blank */
738 current_info.board[r+2][c] = current_info.board[r+1][c];
739 current_info.board[r+1][c] = current_info.board[r][c];
740 current_info.board[r][c] = current_info.player.spot;
741 current_info.player.spot = ' ';
742 break;
743
744 case '.': /* going from a blank to home */
745 current_info.board[r+2][c] = '%';
746 current_info.board[r+1][c] = current_info.board[r][c];
747 current_info.board[r][c] = current_info.player.spot;
748 current_info.player.spot = ' ';
749 current_info.level.boxes_to_go--;
750 break;
751
752 default:
753 moved = false;
754 break;
755 }
756 break;
757
758 case '%':
759 switch(current_info.board[r+2][c]) {
760 case ' ': /* going from a home to a blank */
761 current_info.board[r+2][c] = '$';
762 current_info.board[r+1][c] = current_info.board[r][c];
763 current_info.board[r][c] = current_info.player.spot;
764 current_info.player.spot = '.';
765 current_info.level.boxes_to_go++;
766 break;
767
768 case '.': /* going from a home to home */
769 current_info.board[r+2][c] = '%';
770 current_info.board[r+1][c] = current_info.board[r][c];
771 current_info.board[r][c] = current_info.player.spot;
772 current_info.player.spot = '.';
773 break;
774
775 default:
776 moved = false;
777 break;
778 }
779 break;
780
781 default:
782 moved = false;
783 break;
784 }
785
786 if (moved)
787 current_info.player.row++;
788 break;
789
790 case SYS_USB_CONNECTED:
791 usb_screen();
792 return true;
793
794 default:
795 moved = false;
796 break;
797 }
798
799 if (moved) {
800 current_info.level.moves++;
801 lcd_clear_display();
802 update_screen();
803 }
804
805 /* We have completed this level */
806 if (current_info.level.boxes_to_go == 0) {
807 current_info.level.level++;
808
809 /* clear undo stats */
810 init_undo();
811
812 lcd_clear_display();
813
814 if (current_info.level.level > current_info.max_level) {
815 lcd_putsxy(10, 20, str(LANG_SOKOBAN_WIN));
816
817 for (i = 0; i < 30000 ; i++) {
818 lcd_invertrect(0, 0, 111, 63);
819 lcd_update();
820
821 button = button_get(false);
822 if (button && ((button & BUTTON_REL) != BUTTON_REL))
823 break;
824 }
825
826 return false;
827 }
828
829 load_level();
830 update_screen();
831 }
832
833 } /* end while */
834
835 return false;
836}
837
838
839bool sokoban(void)
840{
841 bool result;
842 int w, h;
843 int len;
844
845 lcd_setfont(FONT_SYSFIXED);
846
847 lcd_getstringsize(SOKOBAN_TITLE, &w, &h);
848
849 /* Get horizontel centering for text */
850 len = w;
851 if (len%2 != 0)
852 len =((len+1)/2)+(w/2);
853 else
854 len /= 2;
855
856 if (h%2 != 0)
857 h = (h/2)+1;
858 else
859 h /= 2;
860
861 lcd_clear_display();
862 lcd_putsxy(LCD_WIDTH/2-len,(LCD_HEIGHT/2)-h, SOKOBAN_TITLE);
863
864 lcd_update();
865 sleep(HZ*2);
866
867 lcd_clear_display();
868
869 lcd_putsxy(3, 6, str(LANG_SOKOBAN_QUIT));
870 lcd_putsxy(3, 16, str(LANG_SOKOBAN_ON));
871 lcd_putsxy(3, 26, str(LANG_SOKOBAN_F1));
872 lcd_putsxy(3, 36, str(LANG_SOKOBAN_F2));
873 lcd_putsxy(3, 46, str(LANG_SOKOBAN_F3));
874
875 lcd_update();
876 sleep(HZ*2);
877 lcd_clear_display();
878
879 init_boards();
880
881 if (get_level_count() != 0)
882 return false;
883
884 result = sokoban_loop();
885
886 lcd_setfont(FONT_UI);
887
888 return result;
889}
890
891#endif
diff --git a/apps/recorder/sokoban.h b/apps/recorder/sokoban.h
deleted file mode 100644
index f4f8fdd24f..0000000000
--- a/apps/recorder/sokoban.h
+++ /dev/null
@@ -1,28 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2002 Robert E. Hak
11 *
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19
20#ifndef __SOKOBAN__
21#define __SOKOBAN__
22
23#include "menu.h"
24
25bool sokoban(void);
26
27#endif /*__SOKOBAN__ */
28
diff --git a/apps/recorder/tetris.c b/apps/recorder/tetris.c
deleted file mode 100644
index 6302e40109..0000000000
--- a/apps/recorder/tetris.c
+++ /dev/null
@@ -1,438 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 1999 Mattis Wadman (nappe@sudac.org)
11 *
12 * Heavily modified for embedded use by Björn Stenberg (bjorn@haxx.se)
13 *
14 * All files in this archive are subject to the GNU General Public License.
15 * See the file COPYING in the source tree root for full license agreement.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#include "config.h"
23#include "options.h"
24
25#ifdef USE_GAMES
26
27#include <stdbool.h>
28#include <string.h>
29#include "lcd.h"
30#include "button.h"
31#include "kernel.h"
32#include "menu.h"
33#include "screens.h"
34#include "font.h"
35
36#ifdef SIMULATOR
37#include <stdio.h>
38#endif
39#include "sprintf.h"
40#include "lang.h"
41#define TETRIS_TITLE "Tetris!"
42#define TETRIS_TITLE_FONT 1
43#define TETRIS_TITLE_XLOC 43
44#define TETRIS_TITLE_YLOC 15
45
46static const int start_x = 5;
47static const int start_y = 5;
48static const int max_x = 4 * 17;
49static const int max_y = 3 * 10;
50static const short level_speeds[10] = {
51 1000, 900, 800, 700, 600, 500, 400, 300, 250, 200
52};
53static const int blocks = 7;
54static const int block_frames[7] = {1,2,2,2,4,4,4};
55
56static int current_x, current_y, current_f, current_b;
57static int level, score;
58static int next_b, next_f;
59static short lines;
60static char virtual[LCD_WIDTH * LCD_HEIGHT];
61
62/*
63 block_data is built up the following way
64
65 first array index specifies the block number
66 second array index specifies the rotation of the block
67 third array index specifies:
68 0: x-coordinates of pixels
69 1: y-coordinates of pixels
70 fourth array index specifies the coordinate of a pixel
71
72 each block consists of four pixels whose relative coordinates are given
73 with block_data
74*/
75
76static const char block_data[7][4][2][4] =
77{
78 {
79 {{0,1,0,1},{0,0,1,1}}
80 },
81 {
82 {{0,1,1,2},{1,1,0,0}},
83 {{0,0,1,1},{0,1,1,2}}
84 },
85 {
86 {{0,1,1,2},{0,0,1,1}},
87 {{1,1,0,0},{0,1,1,2}}
88 },
89 {
90 {{1,1,1,1},{0,1,2,3}},
91 {{0,1,2,3},{2,2,2,2}}
92 },
93 {
94 {{1,1,1,2},{2,1,0,0}},
95 {{0,1,2,2},{1,1,1,2}},
96 {{0,1,1,1},{2,2,1,0}},
97 {{0,0,1,2},{0,1,1,1}}
98 },
99 {
100 {{0,1,1,1},{0,0,1,2}},
101 {{0,1,2,2},{1,1,1,0}},
102 {{1,1,1,2},{0,1,2,2}},
103 {{0,0,1,2},{2,1,1,1}}
104 },
105 {
106 {{1,0,1,2},{0,1,1,1}},
107 {{2,1,1,1},{1,0,1,2}},
108 {{1,0,1,2},{2,1,1,1}},
109 {{0,1,1,1},{1,0,1,2}}
110 }
111};
112
113static int t_rand(int range)
114{
115 return current_tick % range;
116}
117
118static void draw_frame(int fstart_x,int fstop_x,int fstart_y,int fstop_y)
119{
120 lcd_drawline(fstart_x, fstart_y, fstop_x, fstart_y);
121 lcd_drawline(fstart_x, fstop_y, fstop_x, fstop_y);
122
123 lcd_drawline(fstart_x, fstart_y, fstart_x, fstop_y);
124 lcd_drawline(fstop_x, fstart_y, fstop_x, fstop_y);
125
126 lcd_drawline(fstart_x - 1, fstart_y + 1, fstart_x - 1, fstop_y + 1);
127 lcd_drawline(fstart_x - 1, fstop_y + 1, fstop_x - 1, fstop_y + 1);
128}
129
130static void draw_block(int x, int y, int block, int frame, bool clear)
131{
132 int i, a, b;
133 for(i=0;i < 4;i++) {
134 if (clear)
135 {
136 for (a = 0; a < 3; a++)
137 for (b = 0; b < 4; b++)
138 lcd_clearpixel(start_x + x + block_data[block][frame][1][i] * 4 - b,
139 start_y + y + block_data[block][frame][0][i] * 3 + a);
140 }
141 else
142 {
143 for (a = 0; a < 3; a++)
144 for (b = 0; b < 4; b++)
145 lcd_drawpixel(start_x+x+block_data[block][frame][1][i] * 4 - b,
146 start_y+y+block_data[block][frame][0][i] * 3 + a);
147 }
148 }
149}
150
151static void to_virtual(void)
152{
153 int i, a, b;
154
155 for(i = 0; i < 4; i++)
156 for (a = 0; a < 3; a++)
157 for (b = 0; b < 4; b++)
158 *(virtual +
159 (current_y + block_data[current_b][current_f][0][i] * 3 + a) *
160 max_x + current_x + block_data[current_b][current_f][1][i] *
161 4 - b) = current_b + 1;
162}
163
164static bool block_touch (int x, int y)
165{
166 int a,b;
167 for (a = 0; a < 4; a++)
168 for (b = 0; b < 3; b++)
169 if (*(virtual + (y + b) * max_x + (x - a)) != 0)
170 return true;
171 return false;
172}
173
174static bool gameover(void)
175{
176 int i;
177 int frame, block, y, x;
178
179 x = current_x;
180 y = current_y;
181 block = current_b;
182 frame = current_f;
183
184 for(i = 0; i < 4; i++){
185 /* Do we have blocks touching? */
186 if(block_touch(x + block_data[block][frame][1][i] * 4,
187 y + block_data[block][frame][0][i] * 3))
188 {
189 /* Are we at the top of the frame? */
190 if(x + block_data[block][frame][1][i] * 4 >= max_x - 16)
191 {
192 /* Game over ;) */
193 return true;
194 }
195 }
196 }
197 return false;
198}
199
200static bool valid_position(int x, int y, int block, int frame)
201{
202 int i;
203 for(i=0;i < 4;i++)
204 if ((y + block_data[block][frame][0][i] * 3 > max_y - 3) ||
205 (x + block_data[block][frame][1][i] * 4 > max_x - 4) ||
206 (y + block_data[block][frame][0][i] * 3 < 0) ||
207 (x + block_data[block][frame][1][i] * 4 < 4) ||
208 block_touch (x + block_data[block][frame][1][i] * 4,
209 y + block_data[block][frame][0][i] * 3))
210 {
211 return false;
212 }
213 return true;
214}
215
216static void from_virtual(void)
217{
218 int x,y;
219 for(y = 0; y < max_y; y++)
220 for(x = 1; x < max_x - 1; x++)
221 if(*(virtual + (y * max_x) + x) != 0)
222 lcd_drawpixel(start_x + x, start_y + y);
223 else
224 lcd_clearpixel(start_x + x, start_y + y);
225}
226
227static void move_block(int x,int y,int f)
228{
229 int last_frame = current_f;
230 if(f != 0)
231 {
232 current_f += f;
233 if(current_f > block_frames[current_b]-1)
234 current_f = 0;
235 if(current_f < 0)
236 current_f = block_frames[current_b]-1;
237 }
238
239 if(valid_position(current_x + x, current_y + y, current_b, current_f))
240 {
241 draw_block(current_x,current_y,current_b,last_frame,true);
242 current_x += x;
243 current_y += y;
244 draw_block(current_x,current_y,current_b,current_f,false);
245 lcd_update();
246 }
247 else
248 current_f = last_frame;
249}
250
251static void new_block(void)
252{
253 current_b = next_b;
254 current_f = next_f;
255 current_x = max_x - 16;
256 current_y = (int)12;
257 next_b = t_rand(blocks);
258 next_f = t_rand(block_frames[next_b]);
259
260 lcd_drawline (max_x + 7, start_y - 1, max_x + 29, start_y - 1);
261 lcd_drawline (max_x + 29, start_y, max_x + 29, start_y + 14);
262 lcd_drawline (max_x + 29, start_y + 14, max_x + 7, start_y + 14);
263 lcd_drawline (max_x + 7, start_y + 14, max_x + 7, start_y - 1);
264 lcd_drawline (max_x + 6, start_y + 15, max_x + 6, start_y);
265 lcd_drawline (max_x + 6, start_y + 15, max_x + 28, start_y + 15);
266
267 draw_block(max_x + 9, start_y - 4, current_b, current_f, true);
268 draw_block(max_x + 9, start_y - 4, next_b, next_f, false);
269 if(!valid_position(current_x, current_y, current_b, current_f))
270 {
271 draw_block(current_x, current_y, current_b, current_f, false);
272 lcd_update();
273 }
274 else
275 draw_block(current_x, current_y, current_b, current_f, false);
276}
277
278static int check_lines(void)
279{
280 int x,y,i,j;
281 bool line;
282 int lines = 0;
283 for(x = 0; x < max_x; x++)
284 {
285 line = true;
286 for(y = 0; y < max_y; y++)
287 {
288 if(*(virtual + y * max_x + x) == 0)
289 {
290 line = false;
291 break;
292 }
293 }
294
295 if(line)
296 {
297 lines++;
298 /* move rows down */
299 for(i = x; i < max_x - 1; i++)
300 for (j = 0; j < max_y; j++)
301 *(virtual + j * max_x + i)=*(virtual + j * max_x + (i + 1));
302
303 x--; /* re-check this line */
304 }
305 }
306
307 return lines / 4;
308}
309
310static void move_down(void)
311{
312 int l;
313 char s[25];
314
315 if(!valid_position(current_x - 4, current_y, current_b, current_f))
316 {
317 to_virtual();
318 l = check_lines();
319 if(l)
320 {
321 lines += l;
322 level = (int)lines/10;
323 if(level > 9)
324 level = 9;
325 from_virtual();
326 score += l*l;
327 }
328
329 snprintf (s, sizeof(s), "%d %s %d", lines,
330 str(LANG_TETRIS_LEVEL), level);
331 lcd_putsxy (2, 42, s);
332
333 new_block();
334 move_block(0,0,0);
335 }
336 else
337 move_block(-4,0,0);
338}
339
340static bool game_loop(void)
341{
342 while(1)
343 {
344 int count = 0;
345 while(count * 300 < level_speeds[level])
346 {
347 switch(button_get_w_tmo(HZ/10))
348 {
349 case BUTTON_OFF:
350 return false;
351
352 case BUTTON_UP:
353 case BUTTON_UP | BUTTON_REPEAT:
354 move_block(0,-3,0);
355 break;
356
357 case BUTTON_DOWN:
358 case BUTTON_DOWN | BUTTON_REPEAT:
359 move_block(0,3,0);
360 break;
361
362 case BUTTON_RIGHT:
363 case BUTTON_RIGHT | BUTTON_REPEAT:
364 move_block(0,0,1);
365 break;
366
367 case BUTTON_LEFT:
368 case BUTTON_LEFT | BUTTON_REPEAT:
369 move_down();
370 break;
371
372 case SYS_USB_CONNECTED:
373 usb_screen();
374 return true;
375 }
376
377 count++;
378 }
379
380 if(gameover())
381 {
382 lcd_clearrect(0, 52, LCD_WIDTH, LCD_HEIGHT - 52);
383 lcd_putsxy (2, 52, str(LANG_TETRIS_LOSE));
384 lcd_update();
385 sleep(HZ * 3);
386 return false;
387 }
388
389 move_down();
390 }
391
392 return false;
393}
394
395static void init_tetris(void)
396{
397 memset(&virtual, 0, sizeof(virtual));
398
399 current_x = 0;
400 current_y = 0;
401 current_f = 0;
402 current_b = 0;
403 level = 0;
404 lines = 0;
405 score = 0;
406 next_b = 0;
407 next_f = 0;
408}
409
410bool tetris(void)
411{
412 char buf[20];
413 bool val;
414
415 /* Lets use the default font */
416 lcd_setfont(FONT_SYSFIXED);
417
418 init_tetris();
419
420 draw_frame(start_x, start_x + max_x - 1, start_y - 1, start_y + max_y);
421 snprintf(buf, sizeof(buf), "0 %s 0", str(LANG_TETRIS_LEVEL));
422 lcd_putsxy (2, 42, buf);
423 lcd_update();
424
425 next_b = t_rand(blocks);
426 next_f = t_rand(block_frames[next_b]);
427 new_block();
428 val = game_loop();
429
430 lcd_setfont(FONT_UI);
431
432 return val;
433}
434
435#endif
436
437
438
diff --git a/apps/recorder/wormlet.h b/apps/recorder/wormlet.h
deleted file mode 100644
index 0aeea3cc77..0000000000
--- a/apps/recorder/wormlet.h
+++ /dev/null
@@ -1,28 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2002 Philipp Pertermann
11 *
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19
20#ifndef __WORMLET__
21#define __WORMLET__
22
23#include "menu.h"
24
25bool wormlet(void);
26
27#endif /*__WORMLET__ */
28
diff --git a/apps/screens.c b/apps/screens.c
index d12a93a4d4..6055be3a2d 100644
--- a/apps/screens.c
+++ b/apps/screens.c
@@ -31,6 +31,7 @@
31#include "status.h" 31#include "status.h"
32#include "playlist.h" 32#include "playlist.h"
33#include "sprintf.h" 33#include "sprintf.h"
34#include "kernel.h"
34 35
35#ifdef HAVE_LCD_BITMAP 36#ifdef HAVE_LCD_BITMAP
36#define BMPHEIGHT_usb_logo 32 37#define BMPHEIGHT_usb_logo 32
diff --git a/apps/tree.c b/apps/tree.c
index 9935d8263d..e61fdc50cb 100644
--- a/apps/tree.c
+++ b/apps/tree.c
@@ -46,12 +46,12 @@
46#include "rolo.h" 46#include "rolo.h"
47#include "icons.h" 47#include "icons.h"
48#include "lang.h" 48#include "lang.h"
49#include "viewer.h"
50#include "language.h" 49#include "language.h"
51#include "screens.h" 50#include "screens.h"
52#include "keyboard.h" 51#include "keyboard.h"
53#include "onplay.h" 52#include "onplay.h"
54#include "buffer.h" 53#include "buffer.h"
54#include "plugin.h"
55 55
56#ifdef HAVE_LCD_BITMAP 56#ifdef HAVE_LCD_BITMAP
57#include "widgets.h" 57#include "widgets.h"
@@ -318,6 +318,8 @@ static int showdir(char *path, int start)
318 else if (!strcasecmp(&entry->d_name[len-4], ".mod")) 318 else if (!strcasecmp(&entry->d_name[len-4], ".mod"))
319#endif 319#endif
320 dptr->attr |= TREE_ATTR_MOD; 320 dptr->attr |= TREE_ATTR_MOD;
321 else if (!strcasecmp(&entry->d_name[len-5], ".rock"))
322 dptr->attr |= TREE_ATTR_ROCK;
321 } 323 }
322 324
323 /* filter out all non-playlist files */ 325 /* filter out all non-playlist files */
@@ -468,6 +470,10 @@ static int showdir(char *path, int start)
468 icon_type = Mod_Ajz; 470 icon_type = Mod_Ajz;
469 break; 471 break;
470 472
473 case TREE_ATTR_ROCK:
474 icon_type = Plugin;
475 break;
476
471#ifdef HAVE_LCD_BITMAP 477#ifdef HAVE_LCD_BITMAP
472 case TREE_ATTR_FONT: 478 case TREE_ATTR_FONT:
473 icon_type = Font; 479 icon_type = Font;
@@ -962,7 +968,7 @@ bool dirbrowse(char *root)
962 break; 968 break;
963 969
964 case TREE_ATTR_TXT: 970 case TREE_ATTR_TXT:
965 viewer_run(buf); 971 plugin_load("/.rockbox/rocks/viewer.rock",buf);
966 restore = true; 972 restore = true;
967 break; 973 break;
968 974
@@ -998,6 +1004,14 @@ bool dirbrowse(char *root)
998 rolo_load(buf); 1004 rolo_load(buf);
999 break; 1005 break;
1000#endif 1006#endif
1007
1008 /* plugin file */
1009 case TREE_ATTR_ROCK:
1010 if (plugin_load(buf,NULL) == PLUGIN_USB_CONNECTED)
1011 reload_root = true;
1012 else
1013 restore = true;
1014 break;
1001 } 1015 }
1002 1016
1003 if ( play ) { 1017 if ( play ) {
@@ -1194,6 +1208,7 @@ bool dirbrowse(char *root)
1194 /* the sub-screen might've ruined the margins */ 1208 /* the sub-screen might've ruined the margins */
1195 lcd_setmargins(MARGIN_X,MARGIN_Y); /* leave room for cursor and 1209 lcd_setmargins(MARGIN_X,MARGIN_Y); /* leave room for cursor and
1196 icon */ 1210 icon */
1211 lcd_setfont(FONT_UI);
1197#endif 1212#endif
1198 numentries = showdir(currdir, dirstart); 1213 numentries = showdir(currdir, dirstart);
1199 update_all = true; 1214 update_all = true;
diff --git a/apps/tree.h b/apps/tree.h
index eb0aa8b98a..aa8f2127f3 100644
--- a/apps/tree.h
+++ b/apps/tree.h
@@ -30,6 +30,7 @@
30#define TREE_ATTR_TXT 0x500 /* text file */ 30#define TREE_ATTR_TXT 0x500 /* text file */
31#define TREE_ATTR_FONT 0x800 /* font file */ 31#define TREE_ATTR_FONT 0x800 /* font file */
32#define TREE_ATTR_LNG 0x1000 /* binary lang file */ 32#define TREE_ATTR_LNG 0x1000 /* binary lang file */
33#define TREE_ATTR_ROCK 0x2000 /* binary rockbox plugin */
33#define TREE_ATTR_MASK 0xffd0 /* which bits tree.c uses (above + DIR) */ 34#define TREE_ATTR_MASK 0xffd0 /* which bits tree.c uses (above + DIR) */
34 35
35void tree_init(void); 36void tree_init(void);
diff --git a/apps/viewer.h b/apps/viewer.h
deleted file mode 100644
index ed9f64ca49..0000000000
--- a/apps/viewer.h
+++ /dev/null
@@ -1,24 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2002 Jerome Kuptz
11 *
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19#ifndef _VIEWER_H
20#define _VIEWER_H
21
22bool viewer_run(char* file);
23
24#endif
diff --git a/firmware/app.lds b/firmware/app.lds
index 46a6ca70fb..34ab1adf66 100644
--- a/firmware/app.lds
+++ b/firmware/app.lds
@@ -2,15 +2,17 @@ ENTRY(start)
2OUTPUT_FORMAT(elf32-sh) 2OUTPUT_FORMAT(elf32-sh)
3INPUT(crt0.o) 3INPUT(crt0.o)
4 4
5#define PLUGINSIZE 0x8000
6
5#ifdef DEBUG 7#ifdef DEBUG
6#define DRAMSIZE 0x1f0000 8#define DRAMSIZE 0x1f0000 - PLUGINSIZE
7#define ORIGADDR 0x09010000 9#define ORIGADDR 0x09010000
8#define ENDADDR 0x09200000 10
9#else 11#else
10#define DRAMSIZE (MEMORYSIZE * 0x100000) 12#define DRAMSIZE (MEMORYSIZE * 0x100000) - PLUGINSIZE
11#define ORIGADDR 0x09000000 13#define ORIGADDR 0x09000000
12#define ENDADDR (ORIGADDR + DRAMSIZE)
13#endif 14#endif
15#define ENDADDR (ORIGADDR + DRAMSIZE)
14 16
15MEMORY 17MEMORY
16{ 18{
@@ -91,6 +93,11 @@ SECTIONS
91 _topramend = .; 93 _topramend = .;
92 } > DRAM 94 } > DRAM
93 95
96 .plugin ENDADDR:
97 {
98 _pluginbuf = .;
99 }
100
94 .iram 0xf000000 : AT ( _iramcopy ) 101 .iram 0xf000000 : AT ( _iramcopy )
95 { 102 {
96 _iramstart = .; 103 _iramstart = .;
diff --git a/firmware/drivers/lcd-player-charset.c b/firmware/drivers/lcd-player-charset.c
index 523158f49f..df4f3f016d 100644
--- a/firmware/drivers/lcd-player-charset.c
+++ b/firmware/drivers/lcd-player-charset.c
@@ -47,7 +47,7 @@ unsigned short new_lcd_rocklatin1_to_xlcd[] =
47 RESERVED_CHAR, /* 0x01-0x17 reserved */ 47 RESERVED_CHAR, /* 0x01-0x17 reserved */
48 RESERVED_CHAR, /* 0x01-0x17 reserved */ 48 RESERVED_CHAR, /* 0x01-0x17 reserved */
49 RESERVED_CHAR, /* 0x01-0x17 reserved */ 49 RESERVED_CHAR, /* 0x01-0x17 reserved */
50 RESERVED_CHAR, /* 0x01-0x17 reserved */ 50 0x217, /* 0x17 .. "plugin" icon */
51 0x218, /* 0x18 .. "folder" icon */ 51 0x218, /* 0x18 .. "folder" icon */
52 0x219, /* 0x19 .. "MOD/AJZ" icon (winlatin o (dote in the middle) */ 52 0x219, /* 0x19 .. "MOD/AJZ" icon (winlatin o (dote in the middle) */
53 0x21a, /* 0x1a .. "language" icon (winlatin - (a bit longer minus sign) */ 53 0x21a, /* 0x1a .. "language" icon (winlatin - (a bit longer minus sign) */
@@ -668,7 +668,7 @@ unsigned char extended_font_player[NO_EXTENDED_LCD_CHARS][8] = {
668 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 14 */ 668 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 14 */
669 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 15 */ 669 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 15 */
670 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 16 */ 670 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 16 */
671 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 17 */ 671 { 0x04, 0x1e, 0x07, 0x1f, 0x05, 0x01, 0x06, 0x00}, /* 17 Plugin file icon */
672 { 0x0c, 0x13, 0x11, 0x11, 0x11, 0x11, 0x1f, 0x00}, /* 18 Folder icon */ 672 { 0x0c, 0x13, 0x11, 0x11, 0x11, 0x11, 0x1f, 0x00}, /* 18 Folder icon */
673 { 0x1f, 0x11, 0x1b, 0x15, 0x1b, 0x11, 0x1f, 0x00}, /* 19 MOD/AJZ icon */ 673 { 0x1f, 0x11, 0x1b, 0x15, 0x1b, 0x11, 0x1f, 0x00}, /* 19 MOD/AJZ icon */
674 { 0x00, 0x1f, 0x15, 0x1f, 0x15, 0x1f, 0x00, 0x00}, /* 1a Language icon */ 674 { 0x00, 0x1f, 0x15, 0x1f, 0x15, 0x1f, 0x00, 0x00}, /* 1a Language icon */