FS#8708: D2/m:robe500 touchscreen keymaps by Andreas Mueller.
[kugel-rb.git] / apps / plugins / snake2.c
blob04522941955f515b9a5568bda78ba6da227565d4
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2003 Mat Holton
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.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
21 Snake2!
23 Board consists of a WIDTHxHEIGHT grid. If board element is 0 then nothing is
24 there otherwise it is part of the snake or a wall.
26 Head and Tail are stored
30 #include "plugin.h"
31 #ifdef HAVE_LCD_BITMAP
33 PLUGIN_HEADER
35 #define WIDTH 28
36 #define HEIGHT 16
38 #if (LCD_WIDTH >= 160) && (LCD_HEIGHT >= 128) && (LCD_DEPTH >= 1)
39 #include "snake2_header1.h"
40 #include "snake2_header2.h"
41 #include "snake2_left.h"
42 #include "snake2_right.h"
43 #include "snake2_bottom.h"
44 #define BMPHEIGHT_snake2_header BMPHEIGHT_snake2_header1
45 #define BMPWIDTH_snake2_header BMPWIDTH_snake2_header1
46 #endif
49 #if (LCD_WIDTH >= 320) && (LCD_HEIGHT >= 240)
50 #define MULTIPLIER 10 /*Modifier for porting on other screens*/
51 #define MODIFIER_1 10
52 #define MODIFIER_2 8
53 #define CENTER_X 20
54 #define CENTER_Y 55
55 #define TOP_X1 34 /* x-coord of the upperleft item (game type) */
56 #define TOP_X2 281 /* x-coord of the upperright item (maze type) */
57 #define TOP_X3 42 /* x-coord of the lowerleft item (speed) */
58 #define TOP_X4 274 /* x-coord of the lowerright item (hi-score) */
59 #define TOP_Y1 4 /* y-coord of the top row of items */
60 #define TOP_Y2 25 /* y-coord of the bottom row of items */
61 #elif (LCD_WIDTH >= 240) && (LCD_HEIGHT >= 168)
62 #define MULTIPLIER 8
63 #define MODIFIER_1 8
64 #define MODIFIER_2 6
65 #define CENTER_X 8
66 #define CENTER_Y 34
67 #define TOP_X1 34
68 #define TOP_X2 201
69 #define TOP_X3 42
70 #define TOP_X4 194
71 #define TOP_Y1 4
72 #define TOP_Y2 25
73 #elif (LCD_WIDTH >= 220) && (LCD_HEIGHT >= 176)
74 #define MULTIPLIER 7
75 #define MODIFIER_1 7
76 #define MODIFIER_2 5
77 #define CENTER_X 12
78 #define CENTER_Y 46
79 #define TOP_X1 34
80 #define TOP_X2 181
81 #define TOP_X3 42
82 #define TOP_X4 174
83 #define TOP_Y1 4
84 #define TOP_Y2 25
85 #elif (LCD_WIDTH >= 176) && (LCD_HEIGHT >= 132)
86 #define MULTIPLIER 5
87 #define MODIFIER_1 5
88 #define MODIFIER_2 3
89 #define CENTER_X 18
90 #define CENTER_Y 40
91 #define TOP_X1 34
92 #define TOP_X2 137
93 #define TOP_X3 42
94 #define TOP_X4 130
95 #define TOP_Y1 4
96 #define TOP_Y2 25
97 #elif (LCD_WIDTH >= 160) && (LCD_HEIGHT >= 128)
98 #define MULTIPLIER 5
99 #define MODIFIER_1 5
100 #define MODIFIER_2 3
101 #define CENTER_X 10
102 #define CENTER_Y 38
103 #define TOP_X1 34
104 #define TOP_X2 121
105 #define TOP_X3 42
106 #define TOP_X4 114
107 #define TOP_Y1 4
108 #define TOP_Y2 25
109 #else
110 #define MULTIPLIER 4
111 #define MODIFIER_1 4
112 #define MODIFIER_2 2
113 #define CENTER_X 0
114 #define CENTER_Y 0
116 #endif
118 /* variable button definitions */
119 #if CONFIG_KEYPAD == RECORDER_PAD
120 #define SNAKE2_LEFT BUTTON_LEFT
121 #define SNAKE2_RIGHT BUTTON_RIGHT
122 #define SNAKE2_UP BUTTON_UP
123 #define SNAKE2_DOWN BUTTON_DOWN
124 #define SNAKE2_QUIT BUTTON_OFF
125 #define SNAKE2_LEVEL_UP BUTTON_UP
126 #define SNAKE2_LEVEL_DOWN BUTTON_DOWN
127 #define SNAKE2_MAZE_NEXT BUTTON_RIGHT
128 #define SNAKE2_MAZE_LAST BUTTON_LEFT
129 #define SNAKE2_SELECT_TYPE BUTTON_F3
130 #define SNAKE2_PLAYPAUSE BUTTON_PLAY
131 #define SNAKE2_PLAYPAUSE_TEXT "Play"
133 #elif CONFIG_KEYPAD == ARCHOS_AV300_PAD
134 #define SNAKE2_LEFT BUTTON_LEFT
135 #define SNAKE2_RIGHT BUTTON_RIGHT
136 #define SNAKE2_UP BUTTON_UP
137 #define SNAKE2_DOWN BUTTON_DOWN
138 #define SNAKE2_QUIT BUTTON_OFF
139 #define SNAKE2_LEVEL_UP BUTTON_UP
140 #define SNAKE2_LEVEL_DOWN BUTTON_DOWN
141 #define SNAKE2_MAZE_NEXT BUTTON_RIGHT
142 #define SNAKE2_MAZE_LAST BUTTON_LEFT
143 #define SNAKE2_SELECT_TYPE BUTTON_F3
144 #define SNAKE2_PLAYPAUSE BUTTON_SELECT
145 #define SNAKE2_PLAYPAUSE_TEXT "Select"
147 #elif CONFIG_KEYPAD == ONDIO_PAD
148 #define SNAKE2_LEFT BUTTON_LEFT
149 #define SNAKE2_RIGHT BUTTON_RIGHT
150 #define SNAKE2_UP BUTTON_UP
151 #define SNAKE2_DOWN BUTTON_DOWN
152 #define SNAKE2_QUIT BUTTON_OFF
153 #define SNAKE2_LEVEL_UP BUTTON_UP
154 #define SNAKE2_LEVEL_DOWN BUTTON_DOWN
155 #define SNAKE2_MAZE_NEXT BUTTON_RIGHT
156 #define SNAKE2_SELECT_TYPE BUTTON_LEFT
157 #define SNAKE2_PLAYPAUSE BUTTON_MENU
158 #define SNAKE2_PLAYPAUSE_TEXT "Menu"
160 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
161 (CONFIG_KEYPAD == IRIVER_H300_PAD)
162 #define SNAKE2_LEFT BUTTON_LEFT
163 #define SNAKE2_RIGHT BUTTON_RIGHT
164 #define SNAKE2_UP BUTTON_UP
165 #define SNAKE2_DOWN BUTTON_DOWN
166 #define SNAKE2_QUIT BUTTON_OFF
167 #define SNAKE2_LEVEL_UP BUTTON_UP
168 #define SNAKE2_LEVEL_DOWN BUTTON_DOWN
169 #define SNAKE2_MAZE_NEXT BUTTON_RIGHT
170 #define SNAKE2_MAZE_LAST BUTTON_LEFT
171 #define SNAKE2_SELECT_TYPE BUTTON_MODE
172 #define SNAKE2_PLAYPAUSE BUTTON_ON
173 #define SNAKE2_PLAYPAUSE_TEXT "Play"
175 #define SNAKE2_RC_QUIT BUTTON_RC_STOP
176 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \
177 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
178 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
179 #define SNAKE2_LEFT BUTTON_LEFT
180 #define SNAKE2_RIGHT BUTTON_RIGHT
181 #define SNAKE2_UP BUTTON_MENU
182 #define SNAKE2_DOWN BUTTON_PLAY
183 #define SNAKE2_QUIT (BUTTON_SELECT | BUTTON_MENU)
184 #define SNAKE2_LEVEL_UP BUTTON_SCROLL_FWD
185 #define SNAKE2_LEVEL_DOWN BUTTON_SCROLL_BACK
186 #define SNAKE2_MAZE_NEXT BUTTON_RIGHT
187 #define SNAKE2_MAZE_LAST BUTTON_LEFT
188 #define SNAKE2_SELECT_TYPE BUTTON_PLAY
189 #define SNAKE2_PLAYPAUSE BUTTON_SELECT
190 #define SNAKE2_PLAYPAUSE_TEXT "Select"
192 #elif (CONFIG_KEYPAD == IAUDIO_X5M5_PAD)
193 #define SNAKE2_LEFT BUTTON_LEFT
194 #define SNAKE2_RIGHT BUTTON_RIGHT
195 #define SNAKE2_UP BUTTON_UP
196 #define SNAKE2_DOWN BUTTON_DOWN
197 #define SNAKE2_QUIT BUTTON_POWER
198 #define SNAKE2_LEVEL_UP BUTTON_UP
199 #define SNAKE2_LEVEL_DOWN BUTTON_DOWN
200 #define SNAKE2_MAZE_NEXT BUTTON_RIGHT
201 #define SNAKE2_MAZE_LAST BUTTON_LEFT
202 #define SNAKE2_SELECT_TYPE BUTTON_PLAY
203 #define SNAKE2_PLAYPAUSE BUTTON_SELECT
204 #define SNAKE2_PLAYPAUSE_TEXT "Select"
206 #elif (CONFIG_KEYPAD == GIGABEAT_PAD)
207 #define SNAKE2_LEFT BUTTON_LEFT
208 #define SNAKE2_RIGHT BUTTON_RIGHT
209 #define SNAKE2_UP BUTTON_UP
210 #define SNAKE2_DOWN BUTTON_DOWN
211 #define SNAKE2_QUIT BUTTON_POWER
212 #define SNAKE2_LEVEL_UP BUTTON_UP
213 #define SNAKE2_LEVEL_DOWN BUTTON_DOWN
214 #define SNAKE2_MAZE_NEXT BUTTON_RIGHT
215 #define SNAKE2_MAZE_LAST BUTTON_LEFT
216 #define SNAKE2_SELECT_TYPE BUTTON_MENU
217 #define SNAKE2_PLAYPAUSE BUTTON_SELECT
218 #define SNAKE2_PLAYPAUSE_TEXT "Select"
220 #elif (CONFIG_KEYPAD == SANSA_E200_PAD) || \
221 (CONFIG_KEYPAD == SANSA_C200_PAD)
222 #define SNAKE2_LEFT BUTTON_LEFT
223 #define SNAKE2_RIGHT BUTTON_RIGHT
224 #define SNAKE2_UP BUTTON_UP
225 #define SNAKE2_DOWN BUTTON_DOWN
226 #define SNAKE2_QUIT BUTTON_POWER
227 #define SNAKE2_LEVEL_UP BUTTON_UP
228 #define SNAKE2_LEVEL_DOWN BUTTON_DOWN
229 #define SNAKE2_MAZE_NEXT BUTTON_RIGHT
230 #define SNAKE2_MAZE_LAST BUTTON_LEFT
231 #define SNAKE2_SELECT_TYPE BUTTON_REC
232 #define SNAKE2_PLAYPAUSE BUTTON_SELECT
233 #define SNAKE2_PLAYPAUSE_TEXT "Select"
235 #elif (CONFIG_KEYPAD == IRIVER_H10_PAD)
236 #define SNAKE2_LEFT BUTTON_LEFT
237 #define SNAKE2_RIGHT BUTTON_RIGHT
238 #define SNAKE2_UP BUTTON_SCROLL_UP
239 #define SNAKE2_DOWN BUTTON_SCROLL_DOWN
240 #define SNAKE2_QUIT BUTTON_POWER
241 #define SNAKE2_LEVEL_UP BUTTON_SCROLL_UP
242 #define SNAKE2_LEVEL_DOWN BUTTON_SCROLL_DOWN
243 #define SNAKE2_MAZE_NEXT BUTTON_RIGHT
244 #define SNAKE2_MAZE_LAST BUTTON_LEFT
245 #define SNAKE2_SELECT_TYPE BUTTON_PLAY
246 #define SNAKE2_PLAYPAUSE BUTTON_FF
247 #define SNAKE2_PLAYPAUSE_TEXT "FF"
249 #elif (CONFIG_KEYPAD == GIGABEAT_S_PAD)
250 #define SNAKE2_LEFT BUTTON_LEFT
251 #define SNAKE2_RIGHT BUTTON_RIGHT
252 #define SNAKE2_UP BUTTON_UP
253 #define SNAKE2_DOWN BUTTON_DOWN
254 #define SNAKE2_QUIT BUTTON_BACK
255 #define SNAKE2_LEVEL_UP BUTTON_UP
256 #define SNAKE2_LEVEL_DOWN BUTTON_DOWN
257 #define SNAKE2_MAZE_NEXT BUTTON_RIGHT
258 #define SNAKE2_MAZE_LAST BUTTON_LEFT
259 #define SNAKE2_SELECT_TYPE BUTTON_MENU
260 #define SNAKE2_PLAYPAUSE BUTTON_SELECT
261 #define SNAKE2_PLAYPAUSE_TEXT "Select"
263 #elif (CONFIG_KEYPAD == MROBE100_PAD)
264 #define SNAKE2_LEFT BUTTON_LEFT
265 #define SNAKE2_RIGHT BUTTON_RIGHT
266 #define SNAKE2_UP BUTTON_UP
267 #define SNAKE2_DOWN BUTTON_DOWN
268 #define SNAKE2_QUIT BUTTON_POWER
269 #define SNAKE2_LEVEL_UP BUTTON_UP
270 #define SNAKE2_LEVEL_DOWN BUTTON_DOWN
271 #define SNAKE2_MAZE_NEXT BUTTON_RIGHT
272 #define SNAKE2_MAZE_LAST BUTTON_LEFT
273 #define SNAKE2_SELECT_TYPE BUTTON_MENU
274 #define SNAKE2_PLAYPAUSE BUTTON_SELECT
275 #define SNAKE2_PLAYPAUSE_TEXT "Select"
277 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
278 #define SNAKE2_LEFT BUTTON_RC_REW
279 #define SNAKE2_RIGHT BUTTON_RC_FF
280 #define SNAKE2_UP BUTTON_RC_VOL_UP
281 #define SNAKE2_DOWN BUTTON_RC_VOL_DOWN
282 #define SNAKE2_QUIT BUTTON_RC_REC
283 #define SNAKE2_LEVEL_UP BUTTON_RC_VOL_UP
284 #define SNAKE2_LEVEL_DOWN BUTTON_RC_VOL_DOWN
285 #define SNAKE2_MAZE_NEXT BUTTON_RC_FF
286 #define SNAKE2_MAZE_LAST BUTTON_RC_REW
287 #define SNAKE2_SELECT_TYPE BUTTON_RC_MODE
288 #define SNAKE2_PLAYPAUSE BUTTON_RC_PLAY
289 #define SNAKE2_PLAYPAUSE_TEXT "Play"
291 #elif (CONFIG_KEYPAD == COWOND2_PAD)
292 #define SNAKE2_QUIT BUTTON_POWER
294 #else
295 #error No keymap defined!
296 #endif
298 #ifdef HAVE_TOUCHPAD
299 #ifndef SNAKE2_LEFT
300 #define SNAKE2_LEFT BUTTON_MIDLEFT
301 #endif
302 #ifndef SNAKE2_RIGHT
303 #define SNAKE2_RIGHT BUTTON_MIDRIGHT
304 #endif
305 #ifndef SNAKE2_UP
306 #define SNAKE2_UP BUTTON_TOPMIDDLE
307 #endif
308 #ifndef SNAKE2_DOWN
309 #define SNAKE2_DOWN BUTTON_BOTTOMMIDDLE
310 #endif
311 #ifndef SNAKE2_QUIT
312 #define SNAKE2_QUIT BUTTON_TOPLEFT
313 #endif
314 #ifndef SNAKE2_LEVEL_UP
315 #define SNAKE2_LEVEL_UP BUTTON_TOPRIGHT
316 #endif
317 #ifndef SNAKE2_LEVEL_DOWN
318 #define SNAKE2_LEVEL_DOWN BUTTON_TOPLEFT
319 #endif
320 #ifndef SNAKE2_MAZE_NEXT
321 #define SNAKE2_MAZE_NEXT BUTTON_TOPMIDDLE
322 #endif
323 #ifndef SNAKE2_MAZE_LAST
324 #define SNAKE2_MAZE_LAST BUTTON_BOTTOMMIDDLE
325 #endif
326 #ifndef SNAKE2_SELECT_TYPE
327 #define SNAKE2_SELECT_TYPE BUTTON_BOTTOMLEFT
328 #endif
329 #ifndef SNAKE2_PLAYPAUSE
330 #define SNAKE2_PLAYPAUSE BUTTON_CENTER
331 #endif
332 #ifndef SNAKE2_PLAYPAUSE_TEXT
333 #define SNAKE2_PLAYPAUSE_TEXT "CENTER"
334 #endif
335 #endif
337 static int max_levels = 0;
338 static char (*level_cache)[HEIGHT][WIDTH];
340 /*Board itself - 2D int array*/
341 static int board[WIDTH][HEIGHT];
343 Buffer for sorting movement (in case user presses two movements during a
344 single frame
346 static int ardirectionbuffer[2];
347 static unsigned int score, hiscore = 0;
348 static int applex;
349 static int appley;
350 static int strwdt,strhgt; /*used for string width, height for orientation purposes*/
351 static int dir;
352 static int frames;
353 static int apple;
354 static int level = 4, speed = 5,dead = 0, quit = 0;
355 static int sillydir = 0, num_levels = 0;
356 static int level_from_file = 0;
357 static struct plugin_api* rb;
358 static int headx, heady, tailx, taily, applecountdown = 5;
359 static int game_type = 0;
360 static int num_apples_to_get=1;
361 static int num_apples_to_got=0;
362 static int game_b_level=0;
363 static int applecount=0;
364 static char phscore[30];
366 #define NORTH 1
367 #define EAST 2
368 #define SOUTH 4
369 #define WEST 8
370 #define HEAD 16
372 #define EAST_NORTH 32
373 #define EAST_SOUTH 64
374 #define WEST_NORTH 128
375 #define WEST_SOUTH 256
377 #define NORTH_EAST 512
378 #define NORTH_WEST 1024
379 #define SOUTH_EAST 2048
380 #define SOUTH_WEST 4096
382 #define LEVELS_FILE PLUGIN_GAMES_DIR "/snake2.levels"
383 #define HISCORE_FILE PLUGIN_GAMES_DIR "/snake2.hs"
385 int load_all_levels(void)
387 int linecnt = 0;
388 int fd;
389 ssize_t size;
390 char buf[64]; /* Larger than WIDTH, to allow for whitespace after the
391 lines */
393 /* Init the level_cache pointer and
394 calculate how many levels that will fit */
395 level_cache = rb->plugin_get_buffer((size_t *)&size);
396 max_levels = size / (HEIGHT*WIDTH);
398 num_levels = 0;
400 /* open file */
401 if ((fd = rb->open(LEVELS_FILE, O_RDONLY)) < 0)
403 return -1;
406 while(rb->read_line(fd, buf, 64))
408 if(rb->strlen(buf) == 0) /* Separator? */
410 num_levels++;
411 if(num_levels > max_levels)
413 rb->splash(HZ, "Too many levels in file");
414 break;
416 continue;
419 rb->memcpy(level_cache[num_levels][linecnt], buf, WIDTH);
420 linecnt++;
421 if(linecnt == HEIGHT)
423 linecnt = 0;
427 rb->close(fd);
428 return 0;
431 /*Hi-Score reading and writing to file "/.rockbox/rocks/games/snake2.levels" function */
432 void iohiscore(void)
434 int fd;
435 unsigned int compare;
437 /* clear the buffer we're about to load the highscore data into */
438 rb->memset(phscore, 0, sizeof(phscore));
440 fd = rb->open(HISCORE_FILE,O_RDWR | O_CREAT);
442 /* highscore used to %d, is now %d\n
443 Deal with no file or bad file */
444 rb->read(fd,phscore, sizeof(phscore));
446 compare = rb->atoi(phscore);
448 if(hiscore > compare){
449 rb->lseek(fd,0,SEEK_SET);
450 rb->fdprintf(fd, "%d\n", hiscore);
452 else
453 hiscore = compare;
455 rb->close(fd);
460 ** Completely clear the board of walls and/or snake */
462 void clear_board( void)
464 int x,y;
466 for (x = 0; x < WIDTH; x++)
468 for (y = 0; y < HEIGHT; y++)
470 board[x][y] = 0;
475 int load_level( int level_number )
477 int x,y;
478 clear_board();
479 for(y = 0;y < HEIGHT;y++)
481 for(x = 0;x < WIDTH;x++)
483 switch(level_cache[level_number][y][x])
485 case '|':
486 board[x][y] = NORTH;
487 break;
489 case '-':
490 board[x][y] = EAST;
491 break;
493 case '+':
494 board[x][y] = HEAD;
495 break;
499 return 1;
503 ** Gets the currently chosen direction from the first place
504 ** in the direction buffer. If there is something in the
505 ** next part of the buffer then that is moved to the first place
507 void get_direction( void )
509 /*if 1st place is empty*/
510 if(ardirectionbuffer[0] != -1)
512 /*return this direction*/
513 dir = ardirectionbuffer[0];
514 ardirectionbuffer[0]=-1;
515 /*now see if one needs moving:*/
516 if(ardirectionbuffer[1] != -1)
518 /*there's a move waiting to be done
519 so move it into the space:*/
520 ardirectionbuffer[0] = ardirectionbuffer[1];
521 ardirectionbuffer[1] = -1;
527 ** Sets the direction
529 void set_direction(int newdir)
531 if(ardirectionbuffer[0] != newdir)
533 /*if 1st place is empty*/
534 if(ardirectionbuffer[0] == -1)
536 /*use 1st space:*/
537 ardirectionbuffer[0] = newdir;
539 else
541 /*use 2nd space:*/
542 if(ardirectionbuffer[0] != newdir) ardirectionbuffer[1] = newdir;
545 if(frames < 0) ardirectionbuffer[0] = newdir;
549 void new_level(int level)
551 load_level(level);
553 ardirectionbuffer[0] = -1;
554 ardirectionbuffer[1] = -1;
555 dir = EAST;
556 headx = WIDTH/2;
557 heady = HEIGHT/2;
558 tailx = headx - 4;
559 taily = heady;
560 applecountdown = 0;
561 /*Create a small snake to start off with*/
562 board[headx][heady] = dir;
563 board[headx-1][heady] = dir;
564 board[headx-2][heady] = dir;
565 board[headx-3][heady] = dir;
566 board[headx-4][heady] = dir;
567 num_apples_to_got=0;
570 void init_snake(void)
572 num_apples_to_get=1;
573 if(game_type == 1)
574 level_from_file = 1;
575 game_b_level=1;
576 new_level(level_from_file);
580 ** Draws the apple. If it doesn't exist then
581 ** a new one get's created.
583 void draw_apple( void )
585 int x,y;
587 #if LCD_WIDTH >= 160 && LCD_HEIGHT >= 128
588 char pscore[5], counter[4];
590 rb->lcd_bitmap(snake2_header2,0,0,BMPWIDTH_snake2_header, BMPHEIGHT_snake2_header);
591 rb->lcd_bitmap(snake2_left,0,BMPHEIGHT_snake2_header,BMPWIDTH_snake2_left, BMPHEIGHT_snake2_left);
592 rb->lcd_bitmap(snake2_right,LCD_WIDTH-BMPWIDTH_snake2_right,BMPHEIGHT_snake2_header,BMPWIDTH_snake2_right, BMPHEIGHT_snake2_right);
593 rb->lcd_bitmap(snake2_bottom,0,BMPHEIGHT_snake2_header+BMPHEIGHT_snake2_left,BMPWIDTH_snake2_bottom, BMPHEIGHT_snake2_bottom);
595 rb->snprintf(counter,sizeof(counter),"%d",applecount);
596 rb->lcd_getstringsize(counter,&strwdt,&strhgt);
597 rb->lcd_putsxy(TOP_X3-strwdt/2,TOP_Y2,counter);
599 rb->snprintf(pscore,sizeof(pscore),"%d",score);
600 rb->lcd_getstringsize(pscore,&strwdt,&strhgt);
601 rb->lcd_putsxy(TOP_X4-strwdt/2,TOP_Y2,pscore);
602 #endif
604 if (!apple)
608 x = (rb->rand() % (WIDTH-1))+1;
609 y = (rb->rand() % (HEIGHT-1))+1;
610 } while (board[x][y]);
611 apple=1;
612 board[x][y]=-1;
613 applex = x;appley = y;
615 rb->lcd_fillrect((CENTER_X+applex*MULTIPLIER)+1,CENTER_Y+appley*MULTIPLIER,MODIFIER_2,MODIFIER_1);
616 rb->lcd_fillrect(CENTER_X+applex*MULTIPLIER,(CENTER_Y+appley*MULTIPLIER)+1,MODIFIER_1,MODIFIER_2);
620 * x x *
621 * x x *
622 * x x *
623 * x x *
625 void draw_vertical_bit(int x, int y)
627 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER+1,CENTER_Y+y*MULTIPLIER,MODIFIER_2,MODIFIER_1);
631 * * * *
632 X X X X
633 X X X X
634 * * * *
636 void draw_horizontal_bit(int x, int y)
638 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER,CENTER_Y+y*MULTIPLIER+1,MODIFIER_1,MODIFIER_2);
642 * * * *
643 * * X X
644 * X X X
645 * X X *
647 void draw_n_to_e_bit(int x, int y)
649 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER+1,CENTER_Y+y*MULTIPLIER+2,MODIFIER_2,MODIFIER_2);
650 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER+2,CENTER_Y+y*MULTIPLIER+1,MODIFIER_2,MODIFIER_2);
654 * * * *
655 * * X X
656 * X X X
657 * X X *
659 void draw_w_to_s_bit(int x, int y)
661 draw_n_to_e_bit(x,y);
665 * * * *
666 X X * *
667 X X X *
668 * X X *
670 void draw_n_to_w_bit(int x, int y)
672 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER,CENTER_Y+y*MULTIPLIER+1,MODIFIER_2,MODIFIER_2);
673 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER+1,CENTER_Y+y*MULTIPLIER+2,MODIFIER_2,MODIFIER_2);
677 * * * *
678 X X * *
679 X X X *
680 * X X *
682 void draw_e_to_s_bit(int x, int y)
684 draw_n_to_w_bit(x, y);
688 * X X *
689 * X X X
690 * * X X
691 * * * *
693 void draw_s_to_e_bit(int x, int y)
695 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER+1,CENTER_Y+y*MULTIPLIER,MODIFIER_2,MODIFIER_2);
696 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER+2,CENTER_Y+y*MULTIPLIER+1,MODIFIER_2,MODIFIER_2);
700 * X X *
701 * X X X
702 * * X X
703 * * * *
705 void draw_w_to_n_bit(int x, int y)
707 draw_s_to_e_bit(x,y);
711 * X X *
712 X X X *
713 X X * *
714 * * * *
716 void draw_e_to_n_bit(int x, int y)
718 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER+1,CENTER_Y+y*MULTIPLIER,MODIFIER_2,MODIFIER_2);
719 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER,CENTER_Y+y*MULTIPLIER+1,MODIFIER_2,MODIFIER_2);
723 * X X *
724 X X X *
725 X X * *
726 * * * *
728 void draw_s_to_w_bit(int x, int y)
730 draw_e_to_n_bit(x, y);
734 ** Draws a wall/obsticals
736 void draw_boundary ( void )
738 int x, y;
740 /*TODO: Load levels from file!*/
742 /*top and bottom line*/
743 for(x=0; x < WIDTH; x++)
745 board[x][0] = EAST;
746 board[x][HEIGHT-1] = WEST;
749 /*left and right lines*/
750 for(y=0; y < HEIGHT; y++)
752 board[0][y] = NORTH;
753 board[WIDTH-1][y] = SOUTH;
756 /*corners:*/
757 board[0][0] = NORTH_EAST;
758 board[WIDTH-1][0] = EAST_SOUTH;
759 board[0][HEIGHT-1] = SOUTH_EAST;
760 board[WIDTH-1][HEIGHT-1] = EAST_NORTH;
764 ** Redraw the entire board
766 void redraw (void)
768 int x,y;
770 for (x = 0; x < WIDTH; x++)
772 for (y = 0; y < HEIGHT; y++)
774 switch (board[x][y])
776 case -1:
777 rb->lcd_fillrect((CENTER_X+x*MULTIPLIER)+1,CENTER_Y+y*MULTIPLIER,MODIFIER_2,MODIFIER_1);
778 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER,(CENTER_Y+y*MULTIPLIER)+1,MODIFIER_1,MODIFIER_2);
779 break;
780 case 0:
781 break;
783 case NORTH:
784 case SOUTH:
785 draw_vertical_bit(x,y);
786 break;
788 case EAST:
789 case WEST:
790 draw_horizontal_bit(x,y);
791 break;
793 default:
794 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER,CENTER_Y+y*MULTIPLIER,MODIFIER_1,MODIFIER_1);
795 break;
802 ** Draws the snake bit described by nCurrentBit at position x/y
803 ** deciding whether it's a corner bit by examing the nPrevious bit
805 void draw_snake_bit(int currentbit, int previousbit, int x, int y)
807 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
808 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER,CENTER_Y+y*MULTIPLIER,MODIFIER_1,MODIFIER_1);
809 rb->lcd_set_drawmode(DRMODE_SOLID);
811 switch(currentbit)
813 case(NORTH):
814 switch(previousbit)
816 case(SOUTH):
817 case(NORTH):
818 draw_vertical_bit(x,y);
819 break;
821 case(EAST):
822 draw_e_to_n_bit(x,y);
823 break;
825 case(WEST):
826 draw_w_to_n_bit(x,y);
827 break;
829 break;
831 case(EAST):
832 switch(previousbit)
834 case(WEST):
835 case(EAST):
836 draw_horizontal_bit(x,y);
837 break;
839 case(NORTH):
840 draw_n_to_e_bit(x,y);
841 break;
843 case(SOUTH):
844 draw_s_to_e_bit(x,y);
845 break;
847 break;
849 case(SOUTH):
850 switch(previousbit)
852 case(SOUTH):
853 case(NORTH):
854 draw_vertical_bit(x,y);
855 break;
857 case(EAST):
858 draw_e_to_s_bit(x,y);
859 break;
861 case(WEST):
862 draw_w_to_s_bit(x,y);
863 break;
865 break;
867 case(WEST):
868 switch(previousbit)
870 case(EAST):
871 case(WEST):
872 draw_horizontal_bit(x,y);
873 break;
875 case(SOUTH):
876 draw_s_to_w_bit(x,y);
877 break;
879 case(NORTH):
880 draw_n_to_w_bit(x,y);
881 break;
883 break;
888 ** Death 'sequence' and end game stuff.
890 void die (void)
892 int button;
893 bool done=false;
894 char pscore[20];
896 rb->splash(HZ*2, "Oops!");
898 rb->lcd_clear_display();
900 applecount=0;
902 rb->lcd_getstringsize("You died!",&strwdt,&strhgt);
903 rb->lcd_putsxy((LCD_WIDTH - strwdt)/2,strhgt,"You died!");
905 rb->snprintf(pscore,sizeof(pscore),"Your score: %d",score);
906 rb->lcd_getstringsize(pscore,&strwdt,&strhgt);
907 rb->lcd_putsxy((LCD_WIDTH - strwdt)/2,strhgt * 2 + 2,pscore);
909 if (score>hiscore)
911 hiscore=score;
912 rb->lcd_getstringsize("New high score!",&strwdt,&strhgt);
913 rb->lcd_putsxy((LCD_WIDTH - strwdt)/2,strhgt * 4 + 2,"New high score!");
915 else
917 rb->snprintf(phscore,sizeof(phscore),"High score: %d",hiscore);
918 rb->lcd_getstringsize(phscore,&strwdt,&strhgt);
919 rb->lcd_putsxy((LCD_WIDTH - strwdt)/2,strhgt * 5,phscore);
922 rb->snprintf(phscore,sizeof(phscore),"Press %s...",SNAKE2_PLAYPAUSE_TEXT);
923 rb->lcd_getstringsize(phscore,&strwdt,&strhgt);
924 rb->lcd_putsxy((LCD_WIDTH - strwdt)/2,strhgt * 7,phscore);
926 rb->lcd_update();
928 while(!done)
930 button=rb->button_get(true);
931 switch(button)
933 case SNAKE2_PLAYPAUSE:
934 done = true;
935 break;
939 dead=1;
943 ** Check for collision. TODO: Currently this
944 ** sets of the death sequence. What we want is it to only return a true/false
945 ** depending on whether a collision occured.
947 void collision ( int x, int y )
949 int bdeath=0;
952 switch (board[x][y])
954 case 0:
956 break;
957 case -1:
958 score = score + (1 * level);
959 apple=0;
960 applecountdown=2;
961 applecount++;
963 if(game_type==1)
965 if(num_apples_to_get == num_apples_to_got)
967 level_from_file++;
968 if(level_from_file >= num_levels)
970 level_from_file = 1;
971 /*and increase the number of apples to pick up
972 before level changes*/
973 num_apples_to_get+=2;
974 game_b_level++;
976 rb->splash(HZ, "Level Completed!");
977 rb->lcd_clear_display();
978 new_level(level_from_file);
979 rb->lcd_clear_display();
980 redraw();
981 rb->lcd_update();
983 else
984 num_apples_to_got++;
986 break;
987 default:
988 bdeath=1;
989 break;
992 if(bdeath==1)
994 die();
995 sillydir = dir;
996 frames = -110;
1000 void move( void )
1002 int taildir;
1003 /*this actually sets the dir variable.*/
1004 get_direction();
1005 /*draw head*/
1006 switch (dir)
1008 case (NORTH):
1009 board[headx][heady]=NORTH;
1010 heady--;
1011 break;
1012 case (EAST):
1013 board[headx][heady]=EAST;
1014 headx++;
1015 break;
1016 case (SOUTH):
1017 board[headx][heady]=SOUTH;
1018 heady++;
1019 break;
1020 case (WEST):
1021 board[headx][heady]=WEST;
1022 headx--;
1023 break;
1026 if(headx == WIDTH)
1027 headx = 0;
1028 else if(headx < 0)
1029 headx = WIDTH-1;
1031 if(heady == HEIGHT)
1032 heady = 0;
1033 else if(heady < 0)
1034 heady = HEIGHT-1;
1036 rb->lcd_fillrect(CENTER_X+headx*MULTIPLIER,CENTER_Y+heady*MULTIPLIER,MODIFIER_1,MODIFIER_1);
1038 /*clear tail*/
1039 if(applecountdown <= 0)
1041 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
1042 rb->lcd_fillrect(CENTER_X+tailx*MULTIPLIER,CENTER_Y+taily*MULTIPLIER,MODIFIER_1,MODIFIER_1);
1043 rb->lcd_set_drawmode(DRMODE_SOLID);
1045 taildir = board[tailx][taily];
1046 board[tailx][taily] = 0;
1048 switch (taildir)
1050 case(NORTH):
1051 taily--;
1052 break;
1054 case(EAST):
1055 tailx++;
1056 break;
1058 case(SOUTH):
1059 taily++;
1060 break;
1062 case(WEST):
1063 tailx--;
1064 break;
1067 if(tailx == WIDTH)
1068 tailx = 0;
1069 else if(tailx < 0)
1070 tailx = WIDTH-1;
1072 if(taily == HEIGHT)
1073 taily = 0;
1074 else if(taily < 0)
1075 taily = HEIGHT-1;
1077 else
1078 applecountdown--;
1081 void frame (void)
1083 int olddir, noldx, noldy, temp;
1084 noldx = headx;
1085 noldy = heady;
1086 olddir = 0;
1087 switch(dir)
1089 case(NORTH):
1090 if(heady == HEIGHT-1)
1091 temp = 0;
1092 else
1093 temp = heady + 1;
1095 olddir = board[headx][temp];
1096 break;
1098 case(EAST):
1099 if(headx == 0)
1100 temp = WIDTH-1;
1101 else
1102 temp = headx - 1;
1104 olddir = board[temp][heady];
1105 break;
1107 case(SOUTH):
1108 if(heady == 0)
1109 temp = HEIGHT-1;
1110 else
1111 temp = heady - 1;
1113 olddir = board[headx][temp];
1114 break;
1116 case(WEST):
1117 if(headx == WIDTH-1)
1118 temp = 0;
1119 else
1120 temp = headx + 1;
1122 olddir = board[temp][heady];
1123 break;
1126 move();
1129 now redraw the bit that was
1130 the tail, to something snake-like:
1132 draw_snake_bit(dir, olddir, noldx, noldy);
1134 collision(headx, heady);
1136 rb->lcd_update();
1139 void game_pause (void)
1141 int button;
1143 rb->lcd_clear_display();
1144 rb->lcd_getstringsize("Paused",&strwdt,&strhgt);
1145 rb->lcd_putsxy((LCD_WIDTH - strwdt)/2,LCD_HEIGHT/2,"Paused");
1147 rb->lcd_update();
1148 while (1)
1150 button = rb->button_get(true);
1151 switch (button)
1153 case SNAKE2_PLAYPAUSE:
1154 rb->lcd_clear_display();
1155 redraw();
1156 rb->lcd_update();
1157 rb->sleep(HZ/2);
1158 return;
1160 #ifdef SNAKE2_RC_QUIT
1161 case SNAKE2_RC_QUIT:
1162 #endif
1163 case SNAKE2_QUIT:
1164 dead = 1;
1165 quit = 1;
1166 return;
1168 default:
1169 if (rb->default_event_handler(button)==SYS_USB_CONNECTED) {
1170 dead = 1;
1171 quit = 2;
1172 return;
1174 break;
1179 void game (void)
1181 int button;
1183 rb->lcd_clear_display();
1184 redraw();
1185 rb->lcd_update();
1186 /*main loop:*/
1187 while (1)
1189 if(frames==5)
1191 frame();
1192 if(frames>0) frames=0;
1194 frames++;
1196 if(frames == 0)
1198 die();
1200 else
1202 if(frames < 0)
1204 if(sillydir != dir)
1206 /*it has, great set frames to a positive value again:*/
1207 frames = 1;
1212 if (dead) return;
1214 draw_apple();
1216 rb->sleep(HZ/speed);
1218 button = rb->button_get(false);
1220 #ifdef HAS_BUTTON_HOLD
1221 if (rb->button_hold())
1222 button = SNAKE2_PLAYPAUSE;
1223 #endif
1225 switch (button)
1227 case SNAKE2_UP:
1228 case SNAKE2_UP | BUTTON_REPEAT:
1229 if (dir != SOUTH) set_direction(NORTH);
1230 break;
1232 case SNAKE2_RIGHT:
1233 case SNAKE2_RIGHT | BUTTON_REPEAT:
1234 if (dir != WEST) set_direction(EAST);
1235 break;
1237 case SNAKE2_DOWN:
1238 case SNAKE2_DOWN | BUTTON_REPEAT:
1239 if (dir != NORTH) set_direction(SOUTH);
1240 break;
1242 case SNAKE2_LEFT:
1243 case SNAKE2_LEFT | BUTTON_REPEAT:
1244 if (dir != EAST) set_direction(WEST);
1245 break;
1247 #ifdef SNAKE2_RC_QUIT
1248 case SNAKE2_RC_QUIT:
1249 #endif
1250 case SNAKE2_QUIT:
1251 dead=1;
1252 return;
1254 case SNAKE2_PLAYPAUSE:
1255 game_pause();
1256 break;
1258 default:
1259 if (rb->default_event_handler(button)==SYS_USB_CONNECTED) {
1260 quit = 2;
1261 return;
1263 break;
1269 void game_init(void)
1271 int button;
1272 char plevel[30];
1274 dead=0;
1275 apple=0;
1276 score=0;
1277 applecount=0;
1279 clear_board();
1280 load_level( level_from_file );
1281 rb->lcd_clear_display();
1282 redraw();
1283 rb->lcd_update();
1285 while (1)
1287 #if LCD_WIDTH >= 160 && LCD_HEIGHT >= 128
1289 rb->lcd_bitmap(snake2_header1,0,0,BMPWIDTH_snake2_header, BMPHEIGHT_snake2_header);
1290 rb->lcd_bitmap(snake2_left,0,BMPHEIGHT_snake2_header,BMPWIDTH_snake2_left, BMPHEIGHT_snake2_left);
1291 rb->lcd_bitmap(snake2_right,LCD_WIDTH-BMPWIDTH_snake2_right,BMPHEIGHT_snake2_header,BMPWIDTH_snake2_right, BMPHEIGHT_snake2_right);
1292 rb->lcd_bitmap(snake2_bottom,0,BMPHEIGHT_snake2_header+BMPHEIGHT_snake2_left,BMPWIDTH_snake2_bottom, BMPHEIGHT_snake2_bottom);
1294 rb->snprintf(plevel,sizeof(plevel),"%d",level);
1295 rb->lcd_getstringsize(plevel,&strwdt,&strhgt);
1296 rb->lcd_putsxy(TOP_X3-strwdt/2,TOP_Y2, plevel);
1298 rb->snprintf(plevel,sizeof(plevel),"%d",level_from_file);
1299 rb->lcd_getstringsize(plevel,&strwdt,&strhgt);
1300 rb->lcd_putsxy(TOP_X2-strwdt/2,TOP_Y1, plevel);
1302 if(game_type==0){
1303 rb->lcd_getstringsize("A",&strwdt,&strhgt);
1304 rb->lcd_putsxy(TOP_X1,TOP_Y1,"A");
1306 else{
1307 rb->lcd_getstringsize("B",&strwdt,&strhgt);
1308 rb->lcd_putsxy(TOP_X1,TOP_Y1,"B");
1311 rb->snprintf(phscore,sizeof(phscore),"%d",hiscore);
1312 rb->lcd_getstringsize(phscore,&strwdt,&strhgt);
1313 rb->lcd_putsxy(TOP_X4-strwdt/2,TOP_Y2, phscore);
1315 #else
1316 rb->snprintf(plevel,sizeof(plevel),"Speed: %02d",level);
1317 rb->lcd_getstringsize("Speed: 00",&strwdt,&strhgt);
1318 rb->lcd_putsxy((LCD_WIDTH - strwdt)/2,strhgt+4, plevel);
1320 rb->snprintf(plevel,sizeof(plevel),"Maze: %d",level_from_file);
1321 rb->lcd_getstringsize(plevel,&strwdt,&strhgt);
1322 rb->lcd_putsxy((LCD_WIDTH - strwdt)/2,strhgt*2+4, plevel);
1324 if(game_type==0){
1325 rb->lcd_getstringsize("Game Type: A ",&strwdt,&strhgt);
1326 rb->lcd_putsxy((LCD_WIDTH - strwdt)/2,strhgt*3+4,"Game Type: A");
1328 else{
1329 rb->lcd_getstringsize("Game Type: B ",&strwdt,&strhgt);
1330 rb->lcd_putsxy((LCD_WIDTH - strwdt)/2,strhgt*3+4,"Game Type: B");
1333 rb->snprintf(phscore,sizeof(phscore),"Hi Score: %d",hiscore);
1334 rb->lcd_getstringsize(phscore,&strwdt,&strhgt);
1335 rb->lcd_putsxy((LCD_WIDTH - strwdt)/2,strhgt*4+4, phscore);
1336 #endif
1338 rb->lcd_update();
1340 button=rb->button_get(true);
1341 switch (button)
1343 case SNAKE2_LEVEL_UP:
1344 case SNAKE2_LEVEL_UP|BUTTON_REPEAT:
1345 if (level<10)
1346 level+=1;
1347 break;
1348 case SNAKE2_LEVEL_DOWN:
1349 case SNAKE2_LEVEL_DOWN|BUTTON_REPEAT:
1350 if (level>1)
1351 level-=1;
1352 break;
1353 case SNAKE2_QUIT:
1354 quit=1;
1355 return;
1356 break;
1357 case SNAKE2_PLAYPAUSE:
1358 speed = level*20;
1359 return;
1360 break;
1361 case SNAKE2_SELECT_TYPE:
1362 if(game_type==0)game_type=1; else game_type=0;
1363 break;
1364 case SNAKE2_MAZE_NEXT:
1365 rb->lcd_set_drawmode(DRMODE_BG|DRMODE_INVERSEVID);
1366 rb->lcd_fillrect(CENTER_X, CENTER_Y, CENTER_X+WIDTH*MULTIPLIER,
1367 CENTER_Y+HEIGHT*MULTIPLIER);
1368 rb->lcd_set_drawmode(DRMODE_SOLID);
1369 if(level_from_file < num_levels)
1370 level_from_file++;
1371 else
1372 level_from_file = 0;
1373 load_level( level_from_file );
1374 redraw();
1375 break;
1376 #ifdef SNAKE2_MAZE_LAST
1377 case SNAKE2_MAZE_LAST:
1378 rb->lcd_set_drawmode(DRMODE_BG|DRMODE_INVERSEVID);
1379 rb->lcd_fillrect(CENTER_X, CENTER_Y, CENTER_X+WIDTH*MULTIPLIER,
1380 CENTER_Y+HEIGHT*MULTIPLIER);
1381 rb->lcd_set_drawmode(DRMODE_SOLID);
1382 if(level_from_file > 0)
1383 level_from_file--;
1384 else
1385 level_from_file = num_levels;
1386 load_level( level_from_file );
1387 redraw();
1388 break;
1389 #endif
1390 default:
1391 if (rb->default_event_handler(button)==SYS_USB_CONNECTED) {
1392 quit = 2;
1393 return;
1395 break;
1401 enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
1403 (void)(parameter);
1404 rb = api;
1406 /* Lets use the default font */
1407 rb->lcd_setfont(FONT_SYSFIXED);
1408 #if LCD_DEPTH > 1
1409 rb->lcd_set_backdrop(NULL);
1410 #endif
1411 #ifdef HAVE_LCD_COLOR
1412 rb->lcd_set_foreground(LCD_BLACK);
1413 rb->lcd_set_background(LCD_WHITE);
1414 #endif
1416 load_all_levels();
1418 if (num_levels == 0) {
1419 rb->splash(HZ*2, "Failed loading levels!");
1420 return PLUGIN_OK;
1423 iohiscore();
1425 while(quit==0)
1427 game_init();
1428 rb->lcd_clear_display();
1429 frames=1;
1431 if(quit==0)
1433 init_snake();
1435 /*Start Game:*/
1436 game();
1440 iohiscore();
1441 return (quit==1) ? PLUGIN_OK : PLUGIN_USB_CONNECTED;
1444 #endif