Fix some quotation marks. Thanks to Alexander Levin for pointing it out.
[Rockbox.git] / apps / plugins / snake2.c
blob0c2b88868cc76734b9fecdbc6ca4630991f7c19a
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_LEFT BUTTON_LEFT
293 #define SNAKE2_RIGHT BUTTON_RIGHT
294 #define SNAKE2_UP BUTTON_UP
295 #define SNAKE2_DOWN BUTTON_DOWN
296 #define SNAKE2_QUIT BUTTON_POWER
297 #define SNAKE2_LEVEL_UP BUTTON_UP
298 #define SNAKE2_LEVEL_DOWN BUTTON_DOWN
299 #define SNAKE2_MAZE_NEXT BUTTON_RIGHT
300 #define SNAKE2_MAZE_LAST BUTTON_LEFT
301 #define SNAKE2_SELECT_TYPE BUTTON_MENU
302 #define SNAKE2_PLAYPAUSE BUTTON_SELECT
303 #define SNAKE2_PLAYPAUSE_TEXT "Select"
305 #else
306 #error No keymap defined!
307 #endif
309 static int max_levels = 0;
310 static char (*level_cache)[HEIGHT][WIDTH];
312 /*Board itself - 2D int array*/
313 static int board[WIDTH][HEIGHT];
315 Buffer for sorting movement (in case user presses two movements during a
316 single frame
318 static int ardirectionbuffer[2];
319 static unsigned int score, hiscore = 0;
320 static int applex;
321 static int appley;
322 static int strwdt,strhgt; /*used for string width, height for orientation purposes*/
323 static int dir;
324 static int frames;
325 static int apple;
326 static int level = 4, speed = 5,dead = 0, quit = 0;
327 static int sillydir = 0, num_levels = 0;
328 static int level_from_file = 0;
329 static struct plugin_api* rb;
330 static int headx, heady, tailx, taily, applecountdown = 5;
331 static int game_type = 0;
332 static int num_apples_to_get=1;
333 static int num_apples_to_got=0;
334 static int game_b_level=0;
335 static int applecount=0;
336 static char phscore[30];
338 #define NORTH 1
339 #define EAST 2
340 #define SOUTH 4
341 #define WEST 8
342 #define HEAD 16
344 #define EAST_NORTH 32
345 #define EAST_SOUTH 64
346 #define WEST_NORTH 128
347 #define WEST_SOUTH 256
349 #define NORTH_EAST 512
350 #define NORTH_WEST 1024
351 #define SOUTH_EAST 2048
352 #define SOUTH_WEST 4096
354 #define LEVELS_FILE PLUGIN_GAMES_DIR "/snake2.levels"
355 #define HISCORE_FILE PLUGIN_GAMES_DIR "/snake2.hs"
357 int load_all_levels(void)
359 int linecnt = 0;
360 int fd;
361 ssize_t size;
362 char buf[64]; /* Larger than WIDTH, to allow for whitespace after the
363 lines */
365 /* Init the level_cache pointer and
366 calculate how many levels that will fit */
367 level_cache = rb->plugin_get_buffer((size_t *)&size);
368 max_levels = size / (HEIGHT*WIDTH);
370 num_levels = 0;
372 /* open file */
373 if ((fd = rb->open(LEVELS_FILE, O_RDONLY)) < 0)
375 return -1;
378 while(rb->read_line(fd, buf, 64))
380 if(rb->strlen(buf) == 0) /* Separator? */
382 num_levels++;
383 if(num_levels > max_levels)
385 rb->splash(HZ, "Too many levels in file");
386 break;
388 continue;
391 rb->memcpy(level_cache[num_levels][linecnt], buf, WIDTH);
392 linecnt++;
393 if(linecnt == HEIGHT)
395 linecnt = 0;
399 rb->close(fd);
400 return 0;
403 /*Hi-Score reading and writing to file "/.rockbox/rocks/games/snake2.levels" function */
404 void iohiscore(void)
406 int fd;
407 unsigned int compare;
409 /* clear the buffer we're about to load the highscore data into */
410 rb->memset(phscore, 0, sizeof(phscore));
412 fd = rb->open(HISCORE_FILE,O_RDWR | O_CREAT);
414 /* highscore used to %d, is now %d\n
415 Deal with no file or bad file */
416 rb->read(fd,phscore, sizeof(phscore));
418 compare = rb->atoi(phscore);
420 if(hiscore > compare){
421 rb->lseek(fd,0,SEEK_SET);
422 rb->fdprintf(fd, "%d\n", hiscore);
424 else
425 hiscore = compare;
427 rb->close(fd);
432 ** Completely clear the board of walls and/or snake */
434 void clear_board( void)
436 int x,y;
438 for (x = 0; x < WIDTH; x++)
440 for (y = 0; y < HEIGHT; y++)
442 board[x][y] = 0;
447 int load_level( int level_number )
449 int x,y;
450 clear_board();
451 for(y = 0;y < HEIGHT;y++)
453 for(x = 0;x < WIDTH;x++)
455 switch(level_cache[level_number][y][x])
457 case '|':
458 board[x][y] = NORTH;
459 break;
461 case '-':
462 board[x][y] = EAST;
463 break;
465 case '+':
466 board[x][y] = HEAD;
467 break;
471 return 1;
475 ** Gets the currently chosen direction from the first place
476 ** in the direction buffer. If there is something in the
477 ** next part of the buffer then that is moved to the first place
479 void get_direction( void )
481 /*if 1st place is empty*/
482 if(ardirectionbuffer[0] != -1)
484 /*return this direction*/
485 dir = ardirectionbuffer[0];
486 ardirectionbuffer[0]=-1;
487 /*now see if one needs moving:*/
488 if(ardirectionbuffer[1] != -1)
490 /*there's a move waiting to be done
491 so move it into the space:*/
492 ardirectionbuffer[0] = ardirectionbuffer[1];
493 ardirectionbuffer[1] = -1;
499 ** Sets the direction
501 void set_direction(int newdir)
503 if(ardirectionbuffer[0] != newdir)
505 /*if 1st place is empty*/
506 if(ardirectionbuffer[0] == -1)
508 /*use 1st space:*/
509 ardirectionbuffer[0] = newdir;
511 else
513 /*use 2nd space:*/
514 if(ardirectionbuffer[0] != newdir) ardirectionbuffer[1] = newdir;
517 if(frames < 0) ardirectionbuffer[0] = newdir;
521 void new_level(int level)
523 load_level(level);
525 ardirectionbuffer[0] = -1;
526 ardirectionbuffer[1] = -1;
527 dir = EAST;
528 headx = WIDTH/2;
529 heady = HEIGHT/2;
530 tailx = headx - 4;
531 taily = heady;
532 applecountdown = 0;
533 /*Create a small snake to start off with*/
534 board[headx][heady] = dir;
535 board[headx-1][heady] = dir;
536 board[headx-2][heady] = dir;
537 board[headx-3][heady] = dir;
538 board[headx-4][heady] = dir;
539 num_apples_to_got=0;
542 void init_snake(void)
544 num_apples_to_get=1;
545 if(game_type == 1)
546 level_from_file = 1;
547 game_b_level=1;
548 new_level(level_from_file);
552 ** Draws the apple. If it doesn't exist then
553 ** a new one get's created.
555 void draw_apple( void )
557 int x,y;
559 #if LCD_WIDTH >= 160 && LCD_HEIGHT >= 128
560 char pscore[5], counter[4];
562 rb->lcd_bitmap(snake2_header2,0,0,BMPWIDTH_snake2_header, BMPHEIGHT_snake2_header);
563 rb->lcd_bitmap(snake2_left,0,BMPHEIGHT_snake2_header,BMPWIDTH_snake2_left, BMPHEIGHT_snake2_left);
564 rb->lcd_bitmap(snake2_right,LCD_WIDTH-BMPWIDTH_snake2_right,BMPHEIGHT_snake2_header,BMPWIDTH_snake2_right, BMPHEIGHT_snake2_right);
565 rb->lcd_bitmap(snake2_bottom,0,BMPHEIGHT_snake2_header+BMPHEIGHT_snake2_left,BMPWIDTH_snake2_bottom, BMPHEIGHT_snake2_bottom);
567 rb->snprintf(counter,sizeof(counter),"%d",applecount);
568 rb->lcd_getstringsize(counter,&strwdt,&strhgt);
569 rb->lcd_putsxy(TOP_X3-strwdt/2,TOP_Y2,counter);
571 rb->snprintf(pscore,sizeof(pscore),"%d",score);
572 rb->lcd_getstringsize(pscore,&strwdt,&strhgt);
573 rb->lcd_putsxy(TOP_X4-strwdt/2,TOP_Y2,pscore);
574 #endif
576 if (!apple)
580 x = (rb->rand() % (WIDTH-1))+1;
581 y = (rb->rand() % (HEIGHT-1))+1;
582 } while (board[x][y]);
583 apple=1;
584 board[x][y]=-1;
585 applex = x;appley = y;
587 rb->lcd_fillrect((CENTER_X+applex*MULTIPLIER)+1,CENTER_Y+appley*MULTIPLIER,MODIFIER_2,MODIFIER_1);
588 rb->lcd_fillrect(CENTER_X+applex*MULTIPLIER,(CENTER_Y+appley*MULTIPLIER)+1,MODIFIER_1,MODIFIER_2);
592 * x x *
593 * x x *
594 * x x *
595 * x x *
597 void draw_vertical_bit(int x, int y)
599 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER+1,CENTER_Y+y*MULTIPLIER,MODIFIER_2,MODIFIER_1);
603 * * * *
604 X X X X
605 X X X X
606 * * * *
608 void draw_horizontal_bit(int x, int y)
610 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER,CENTER_Y+y*MULTIPLIER+1,MODIFIER_1,MODIFIER_2);
614 * * * *
615 * * X X
616 * X X X
617 * X X *
619 void draw_n_to_e_bit(int x, int y)
621 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER+1,CENTER_Y+y*MULTIPLIER+2,MODIFIER_2,MODIFIER_2);
622 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER+2,CENTER_Y+y*MULTIPLIER+1,MODIFIER_2,MODIFIER_2);
626 * * * *
627 * * X X
628 * X X X
629 * X X *
631 void draw_w_to_s_bit(int x, int y)
633 draw_n_to_e_bit(x,y);
637 * * * *
638 X X * *
639 X X X *
640 * X X *
642 void draw_n_to_w_bit(int x, int y)
644 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER,CENTER_Y+y*MULTIPLIER+1,MODIFIER_2,MODIFIER_2);
645 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER+1,CENTER_Y+y*MULTIPLIER+2,MODIFIER_2,MODIFIER_2);
649 * * * *
650 X X * *
651 X X X *
652 * X X *
654 void draw_e_to_s_bit(int x, int y)
656 draw_n_to_w_bit(x, y);
660 * X X *
661 * X X X
662 * * X X
663 * * * *
665 void draw_s_to_e_bit(int x, int y)
667 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER+1,CENTER_Y+y*MULTIPLIER,MODIFIER_2,MODIFIER_2);
668 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER+2,CENTER_Y+y*MULTIPLIER+1,MODIFIER_2,MODIFIER_2);
672 * X X *
673 * X X X
674 * * X X
675 * * * *
677 void draw_w_to_n_bit(int x, int y)
679 draw_s_to_e_bit(x,y);
683 * X X *
684 X X X *
685 X X * *
686 * * * *
688 void draw_e_to_n_bit(int x, int y)
690 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER+1,CENTER_Y+y*MULTIPLIER,MODIFIER_2,MODIFIER_2);
691 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER,CENTER_Y+y*MULTIPLIER+1,MODIFIER_2,MODIFIER_2);
695 * X X *
696 X X X *
697 X X * *
698 * * * *
700 void draw_s_to_w_bit(int x, int y)
702 draw_e_to_n_bit(x, y);
706 ** Draws a wall/obsticals
708 void draw_boundary ( void )
710 int x, y;
712 /*TODO: Load levels from file!*/
714 /*top and bottom line*/
715 for(x=0; x < WIDTH; x++)
717 board[x][0] = EAST;
718 board[x][HEIGHT-1] = WEST;
721 /*left and right lines*/
722 for(y=0; y < HEIGHT; y++)
724 board[0][y] = NORTH;
725 board[WIDTH-1][y] = SOUTH;
728 /*corners:*/
729 board[0][0] = NORTH_EAST;
730 board[WIDTH-1][0] = EAST_SOUTH;
731 board[0][HEIGHT-1] = SOUTH_EAST;
732 board[WIDTH-1][HEIGHT-1] = EAST_NORTH;
736 ** Redraw the entire board
738 void redraw (void)
740 int x,y;
742 for (x = 0; x < WIDTH; x++)
744 for (y = 0; y < HEIGHT; y++)
746 switch (board[x][y])
748 case -1:
749 rb->lcd_fillrect((CENTER_X+x*MULTIPLIER)+1,CENTER_Y+y*MULTIPLIER,MODIFIER_2,MODIFIER_1);
750 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER,(CENTER_Y+y*MULTIPLIER)+1,MODIFIER_1,MODIFIER_2);
751 break;
752 case 0:
753 break;
755 case NORTH:
756 case SOUTH:
757 draw_vertical_bit(x,y);
758 break;
760 case EAST:
761 case WEST:
762 draw_horizontal_bit(x,y);
763 break;
765 default:
766 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER,CENTER_Y+y*MULTIPLIER,MODIFIER_1,MODIFIER_1);
767 break;
774 ** Draws the snake bit described by nCurrentBit at position x/y
775 ** deciding whether it's a corner bit by examing the nPrevious bit
777 void draw_snake_bit(int currentbit, int previousbit, int x, int y)
779 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
780 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER,CENTER_Y+y*MULTIPLIER,MODIFIER_1,MODIFIER_1);
781 rb->lcd_set_drawmode(DRMODE_SOLID);
783 switch(currentbit)
785 case(NORTH):
786 switch(previousbit)
788 case(SOUTH):
789 case(NORTH):
790 draw_vertical_bit(x,y);
791 break;
793 case(EAST):
794 draw_e_to_n_bit(x,y);
795 break;
797 case(WEST):
798 draw_w_to_n_bit(x,y);
799 break;
801 break;
803 case(EAST):
804 switch(previousbit)
806 case(WEST):
807 case(EAST):
808 draw_horizontal_bit(x,y);
809 break;
811 case(NORTH):
812 draw_n_to_e_bit(x,y);
813 break;
815 case(SOUTH):
816 draw_s_to_e_bit(x,y);
817 break;
819 break;
821 case(SOUTH):
822 switch(previousbit)
824 case(SOUTH):
825 case(NORTH):
826 draw_vertical_bit(x,y);
827 break;
829 case(EAST):
830 draw_e_to_s_bit(x,y);
831 break;
833 case(WEST):
834 draw_w_to_s_bit(x,y);
835 break;
837 break;
839 case(WEST):
840 switch(previousbit)
842 case(EAST):
843 case(WEST):
844 draw_horizontal_bit(x,y);
845 break;
847 case(SOUTH):
848 draw_s_to_w_bit(x,y);
849 break;
851 case(NORTH):
852 draw_n_to_w_bit(x,y);
853 break;
855 break;
860 ** Death 'sequence' and end game stuff.
862 void die (void)
864 int button;
865 bool done=false;
866 char pscore[20];
868 rb->splash(HZ*2, "Oops!");
870 rb->lcd_clear_display();
872 applecount=0;
874 rb->lcd_getstringsize("You died!",&strwdt,&strhgt);
875 rb->lcd_putsxy((LCD_WIDTH - strwdt)/2,strhgt,"You died!");
877 rb->snprintf(pscore,sizeof(pscore),"Your score: %d",score);
878 rb->lcd_getstringsize(pscore,&strwdt,&strhgt);
879 rb->lcd_putsxy((LCD_WIDTH - strwdt)/2,strhgt * 2 + 2,pscore);
881 if (score>hiscore)
883 hiscore=score;
884 rb->lcd_getstringsize("New high score!",&strwdt,&strhgt);
885 rb->lcd_putsxy((LCD_WIDTH - strwdt)/2,strhgt * 4 + 2,"New high score!");
887 else
889 rb->snprintf(phscore,sizeof(phscore),"High score: %d",hiscore);
890 rb->lcd_getstringsize(phscore,&strwdt,&strhgt);
891 rb->lcd_putsxy((LCD_WIDTH - strwdt)/2,strhgt * 5,phscore);
894 rb->snprintf(phscore,sizeof(phscore),"Press %s...",SNAKE2_PLAYPAUSE_TEXT);
895 rb->lcd_getstringsize(phscore,&strwdt,&strhgt);
896 rb->lcd_putsxy((LCD_WIDTH - strwdt)/2,strhgt * 7,phscore);
898 rb->lcd_update();
900 while(!done)
902 button=rb->button_get(true);
903 switch(button)
905 case SNAKE2_PLAYPAUSE:
906 done = true;
907 break;
911 dead=1;
915 ** Check for collision. TODO: Currently this
916 ** sets of the death sequence. What we want is it to only return a true/false
917 ** depending on whether a collision occured.
919 void collision ( int x, int y )
921 int bdeath=0;
924 switch (board[x][y])
926 case 0:
928 break;
929 case -1:
930 score = score + (1 * level);
931 apple=0;
932 applecountdown=2;
933 applecount++;
935 if(game_type==1)
937 if(num_apples_to_get == num_apples_to_got)
939 level_from_file++;
940 if(level_from_file >= num_levels)
942 level_from_file = 1;
943 /*and increase the number of apples to pick up
944 before level changes*/
945 num_apples_to_get+=2;
946 game_b_level++;
948 rb->splash(HZ, "Level Completed!");
949 rb->lcd_clear_display();
950 new_level(level_from_file);
951 rb->lcd_clear_display();
952 redraw();
953 rb->lcd_update();
955 else
956 num_apples_to_got++;
958 break;
959 default:
960 bdeath=1;
961 break;
964 if(bdeath==1)
966 die();
967 sillydir = dir;
968 frames = -110;
972 void move( void )
974 int taildir;
975 /*this actually sets the dir variable.*/
976 get_direction();
977 /*draw head*/
978 switch (dir)
980 case (NORTH):
981 board[headx][heady]=NORTH;
982 heady--;
983 break;
984 case (EAST):
985 board[headx][heady]=EAST;
986 headx++;
987 break;
988 case (SOUTH):
989 board[headx][heady]=SOUTH;
990 heady++;
991 break;
992 case (WEST):
993 board[headx][heady]=WEST;
994 headx--;
995 break;
998 if(headx == WIDTH)
999 headx = 0;
1000 else if(headx < 0)
1001 headx = WIDTH-1;
1003 if(heady == HEIGHT)
1004 heady = 0;
1005 else if(heady < 0)
1006 heady = HEIGHT-1;
1008 rb->lcd_fillrect(CENTER_X+headx*MULTIPLIER,CENTER_Y+heady*MULTIPLIER,MODIFIER_1,MODIFIER_1);
1010 /*clear tail*/
1011 if(applecountdown <= 0)
1013 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
1014 rb->lcd_fillrect(CENTER_X+tailx*MULTIPLIER,CENTER_Y+taily*MULTIPLIER,MODIFIER_1,MODIFIER_1);
1015 rb->lcd_set_drawmode(DRMODE_SOLID);
1017 taildir = board[tailx][taily];
1018 board[tailx][taily] = 0;
1020 switch (taildir)
1022 case(NORTH):
1023 taily--;
1024 break;
1026 case(EAST):
1027 tailx++;
1028 break;
1030 case(SOUTH):
1031 taily++;
1032 break;
1034 case(WEST):
1035 tailx--;
1036 break;
1039 if(tailx == WIDTH)
1040 tailx = 0;
1041 else if(tailx < 0)
1042 tailx = WIDTH-1;
1044 if(taily == HEIGHT)
1045 taily = 0;
1046 else if(taily < 0)
1047 taily = HEIGHT-1;
1049 else
1050 applecountdown--;
1053 void frame (void)
1055 int olddir, noldx, noldy, temp;
1056 noldx = headx;
1057 noldy = heady;
1058 olddir = 0;
1059 switch(dir)
1061 case(NORTH):
1062 if(heady == HEIGHT-1)
1063 temp = 0;
1064 else
1065 temp = heady + 1;
1067 olddir = board[headx][temp];
1068 break;
1070 case(EAST):
1071 if(headx == 0)
1072 temp = WIDTH-1;
1073 else
1074 temp = headx - 1;
1076 olddir = board[temp][heady];
1077 break;
1079 case(SOUTH):
1080 if(heady == 0)
1081 temp = HEIGHT-1;
1082 else
1083 temp = heady - 1;
1085 olddir = board[headx][temp];
1086 break;
1088 case(WEST):
1089 if(headx == WIDTH-1)
1090 temp = 0;
1091 else
1092 temp = headx + 1;
1094 olddir = board[temp][heady];
1095 break;
1098 move();
1101 now redraw the bit that was
1102 the tail, to something snake-like:
1104 draw_snake_bit(dir, olddir, noldx, noldy);
1106 collision(headx, heady);
1108 rb->lcd_update();
1111 void game_pause (void)
1113 int button;
1115 rb->lcd_clear_display();
1116 rb->lcd_getstringsize("Paused",&strwdt,&strhgt);
1117 rb->lcd_putsxy((LCD_WIDTH - strwdt)/2,LCD_HEIGHT/2,"Paused");
1119 rb->lcd_update();
1120 while (1)
1122 button = rb->button_get(true);
1123 switch (button)
1125 case SNAKE2_PLAYPAUSE:
1126 rb->lcd_clear_display();
1127 redraw();
1128 rb->lcd_update();
1129 rb->sleep(HZ/2);
1130 return;
1132 #ifdef SNAKE2_RC_QUIT
1133 case SNAKE2_RC_QUIT:
1134 #endif
1135 case SNAKE2_QUIT:
1136 dead = 1;
1137 quit = 1;
1138 return;
1140 default:
1141 if (rb->default_event_handler(button)==SYS_USB_CONNECTED) {
1142 dead = 1;
1143 quit = 2;
1144 return;
1146 break;
1151 void game (void)
1153 int button;
1155 rb->lcd_clear_display();
1156 redraw();
1157 rb->lcd_update();
1158 /*main loop:*/
1159 while (1)
1161 if(frames==5)
1163 frame();
1164 if(frames>0) frames=0;
1166 frames++;
1168 if(frames == 0)
1170 die();
1172 else
1174 if(frames < 0)
1176 if(sillydir != dir)
1178 /*it has, great set frames to a positive value again:*/
1179 frames = 1;
1184 if (dead) return;
1186 draw_apple();
1188 rb->sleep(HZ/speed);
1190 button = rb->button_get(false);
1192 #ifdef HAS_BUTTON_HOLD
1193 if (rb->button_hold())
1194 button = SNAKE2_PLAYPAUSE;
1195 #endif
1197 switch (button)
1199 case SNAKE2_UP:
1200 case SNAKE2_UP | BUTTON_REPEAT:
1201 if (dir != SOUTH) set_direction(NORTH);
1202 break;
1204 case SNAKE2_RIGHT:
1205 case SNAKE2_RIGHT | BUTTON_REPEAT:
1206 if (dir != WEST) set_direction(EAST);
1207 break;
1209 case SNAKE2_DOWN:
1210 case SNAKE2_DOWN | BUTTON_REPEAT:
1211 if (dir != NORTH) set_direction(SOUTH);
1212 break;
1214 case SNAKE2_LEFT:
1215 case SNAKE2_LEFT | BUTTON_REPEAT:
1216 if (dir != EAST) set_direction(WEST);
1217 break;
1219 #ifdef SNAKE2_RC_QUIT
1220 case SNAKE2_RC_QUIT:
1221 #endif
1222 case SNAKE2_QUIT:
1223 dead=1;
1224 return;
1226 case SNAKE2_PLAYPAUSE:
1227 game_pause();
1228 break;
1230 default:
1231 if (rb->default_event_handler(button)==SYS_USB_CONNECTED) {
1232 quit = 2;
1233 return;
1235 break;
1241 void game_init(void)
1243 int button;
1244 char plevel[30];
1246 dead=0;
1247 apple=0;
1248 score=0;
1249 applecount=0;
1251 clear_board();
1252 load_level( level_from_file );
1253 rb->lcd_clear_display();
1254 redraw();
1255 rb->lcd_update();
1257 while (1)
1259 #if LCD_WIDTH >= 160 && LCD_HEIGHT >= 128
1261 rb->lcd_bitmap(snake2_header1,0,0,BMPWIDTH_snake2_header, BMPHEIGHT_snake2_header);
1262 rb->lcd_bitmap(snake2_left,0,BMPHEIGHT_snake2_header,BMPWIDTH_snake2_left, BMPHEIGHT_snake2_left);
1263 rb->lcd_bitmap(snake2_right,LCD_WIDTH-BMPWIDTH_snake2_right,BMPHEIGHT_snake2_header,BMPWIDTH_snake2_right, BMPHEIGHT_snake2_right);
1264 rb->lcd_bitmap(snake2_bottom,0,BMPHEIGHT_snake2_header+BMPHEIGHT_snake2_left,BMPWIDTH_snake2_bottom, BMPHEIGHT_snake2_bottom);
1266 rb->snprintf(plevel,sizeof(plevel),"%d",level);
1267 rb->lcd_getstringsize(plevel,&strwdt,&strhgt);
1268 rb->lcd_putsxy(TOP_X3-strwdt/2,TOP_Y2, plevel);
1270 rb->snprintf(plevel,sizeof(plevel),"%d",level_from_file);
1271 rb->lcd_getstringsize(plevel,&strwdt,&strhgt);
1272 rb->lcd_putsxy(TOP_X2-strwdt/2,TOP_Y1, plevel);
1274 if(game_type==0){
1275 rb->lcd_getstringsize("A",&strwdt,&strhgt);
1276 rb->lcd_putsxy(TOP_X1,TOP_Y1,"A");
1278 else{
1279 rb->lcd_getstringsize("B",&strwdt,&strhgt);
1280 rb->lcd_putsxy(TOP_X1,TOP_Y1,"B");
1283 rb->snprintf(phscore,sizeof(phscore),"%d",hiscore);
1284 rb->lcd_getstringsize(phscore,&strwdt,&strhgt);
1285 rb->lcd_putsxy(TOP_X4-strwdt/2,TOP_Y2, phscore);
1287 #else
1288 rb->snprintf(plevel,sizeof(plevel),"Speed: %02d",level);
1289 rb->lcd_getstringsize("Speed: 00",&strwdt,&strhgt);
1290 rb->lcd_putsxy((LCD_WIDTH - strwdt)/2,strhgt+4, plevel);
1292 rb->snprintf(plevel,sizeof(plevel),"Maze: %d",level_from_file);
1293 rb->lcd_getstringsize(plevel,&strwdt,&strhgt);
1294 rb->lcd_putsxy((LCD_WIDTH - strwdt)/2,strhgt*2+4, plevel);
1296 if(game_type==0){
1297 rb->lcd_getstringsize("Game Type: A ",&strwdt,&strhgt);
1298 rb->lcd_putsxy((LCD_WIDTH - strwdt)/2,strhgt*3+4,"Game Type: A");
1300 else{
1301 rb->lcd_getstringsize("Game Type: B ",&strwdt,&strhgt);
1302 rb->lcd_putsxy((LCD_WIDTH - strwdt)/2,strhgt*3+4,"Game Type: B");
1305 rb->snprintf(phscore,sizeof(phscore),"Hi Score: %d",hiscore);
1306 rb->lcd_getstringsize(phscore,&strwdt,&strhgt);
1307 rb->lcd_putsxy((LCD_WIDTH - strwdt)/2,strhgt*4+4, phscore);
1308 #endif
1310 rb->lcd_update();
1312 button=rb->button_get(true);
1313 switch (button)
1315 case SNAKE2_LEVEL_UP:
1316 case SNAKE2_LEVEL_UP|BUTTON_REPEAT:
1317 if (level<10)
1318 level+=1;
1319 break;
1320 case SNAKE2_LEVEL_DOWN:
1321 case SNAKE2_LEVEL_DOWN|BUTTON_REPEAT:
1322 if (level>1)
1323 level-=1;
1324 break;
1325 case SNAKE2_QUIT:
1326 quit=1;
1327 return;
1328 break;
1329 case SNAKE2_PLAYPAUSE:
1330 speed = level*20;
1331 return;
1332 break;
1333 case SNAKE2_SELECT_TYPE:
1334 if(game_type==0)game_type=1; else game_type=0;
1335 break;
1336 case SNAKE2_MAZE_NEXT:
1337 rb->lcd_set_drawmode(DRMODE_BG|DRMODE_INVERSEVID);
1338 rb->lcd_fillrect(CENTER_X, CENTER_Y, CENTER_X+WIDTH*MULTIPLIER,
1339 CENTER_Y+HEIGHT*MULTIPLIER);
1340 rb->lcd_set_drawmode(DRMODE_SOLID);
1341 if(level_from_file < num_levels)
1342 level_from_file++;
1343 else
1344 level_from_file = 0;
1345 load_level( level_from_file );
1346 redraw();
1347 break;
1348 #ifdef SNAKE2_MAZE_LAST
1349 case SNAKE2_MAZE_LAST:
1350 rb->lcd_set_drawmode(DRMODE_BG|DRMODE_INVERSEVID);
1351 rb->lcd_fillrect(CENTER_X, CENTER_Y, CENTER_X+WIDTH*MULTIPLIER,
1352 CENTER_Y+HEIGHT*MULTIPLIER);
1353 rb->lcd_set_drawmode(DRMODE_SOLID);
1354 if(level_from_file > 0)
1355 level_from_file--;
1356 else
1357 level_from_file = num_levels;
1358 load_level( level_from_file );
1359 redraw();
1360 break;
1361 #endif
1362 default:
1363 if (rb->default_event_handler(button)==SYS_USB_CONNECTED) {
1364 quit = 2;
1365 return;
1367 break;
1373 enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
1375 (void)(parameter);
1376 rb = api;
1378 /* Lets use the default font */
1379 rb->lcd_setfont(FONT_SYSFIXED);
1380 #if LCD_DEPTH > 1
1381 rb->lcd_set_backdrop(NULL);
1382 #endif
1383 #ifdef HAVE_LCD_COLOR
1384 rb->lcd_set_foreground(LCD_BLACK);
1385 rb->lcd_set_background(LCD_WHITE);
1386 #endif
1388 load_all_levels();
1390 if (num_levels == 0) {
1391 rb->splash(HZ*2, "Failed loading levels!");
1392 return PLUGIN_OK;
1395 iohiscore();
1397 while(quit==0)
1399 game_init();
1400 rb->lcd_clear_display();
1401 frames=1;
1403 if(quit==0)
1405 init_snake();
1407 /*Start Game:*/
1408 game();
1412 iohiscore();
1413 return (quit==1) ? PLUGIN_OK : PLUGIN_USB_CONNECTED;
1416 #endif