Add 2008 to the copyright notice.
[Rockbox.git] / apps / plugins / snake2.c
blobd2eb89f2b4a06bb81d0e9175a1d39fb26692862f
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 >= 320) && (LCD_HEIGHT >= 240)
39 #define MULTIPLIER 10 /*Modifier for porting on other screens*/
40 #define MODIFIER_1 10
41 #define MODIFIER_2 8
42 #define CENTER_X 20
43 #define CENTER_Y 55
44 #define TOP_X1 34 /* x-coord of the upperleft item (game type) */
45 #define TOP_X2 281 /* x-coord of the upperright item (maze type) */
46 #define TOP_X3 42 /* x-coord of the lowerleft item (speed) */
47 #define TOP_X4 274 /* x-coord of the lowerright item (hi-score) */
48 #define TOP_Y1 4 /* y-coord of the top row of items */
49 #define TOP_Y2 25 /* y-coord of the bottom row of items */
50 #define BMPHEIGHT_snake2_header 38
51 #define BMPWIDTH_snake2_header 320
52 #define BMPHEIGHT_snake2_right 192
53 #define BMPWIDTH_snake2_right 10
54 #define BMPHEIGHT_snake2_left 192
55 #define BMPWIDTH_snake2_left 10
56 #define BMPHEIGHT_snake2_bottom 10
57 #define BMPWIDTH_snake2_bottom 320
58 #elif (LCD_WIDTH >= 240) && (LCD_HEIGHT >= 168)
59 #define MULTIPLIER 8
60 #define MODIFIER_1 8
61 #define MODIFIER_2 6
62 #define CENTER_X 8
63 #define CENTER_Y 34
64 #define TOP_X1 34
65 #define TOP_X2 201
66 #define TOP_X3 42
67 #define TOP_X4 194
68 #define TOP_Y1 4
69 #define TOP_Y2 25
70 #define BMPHEIGHT_snake2_header 38
71 #define BMPWIDTH_snake2_header 240
72 #define BMPHEIGHT_snake2_right 120
73 #define BMPWIDTH_snake2_right 10
74 #define BMPHEIGHT_snake2_left 120
75 #define BMPWIDTH_snake2_left 10
76 #define BMPHEIGHT_snake2_bottom 10
77 #define BMPWIDTH_snake2_bottom 240
78 #elif (LCD_WIDTH >= 220) && (LCD_HEIGHT >= 176)
79 #define MULTIPLIER 7
80 #define MODIFIER_1 7
81 #define MODIFIER_2 5
82 #define CENTER_X 12
83 #define CENTER_Y 46
84 #define TOP_X1 34
85 #define TOP_X2 181
86 #define TOP_X3 42
87 #define TOP_X4 174
88 #define TOP_Y1 4
89 #define TOP_Y2 25
90 #define BMPHEIGHT_snake2_header 38
91 #define BMPWIDTH_snake2_header 220
92 #define BMPHEIGHT_snake2_right 128
93 #define BMPWIDTH_snake2_right 10
94 #define BMPHEIGHT_snake2_left 128
95 #define BMPWIDTH_snake2_left 10
96 #define BMPHEIGHT_snake2_bottom 10
97 #define BMPWIDTH_snake2_bottom 220
98 #elif (LCD_WIDTH >= 176) && (LCD_HEIGHT >= 132)
99 #define MULTIPLIER 5
100 #define MODIFIER_1 5
101 #define MODIFIER_2 3
102 #define CENTER_X 18
103 #define CENTER_Y 40
104 #define TOP_X1 34
105 #define TOP_X2 137
106 #define TOP_X3 42
107 #define TOP_X4 130
108 #define TOP_Y1 4
109 #define TOP_Y2 25
110 #define BMPHEIGHT_snake2_header 38
111 #define BMPWIDTH_snake2_header 176
112 #define BMPHEIGHT_snake2_right 84
113 #define BMPWIDTH_snake2_right 10
114 #define BMPHEIGHT_snake2_left 84
115 #define BMPWIDTH_snake2_left 10
116 #define BMPHEIGHT_snake2_bottom 10
117 #define BMPWIDTH_snake2_bottom 176
118 #elif (LCD_WIDTH >= 160) && (LCD_HEIGHT >= 128)
119 #define MULTIPLIER 5
120 #define MODIFIER_1 5
121 #define MODIFIER_2 3
122 #define CENTER_X 10
123 #define CENTER_Y 38
124 #define TOP_X1 34
125 #define TOP_X2 121
126 #define TOP_X3 42
127 #define TOP_X4 114
128 #define TOP_Y1 4
129 #define TOP_Y2 25
130 #define BMPHEIGHT_snake2_header 38
131 #define BMPWIDTH_snake2_header 160
132 #define BMPHEIGHT_snake2_right 80
133 #define BMPWIDTH_snake2_right 10
134 #define BMPHEIGHT_snake2_left 80
135 #define BMPWIDTH_snake2_left 10
136 #define BMPHEIGHT_snake2_bottom 10
137 #define BMPWIDTH_snake2_bottom 160
138 #else
139 #define MULTIPLIER 4
140 #define MODIFIER_1 4
141 #define MODIFIER_2 2
142 #define CENTER_X 0
143 #define CENTER_Y 0
145 #endif
147 /* variable button definitions */
148 #if CONFIG_KEYPAD == RECORDER_PAD
149 #define SNAKE2_UP BUTTON_UP
150 #define SNAKE2_DOWN BUTTON_DOWN
151 #define SNAKE2_QUIT BUTTON_OFF
152 #define SNAKE2_LEVEL_UP BUTTON_UP
153 #define SNAKE2_LEVEL_DOWN BUTTON_DOWN
154 #define SNAKE2_MAZE_NEXT BUTTON_RIGHT
155 #define SNAKE2_MAZE_LAST BUTTON_LEFT
156 #define SNAKE2_SELECT_TYPE BUTTON_F3
157 #define SNAKE2_PLAYPAUSE BUTTON_PLAY
158 #define SNAKE2_PLAYPAUSE_TEXT "Play"
160 #elif CONFIG_KEYPAD == ARCHOS_AV300_PAD
161 #define SNAKE2_UP BUTTON_UP
162 #define SNAKE2_DOWN BUTTON_DOWN
163 #define SNAKE2_QUIT BUTTON_OFF
164 #define SNAKE2_LEVEL_UP BUTTON_UP
165 #define SNAKE2_LEVEL_DOWN BUTTON_DOWN
166 #define SNAKE2_MAZE_NEXT BUTTON_RIGHT
167 #define SNAKE2_MAZE_LAST BUTTON_LEFT
168 #define SNAKE2_SELECT_TYPE BUTTON_F3
169 #define SNAKE2_PLAYPAUSE BUTTON_SELECT
170 #define SNAKE2_PLAYPAUSE_TEXT "Select"
172 #elif CONFIG_KEYPAD == ONDIO_PAD
173 #define SNAKE2_UP BUTTON_UP
174 #define SNAKE2_DOWN BUTTON_DOWN
175 #define SNAKE2_QUIT BUTTON_OFF
176 #define SNAKE2_LEVEL_UP BUTTON_UP
177 #define SNAKE2_LEVEL_DOWN BUTTON_DOWN
178 #define SNAKE2_MAZE_NEXT BUTTON_RIGHT
179 #define SNAKE2_SELECT_TYPE BUTTON_LEFT
180 #define SNAKE2_PLAYPAUSE BUTTON_MENU
181 #define SNAKE2_PLAYPAUSE_TEXT "Menu"
183 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
184 (CONFIG_KEYPAD == IRIVER_H300_PAD)
185 #define SNAKE2_UP BUTTON_UP
186 #define SNAKE2_DOWN BUTTON_DOWN
187 #define SNAKE2_QUIT BUTTON_OFF
188 #define SNAKE2_LEVEL_UP BUTTON_UP
189 #define SNAKE2_LEVEL_DOWN BUTTON_DOWN
190 #define SNAKE2_MAZE_NEXT BUTTON_RIGHT
191 #define SNAKE2_MAZE_LAST BUTTON_LEFT
192 #define SNAKE2_SELECT_TYPE BUTTON_MODE
193 #define SNAKE2_PLAYPAUSE BUTTON_ON
194 #define SNAKE2_PLAYPAUSE_TEXT "Play"
196 #define SNAKE2_RC_QUIT BUTTON_RC_STOP
197 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \
198 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
199 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
200 #define SNAKE2_UP BUTTON_MENU
201 #define SNAKE2_DOWN BUTTON_PLAY
202 #define SNAKE2_QUIT (BUTTON_SELECT | BUTTON_MENU)
203 #define SNAKE2_LEVEL_UP BUTTON_SCROLL_FWD
204 #define SNAKE2_LEVEL_DOWN BUTTON_SCROLL_BACK
205 #define SNAKE2_MAZE_NEXT BUTTON_RIGHT
206 #define SNAKE2_MAZE_LAST BUTTON_LEFT
207 #define SNAKE2_SELECT_TYPE BUTTON_PLAY
208 #define SNAKE2_PLAYPAUSE BUTTON_SELECT
209 #define SNAKE2_PLAYPAUSE_TEXT "Select"
211 #elif (CONFIG_KEYPAD == IAUDIO_X5M5_PAD)
212 #define SNAKE2_UP BUTTON_UP
213 #define SNAKE2_DOWN BUTTON_DOWN
214 #define SNAKE2_QUIT BUTTON_POWER
215 #define SNAKE2_LEVEL_UP BUTTON_UP
216 #define SNAKE2_LEVEL_DOWN BUTTON_DOWN
217 #define SNAKE2_MAZE_NEXT BUTTON_RIGHT
218 #define SNAKE2_MAZE_LAST BUTTON_LEFT
219 #define SNAKE2_SELECT_TYPE BUTTON_PLAY
220 #define SNAKE2_PLAYPAUSE BUTTON_SELECT
221 #define SNAKE2_PLAYPAUSE_TEXT "Select"
223 #elif (CONFIG_KEYPAD == GIGABEAT_PAD)
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_MENU
232 #define SNAKE2_PLAYPAUSE BUTTON_SELECT
233 #define SNAKE2_PLAYPAUSE_TEXT "Select"
235 #elif (CONFIG_KEYPAD == SANSA_E200_PAD) || \
236 (CONFIG_KEYPAD == SANSA_C200_PAD)
237 #define SNAKE2_UP BUTTON_UP
238 #define SNAKE2_DOWN BUTTON_DOWN
239 #define SNAKE2_QUIT BUTTON_POWER
240 #define SNAKE2_LEVEL_UP BUTTON_UP
241 #define SNAKE2_LEVEL_DOWN BUTTON_DOWN
242 #define SNAKE2_MAZE_NEXT BUTTON_RIGHT
243 #define SNAKE2_MAZE_LAST BUTTON_LEFT
244 #define SNAKE2_SELECT_TYPE BUTTON_REC
245 #define SNAKE2_PLAYPAUSE BUTTON_SELECT
246 #define SNAKE2_PLAYPAUSE_TEXT "Select"
248 #elif (CONFIG_KEYPAD == IRIVER_H10_PAD)
249 #define SNAKE2_UP BUTTON_SCROLL_UP
250 #define SNAKE2_DOWN BUTTON_SCROLL_DOWN
251 #define SNAKE2_QUIT BUTTON_POWER
252 #define SNAKE2_LEVEL_UP BUTTON_SCROLL_UP
253 #define SNAKE2_LEVEL_DOWN BUTTON_SCROLL_DOWN
254 #define SNAKE2_MAZE_NEXT BUTTON_RIGHT
255 #define SNAKE2_MAZE_LAST BUTTON_LEFT
256 #define SNAKE2_SELECT_TYPE BUTTON_PLAY
257 #define SNAKE2_PLAYPAUSE BUTTON_FF
258 #define SNAKE2_PLAYPAUSE_TEXT "FF"
260 #elif (CONFIG_KEYPAD == GIGABEAT_S_PAD)
261 #define SNAKE2_UP BUTTON_UP
262 #define SNAKE2_DOWN BUTTON_DOWN
263 #define SNAKE2_QUIT BUTTON_BACK
264 #define SNAKE2_LEVEL_UP BUTTON_UP
265 #define SNAKE2_LEVEL_DOWN BUTTON_DOWN
266 #define SNAKE2_MAZE_NEXT BUTTON_RIGHT
267 #define SNAKE2_MAZE_LAST BUTTON_LEFT
268 #define SNAKE2_SELECT_TYPE BUTTON_MENU
269 #define SNAKE2_PLAYPAUSE BUTTON_SELECT
270 #define SNAKE2_PLAYPAUSE_TEXT "Select"
272 #else
273 #error "lacks keymapping"
274 #endif
276 static int max_levels = 0;
277 static char (*level_cache)[HEIGHT][WIDTH];
279 /*Board itself - 2D int array*/
280 static int board[WIDTH][HEIGHT];
282 Buffer for sorting movement (in case user presses two movements during a
283 single frame
285 static int ardirectionbuffer[2];
286 static unsigned int score, hiscore = 0;
287 static int applex;
288 static int appley;
289 static int strwdt,strhgt; /*used for string width, height for orientation purposes*/
290 static int dir;
291 static int frames;
292 static int apple;
293 static int level = 4, speed = 5,dead = 0, quit = 0;
294 static int sillydir = 0, num_levels = 0;
295 static int level_from_file = 0;
296 static struct plugin_api* rb;
297 static int headx, heady, tailx, taily, applecountdown = 5;
298 static int game_type = 0;
299 static int num_apples_to_get=1;
300 static int num_apples_to_got=0;
301 static int game_b_level=0;
302 static int applecount=0;
303 static char phscore[30];
305 #if (LCD_WIDTH >= 160) && (LCD_HEIGHT >= 128)
306 #ifdef HAVE_LCD_COLOR
307 extern const unsigned short snake2_header1[];
308 extern const unsigned short snake2_header2[];
309 extern const unsigned short snake2_left[];
310 extern const unsigned short snake2_right[];
311 extern const unsigned short snake2_bottom[];
312 #else
313 extern const unsigned char snake2_header1[];
314 extern const unsigned char snake2_header2[];
315 extern const unsigned char snake2_left[];
316 extern const unsigned char snake2_right[];
317 extern const unsigned char snake2_bottom[];
318 #endif
319 #endif
321 #define NORTH 1
322 #define EAST 2
323 #define SOUTH 4
324 #define WEST 8
325 #define HEAD 16
327 #define EAST_NORTH 32
328 #define EAST_SOUTH 64
329 #define WEST_NORTH 128
330 #define WEST_SOUTH 256
332 #define NORTH_EAST 512
333 #define NORTH_WEST 1024
334 #define SOUTH_EAST 2048
335 #define SOUTH_WEST 4096
337 #define LEVELS_FILE PLUGIN_GAMES_DIR "/snake2.levels"
338 #define HISCORE_FILE PLUGIN_GAMES_DIR "/snake2.hs"
340 int load_all_levels(void)
342 int linecnt = 0;
343 int fd;
344 ssize_t size;
345 char buf[64]; /* Larger than WIDTH, to allow for whitespace after the
346 lines */
348 /* Init the level_cache pointer and
349 calculate how many levels that will fit */
350 level_cache = rb->plugin_get_buffer((size_t *)&size);
351 max_levels = size / (HEIGHT*WIDTH);
353 num_levels = 0;
355 /* open file */
356 if ((fd = rb->open(LEVELS_FILE, O_RDONLY)) < 0)
358 return -1;
361 while(rb->read_line(fd, buf, 64))
363 if(rb->strlen(buf) == 0) /* Separator? */
365 num_levels++;
366 if(num_levels > max_levels)
368 rb->splash(HZ, "Too many levels in file");
369 break;
371 continue;
374 rb->memcpy(level_cache[num_levels][linecnt], buf, WIDTH);
375 linecnt++;
376 if(linecnt == HEIGHT)
378 linecnt = 0;
382 rb->close(fd);
383 return 0;
386 /*Hi-Score reading and writing to file "/.rockbox/rocks/games/snake2.levels" function */
387 void iohiscore(void)
389 int fd;
390 unsigned int compare;
392 /* clear the buffer we're about to load the highscore data into */
393 rb->memset(phscore, 0, sizeof(phscore));
395 fd = rb->open(HISCORE_FILE,O_RDWR | O_CREAT);
397 /* highscore used to %d, is now %d\n
398 Deal with no file or bad file */
399 rb->read(fd,phscore, sizeof(phscore));
401 compare = rb->atoi(phscore);
403 if(hiscore > compare){
404 rb->lseek(fd,0,SEEK_SET);
405 rb->fdprintf(fd, "%d\n", hiscore);
407 else
408 hiscore = compare;
410 rb->close(fd);
415 ** Completely clear the board of walls and/or snake */
417 void clear_board( void)
419 int x,y;
421 for (x = 0; x < WIDTH; x++)
423 for (y = 0; y < HEIGHT; y++)
425 board[x][y] = 0;
430 int load_level( int level_number )
432 int x,y;
433 clear_board();
434 for(y = 0;y < HEIGHT;y++)
436 for(x = 0;x < WIDTH;x++)
438 switch(level_cache[level_number][y][x])
440 case '|':
441 board[x][y] = NORTH;
442 break;
444 case '-':
445 board[x][y] = EAST;
446 break;
448 case '+':
449 board[x][y] = HEAD;
450 break;
454 return 1;
458 ** Gets the currently chosen direction from the first place
459 ** in the direction buffer. If there is something in the
460 ** next part of the buffer then that is moved to the first place
462 void get_direction( void )
464 /*if 1st place is empty*/
465 if(ardirectionbuffer[0] != -1)
467 /*return this direction*/
468 dir = ardirectionbuffer[0];
469 ardirectionbuffer[0]=-1;
470 /*now see if one needs moving:*/
471 if(ardirectionbuffer[1] != -1)
473 /*there's a move waiting to be done
474 so move it into the space:*/
475 ardirectionbuffer[0] = ardirectionbuffer[1];
476 ardirectionbuffer[1] = -1;
482 ** Sets the direction
484 void set_direction(int newdir)
486 if(ardirectionbuffer[0] != newdir)
488 /*if 1st place is empty*/
489 if(ardirectionbuffer[0] == -1)
491 /*use 1st space:*/
492 ardirectionbuffer[0] = newdir;
494 else
496 /*use 2nd space:*/
497 if(ardirectionbuffer[0] != newdir) ardirectionbuffer[1] = newdir;
500 if(frames < 0) ardirectionbuffer[0] = newdir;
504 void new_level(int level)
506 load_level(level);
508 ardirectionbuffer[0] = -1;
509 ardirectionbuffer[1] = -1;
510 dir = EAST;
511 headx = WIDTH/2;
512 heady = HEIGHT/2;
513 tailx = headx - 4;
514 taily = heady;
515 applecountdown = 0;
516 /*Create a small snake to start off with*/
517 board[headx][heady] = dir;
518 board[headx-1][heady] = dir;
519 board[headx-2][heady] = dir;
520 board[headx-3][heady] = dir;
521 board[headx-4][heady] = dir;
522 num_apples_to_got=0;
525 void init_snake(void)
527 num_apples_to_get=1;
528 if(game_type == 1)
529 level_from_file = 1;
530 game_b_level=1;
531 new_level(level_from_file);
535 ** Draws the apple. If it doesn't exist then
536 ** a new one get's created.
538 void draw_apple( void )
540 int x,y;
542 #if LCD_WIDTH >= 160 && LCD_HEIGHT >= 128
543 char pscore[5], counter[4];
545 rb->lcd_bitmap(snake2_header2,0,0,BMPWIDTH_snake2_header, BMPHEIGHT_snake2_header);
546 rb->lcd_bitmap(snake2_left,0,BMPHEIGHT_snake2_header,BMPWIDTH_snake2_left, BMPHEIGHT_snake2_left);
547 rb->lcd_bitmap(snake2_right,LCD_WIDTH-BMPWIDTH_snake2_right,BMPHEIGHT_snake2_header,BMPWIDTH_snake2_right, BMPHEIGHT_snake2_right);
548 rb->lcd_bitmap(snake2_bottom,0,BMPHEIGHT_snake2_header+BMPHEIGHT_snake2_left,BMPWIDTH_snake2_bottom, BMPHEIGHT_snake2_bottom);
550 rb->snprintf(counter,sizeof(counter),"%d",applecount);
551 rb->lcd_getstringsize(counter,&strwdt,&strhgt);
552 rb->lcd_putsxy(TOP_X3-strwdt/2,TOP_Y2,counter);
554 rb->snprintf(pscore,sizeof(pscore),"%d",score);
555 rb->lcd_getstringsize(pscore,&strwdt,&strhgt);
556 rb->lcd_putsxy(TOP_X4-strwdt/2,TOP_Y2,pscore);
557 #endif
559 if (!apple)
563 x = (rb->rand() % (WIDTH-1))+1;
564 y = (rb->rand() % (HEIGHT-1))+1;
565 } while (board[x][y]);
566 apple=1;
567 board[x][y]=-1;
568 applex = x;appley = y;
570 rb->lcd_fillrect((CENTER_X+applex*MULTIPLIER)+1,CENTER_Y+appley*MULTIPLIER,MODIFIER_2,MODIFIER_1);
571 rb->lcd_fillrect(CENTER_X+applex*MULTIPLIER,(CENTER_Y+appley*MULTIPLIER)+1,MODIFIER_1,MODIFIER_2);
575 * x x *
576 * x x *
577 * x x *
578 * x x *
580 void draw_vertical_bit(int x, int y)
582 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER+1,CENTER_Y+y*MULTIPLIER,MODIFIER_2,MODIFIER_1);
586 * * * *
587 X X X X
588 X X X X
589 * * * *
591 void draw_horizontal_bit(int x, int y)
593 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER,CENTER_Y+y*MULTIPLIER+1,MODIFIER_1,MODIFIER_2);
597 * * * *
598 * * X X
599 * X X X
600 * X X *
602 void draw_n_to_e_bit(int x, int y)
604 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER+1,CENTER_Y+y*MULTIPLIER+2,MODIFIER_2,MODIFIER_2);
605 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER+2,CENTER_Y+y*MULTIPLIER+1,MODIFIER_2,MODIFIER_2);
609 * * * *
610 * * X X
611 * X X X
612 * X X *
614 void draw_w_to_s_bit(int x, int y)
616 draw_n_to_e_bit(x,y);
620 * * * *
621 X X * *
622 X X X *
623 * X X *
625 void draw_n_to_w_bit(int x, int y)
627 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER,CENTER_Y+y*MULTIPLIER+1,MODIFIER_2,MODIFIER_2);
628 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER+1,CENTER_Y+y*MULTIPLIER+2,MODIFIER_2,MODIFIER_2);
632 * * * *
633 X X * *
634 X X X *
635 * X X *
637 void draw_e_to_s_bit(int x, int y)
639 draw_n_to_w_bit(x, y);
643 * X X *
644 * X X X
645 * * X X
646 * * * *
648 void draw_s_to_e_bit(int x, int y)
650 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER+1,CENTER_Y+y*MULTIPLIER,MODIFIER_2,MODIFIER_2);
651 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER+2,CENTER_Y+y*MULTIPLIER+1,MODIFIER_2,MODIFIER_2);
655 * X X *
656 * X X X
657 * * X X
658 * * * *
660 void draw_w_to_n_bit(int x, int y)
662 draw_s_to_e_bit(x,y);
666 * X X *
667 X X X *
668 X X * *
669 * * * *
671 void draw_e_to_n_bit(int x, int y)
673 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER+1,CENTER_Y+y*MULTIPLIER,MODIFIER_2,MODIFIER_2);
674 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER,CENTER_Y+y*MULTIPLIER+1,MODIFIER_2,MODIFIER_2);
678 * X X *
679 X X X *
680 X X * *
681 * * * *
683 void draw_s_to_w_bit(int x, int y)
685 draw_e_to_n_bit(x, y);
689 ** Draws a wall/obsticals
691 void draw_boundary ( void )
693 int x, y;
695 /*TODO: Load levels from file!*/
697 /*top and bottom line*/
698 for(x=0; x < WIDTH; x++)
700 board[x][0] = EAST;
701 board[x][HEIGHT-1] = WEST;
704 /*left and right lines*/
705 for(y=0; y < HEIGHT; y++)
707 board[0][y] = NORTH;
708 board[WIDTH-1][y] = SOUTH;
711 /*corners:*/
712 board[0][0] = NORTH_EAST;
713 board[WIDTH-1][0] = EAST_SOUTH;
714 board[0][HEIGHT-1] = SOUTH_EAST;
715 board[WIDTH-1][HEIGHT-1] = EAST_NORTH;
719 ** Redraw the entire board
721 void redraw (void)
723 int x,y;
725 for (x = 0; x < WIDTH; x++)
727 for (y = 0; y < HEIGHT; y++)
729 switch (board[x][y])
731 case -1:
732 rb->lcd_fillrect((CENTER_X+x*MULTIPLIER)+1,CENTER_Y+y*MULTIPLIER,MODIFIER_2,MODIFIER_1);
733 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER,(CENTER_Y+y*MULTIPLIER)+1,MODIFIER_1,MODIFIER_2);
734 break;
735 case 0:
736 break;
738 case NORTH:
739 case SOUTH:
740 draw_vertical_bit(x,y);
741 break;
743 case EAST:
744 case WEST:
745 draw_horizontal_bit(x,y);
746 break;
748 default:
749 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER,CENTER_Y+y*MULTIPLIER,MODIFIER_1,MODIFIER_1);
750 break;
757 ** Draws the snake bit described by nCurrentBit at position x/y
758 ** deciding whether it's a corner bit by examing the nPrevious bit
760 void draw_snake_bit(int currentbit, int previousbit, int x, int y)
762 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
763 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER,CENTER_Y+y*MULTIPLIER,MODIFIER_1,MODIFIER_1);
764 rb->lcd_set_drawmode(DRMODE_SOLID);
766 switch(currentbit)
768 case(NORTH):
769 switch(previousbit)
771 case(SOUTH):
772 case(NORTH):
773 draw_vertical_bit(x,y);
774 break;
776 case(EAST):
777 draw_e_to_n_bit(x,y);
778 break;
780 case(WEST):
781 draw_w_to_n_bit(x,y);
782 break;
784 break;
786 case(EAST):
787 switch(previousbit)
789 case(WEST):
790 case(EAST):
791 draw_horizontal_bit(x,y);
792 break;
794 case(NORTH):
795 draw_n_to_e_bit(x,y);
796 break;
798 case(SOUTH):
799 draw_s_to_e_bit(x,y);
800 break;
802 break;
804 case(SOUTH):
805 switch(previousbit)
807 case(SOUTH):
808 case(NORTH):
809 draw_vertical_bit(x,y);
810 break;
812 case(EAST):
813 draw_e_to_s_bit(x,y);
814 break;
816 case(WEST):
817 draw_w_to_s_bit(x,y);
818 break;
820 break;
822 case(WEST):
823 switch(previousbit)
825 case(EAST):
826 case(WEST):
827 draw_horizontal_bit(x,y);
828 break;
830 case(SOUTH):
831 draw_s_to_w_bit(x,y);
832 break;
834 case(NORTH):
835 draw_n_to_w_bit(x,y);
836 break;
838 break;
843 ** Death 'sequence' and end game stuff.
845 void die (void)
847 int button;
848 bool done=false;
849 char pscore[20];
851 rb->splash(HZ*2, "Oops!");
853 rb->lcd_clear_display();
855 applecount=0;
857 rb->lcd_getstringsize("You died!",&strwdt,&strhgt);
858 rb->lcd_putsxy((LCD_WIDTH - strwdt)/2,strhgt,"You died!");
860 rb->snprintf(pscore,sizeof(pscore),"Your score: %d",score);
861 rb->lcd_getstringsize(pscore,&strwdt,&strhgt);
862 rb->lcd_putsxy((LCD_WIDTH - strwdt)/2,strhgt * 2 + 2,pscore);
864 if (score>hiscore)
866 hiscore=score;
867 rb->lcd_getstringsize("New high score!",&strwdt,&strhgt);
868 rb->lcd_putsxy((LCD_WIDTH - strwdt)/2,strhgt * 4 + 2,"New high score!");
870 else
872 rb->snprintf(phscore,sizeof(phscore),"High score: %d",hiscore);
873 rb->lcd_getstringsize(phscore,&strwdt,&strhgt);
874 rb->lcd_putsxy((LCD_WIDTH - strwdt)/2,strhgt * 5,phscore);
877 rb->snprintf(phscore,sizeof(phscore),"Press %s...",SNAKE2_PLAYPAUSE_TEXT);
878 rb->lcd_getstringsize(phscore,&strwdt,&strhgt);
879 rb->lcd_putsxy((LCD_WIDTH - strwdt)/2,strhgt * 7,phscore);
881 rb->lcd_update();
883 while(!done)
885 button=rb->button_get(true);
886 switch(button)
888 case SNAKE2_PLAYPAUSE:
889 done = true;
890 break;
894 dead=1;
898 ** Check for collision. TODO: Currently this
899 ** sets of the death sequence. What we want is it to only return a true/false
900 ** depending on whether a collision occured.
902 void collision ( int x, int y )
904 int bdeath=0;
907 switch (board[x][y])
909 case 0:
911 break;
912 case -1:
913 score = score + (1 * level);
914 apple=0;
915 applecountdown=2;
916 applecount++;
918 if(game_type==1)
920 if(num_apples_to_get == num_apples_to_got)
922 level_from_file++;
923 if(level_from_file >= num_levels)
925 level_from_file = 1;
926 /*and increase the number of apples to pick up
927 before level changes*/
928 num_apples_to_get+=2;
929 game_b_level++;
931 rb->splash(HZ, "Level Completed!");
932 rb->lcd_clear_display();
933 new_level(level_from_file);
934 rb->lcd_clear_display();
935 redraw();
936 rb->lcd_update();
938 else
939 num_apples_to_got++;
941 break;
942 default:
943 bdeath=1;
944 break;
947 if(bdeath==1)
949 die();
950 sillydir = dir;
951 frames = -110;
955 void move( void )
957 int taildir;
958 /*this actually sets the dir variable.*/
959 get_direction();
960 /*draw head*/
961 switch (dir)
963 case (NORTH):
964 board[headx][heady]=NORTH;
965 heady--;
966 break;
967 case (EAST):
968 board[headx][heady]=EAST;
969 headx++;
970 break;
971 case (SOUTH):
972 board[headx][heady]=SOUTH;
973 heady++;
974 break;
975 case (WEST):
976 board[headx][heady]=WEST;
977 headx--;
978 break;
981 if(headx == WIDTH)
982 headx = 0;
983 else if(headx < 0)
984 headx = WIDTH-1;
986 if(heady == HEIGHT)
987 heady = 0;
988 else if(heady < 0)
989 heady = HEIGHT-1;
991 rb->lcd_fillrect(CENTER_X+headx*MULTIPLIER,CENTER_Y+heady*MULTIPLIER,MODIFIER_1,MODIFIER_1);
993 /*clear tail*/
994 if(applecountdown <= 0)
996 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
997 rb->lcd_fillrect(CENTER_X+tailx*MULTIPLIER,CENTER_Y+taily*MULTIPLIER,MODIFIER_1,MODIFIER_1);
998 rb->lcd_set_drawmode(DRMODE_SOLID);
1000 taildir = board[tailx][taily];
1001 board[tailx][taily] = 0;
1003 switch (taildir)
1005 case(NORTH):
1006 taily--;
1007 break;
1009 case(EAST):
1010 tailx++;
1011 break;
1013 case(SOUTH):
1014 taily++;
1015 break;
1017 case(WEST):
1018 tailx--;
1019 break;
1022 if(tailx == WIDTH)
1023 tailx = 0;
1024 else if(tailx < 0)
1025 tailx = WIDTH-1;
1027 if(taily == HEIGHT)
1028 taily = 0;
1029 else if(taily < 0)
1030 taily = HEIGHT-1;
1032 else
1033 applecountdown--;
1036 void frame (void)
1038 int olddir, noldx, noldy, temp;
1039 noldx = headx;
1040 noldy = heady;
1041 olddir = 0;
1042 switch(dir)
1044 case(NORTH):
1045 if(heady == HEIGHT-1)
1046 temp = 0;
1047 else
1048 temp = heady + 1;
1050 olddir = board[headx][temp];
1051 break;
1053 case(EAST):
1054 if(headx == 0)
1055 temp = WIDTH-1;
1056 else
1057 temp = headx - 1;
1059 olddir = board[temp][heady];
1060 break;
1062 case(SOUTH):
1063 if(heady == 0)
1064 temp = HEIGHT-1;
1065 else
1066 temp = heady - 1;
1068 olddir = board[headx][temp];
1069 break;
1071 case(WEST):
1072 if(headx == WIDTH-1)
1073 temp = 0;
1074 else
1075 temp = headx + 1;
1077 olddir = board[temp][heady];
1078 break;
1081 move();
1084 now redraw the bit that was
1085 the tail, to something snake-like:
1087 draw_snake_bit(dir, olddir, noldx, noldy);
1089 collision(headx, heady);
1091 rb->lcd_update();
1094 void game_pause (void)
1096 int button;
1098 rb->lcd_clear_display();
1099 rb->lcd_getstringsize("Paused",&strwdt,&strhgt);
1100 rb->lcd_putsxy((LCD_WIDTH - strwdt)/2,LCD_HEIGHT/2,"Paused");
1102 rb->lcd_update();
1103 while (1)
1105 button = rb->button_get(true);
1106 switch (button)
1108 case SNAKE2_PLAYPAUSE:
1109 rb->lcd_clear_display();
1110 redraw();
1111 rb->lcd_update();
1112 rb->sleep(HZ/2);
1113 return;
1115 #ifdef SNAKE2_RC_QUIT
1116 case SNAKE2_RC_QUIT:
1117 #endif
1118 case SNAKE2_QUIT:
1119 dead = 1;
1120 quit = 1;
1121 return;
1123 default:
1124 if (rb->default_event_handler(button)==SYS_USB_CONNECTED) {
1125 dead = 1;
1126 quit = 2;
1127 return;
1129 break;
1134 void game (void)
1136 int button;
1138 rb->lcd_clear_display();
1139 redraw();
1140 rb->lcd_update();
1141 /*main loop:*/
1142 while (1)
1144 if(frames==5)
1146 frame();
1147 if(frames>0) frames=0;
1149 frames++;
1151 if(frames == 0)
1153 die();
1155 else
1157 if(frames < 0)
1159 if(sillydir != dir)
1161 /*it has, great set frames to a positive value again:*/
1162 frames = 1;
1167 if (dead) return;
1169 draw_apple();
1171 rb->sleep(HZ/speed);
1173 button = rb->button_get(false);
1175 #ifdef HAS_BUTTON_HOLD
1176 if (rb->button_hold())
1177 button = SNAKE2_PLAYPAUSE;
1178 #endif
1180 switch (button)
1182 case SNAKE2_UP:
1183 case SNAKE2_UP | BUTTON_REPEAT:
1184 if (dir != SOUTH) set_direction(NORTH);
1185 break;
1187 case BUTTON_RIGHT:
1188 case BUTTON_RIGHT | BUTTON_REPEAT:
1189 if (dir != WEST) set_direction(EAST);
1190 break;
1192 case SNAKE2_DOWN:
1193 case SNAKE2_DOWN | BUTTON_REPEAT:
1194 if (dir != NORTH) set_direction(SOUTH);
1195 break;
1197 case BUTTON_LEFT:
1198 case BUTTON_LEFT | BUTTON_REPEAT:
1199 if (dir != EAST) set_direction(WEST);
1200 break;
1202 #ifdef SNAKE2_RC_QUIT
1203 case SNAKE2_RC_QUIT:
1204 #endif
1205 case SNAKE2_QUIT:
1206 dead=1;
1207 return;
1209 case SNAKE2_PLAYPAUSE:
1210 game_pause();
1211 break;
1213 default:
1214 if (rb->default_event_handler(button)==SYS_USB_CONNECTED) {
1215 quit = 2;
1216 return;
1218 break;
1224 void game_init(void)
1226 int button;
1227 char plevel[30];
1229 dead=0;
1230 apple=0;
1231 score=0;
1232 applecount=0;
1234 clear_board();
1235 load_level( level_from_file );
1236 rb->lcd_clear_display();
1237 redraw();
1238 rb->lcd_update();
1240 while (1)
1242 #if LCD_WIDTH >= 160 && LCD_HEIGHT >= 128
1244 rb->lcd_bitmap(snake2_header1,0,0,BMPWIDTH_snake2_header, BMPHEIGHT_snake2_header);
1245 rb->lcd_bitmap(snake2_left,0,BMPHEIGHT_snake2_header,BMPWIDTH_snake2_left, BMPHEIGHT_snake2_left);
1246 rb->lcd_bitmap(snake2_right,LCD_WIDTH-BMPWIDTH_snake2_right,BMPHEIGHT_snake2_header,BMPWIDTH_snake2_right, BMPHEIGHT_snake2_right);
1247 rb->lcd_bitmap(snake2_bottom,0,BMPHEIGHT_snake2_header+BMPHEIGHT_snake2_left,BMPWIDTH_snake2_bottom, BMPHEIGHT_snake2_bottom);
1249 rb->snprintf(plevel,sizeof(plevel),"%d",level);
1250 rb->lcd_getstringsize(plevel,&strwdt,&strhgt);
1251 rb->lcd_putsxy(TOP_X3-strwdt/2,TOP_Y2, plevel);
1253 rb->snprintf(plevel,sizeof(plevel),"%d",level_from_file);
1254 rb->lcd_getstringsize(plevel,&strwdt,&strhgt);
1255 rb->lcd_putsxy(TOP_X2-strwdt/2,TOP_Y1, plevel);
1257 if(game_type==0){
1258 rb->lcd_getstringsize("A",&strwdt,&strhgt);
1259 rb->lcd_putsxy(TOP_X1,TOP_Y1,"A");
1261 else{
1262 rb->lcd_getstringsize("B",&strwdt,&strhgt);
1263 rb->lcd_putsxy(TOP_X1,TOP_Y1,"B");
1266 rb->snprintf(phscore,sizeof(phscore),"%d",hiscore);
1267 rb->lcd_getstringsize(phscore,&strwdt,&strhgt);
1268 rb->lcd_putsxy(TOP_X4-strwdt/2,TOP_Y2, phscore);
1270 #else
1271 rb->snprintf(plevel,sizeof(plevel),"Speed: %02d",level);
1272 rb->lcd_getstringsize("Speed: 00",&strwdt,&strhgt);
1273 rb->lcd_putsxy((LCD_WIDTH - strwdt)/2,strhgt+4, plevel);
1275 rb->snprintf(plevel,sizeof(plevel),"Maze: %d",level_from_file);
1276 rb->lcd_getstringsize(plevel,&strwdt,&strhgt);
1277 rb->lcd_putsxy((LCD_WIDTH - strwdt)/2,strhgt*2+4, plevel);
1279 if(game_type==0){
1280 rb->lcd_getstringsize("Game Type: A ",&strwdt,&strhgt);
1281 rb->lcd_putsxy((LCD_WIDTH - strwdt)/2,strhgt*3+4,"Game Type: A");
1283 else{
1284 rb->lcd_getstringsize("Game Type: B ",&strwdt,&strhgt);
1285 rb->lcd_putsxy((LCD_WIDTH - strwdt)/2,strhgt*3+4,"Game Type: B");
1288 rb->snprintf(phscore,sizeof(phscore),"Hi Score: %d",hiscore);
1289 rb->lcd_getstringsize(phscore,&strwdt,&strhgt);
1290 rb->lcd_putsxy((LCD_WIDTH - strwdt)/2,strhgt*4+4, phscore);
1291 #endif
1293 rb->lcd_update();
1295 button=rb->button_get(true);
1296 switch (button)
1298 case SNAKE2_LEVEL_UP:
1299 case SNAKE2_LEVEL_UP|BUTTON_REPEAT:
1300 if (level<10)
1301 level+=1;
1302 break;
1303 case SNAKE2_LEVEL_DOWN:
1304 case SNAKE2_LEVEL_DOWN|BUTTON_REPEAT:
1305 if (level>1)
1306 level-=1;
1307 break;
1308 case SNAKE2_QUIT:
1309 quit=1;
1310 return;
1311 break;
1312 case SNAKE2_PLAYPAUSE:
1313 speed = level*20;
1314 return;
1315 break;
1316 case SNAKE2_SELECT_TYPE:
1317 if(game_type==0)game_type=1; else game_type=0;
1318 break;
1319 case SNAKE2_MAZE_NEXT:
1320 rb->lcd_set_drawmode(DRMODE_BG|DRMODE_INVERSEVID);
1321 rb->lcd_fillrect(CENTER_X, CENTER_Y, CENTER_X+WIDTH*MULTIPLIER,
1322 CENTER_Y+HEIGHT*MULTIPLIER);
1323 rb->lcd_set_drawmode(DRMODE_SOLID);
1324 if(level_from_file < num_levels)
1325 level_from_file++;
1326 else
1327 level_from_file = 0;
1328 load_level( level_from_file );
1329 redraw();
1330 break;
1331 #ifdef SNAKE2_MAZE_LAST
1332 case SNAKE2_MAZE_LAST:
1333 rb->lcd_set_drawmode(DRMODE_BG|DRMODE_INVERSEVID);
1334 rb->lcd_fillrect(CENTER_X, CENTER_Y, CENTER_X+WIDTH*MULTIPLIER,
1335 CENTER_Y+HEIGHT*MULTIPLIER);
1336 rb->lcd_set_drawmode(DRMODE_SOLID);
1337 if(level_from_file > 0)
1338 level_from_file--;
1339 else
1340 level_from_file = num_levels;
1341 load_level( level_from_file );
1342 redraw();
1343 break;
1344 #endif
1345 default:
1346 if (rb->default_event_handler(button)==SYS_USB_CONNECTED) {
1347 quit = 2;
1348 return;
1350 break;
1356 enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
1358 (void)(parameter);
1359 rb = api;
1361 /* Lets use the default font */
1362 rb->lcd_setfont(FONT_SYSFIXED);
1363 #if LCD_DEPTH > 1
1364 rb->lcd_set_backdrop(NULL);
1365 #endif
1366 #ifdef HAVE_LCD_COLOR
1367 rb->lcd_set_foreground(LCD_BLACK);
1368 rb->lcd_set_background(LCD_WHITE);
1369 #endif
1371 load_all_levels();
1373 if (num_levels == 0) {
1374 rb->splash(HZ*2, "Failed loading levels!");
1375 return PLUGIN_OK;
1378 iohiscore();
1380 while(quit==0)
1382 game_init();
1383 rb->lcd_clear_display();
1384 frames=1;
1386 if(quit==0)
1388 init_snake();
1390 /*Start Game:*/
1391 game();
1395 iohiscore();
1396 return (quit==1) ? PLUGIN_OK : PLUGIN_USB_CONNECTED;
1399 #endif