Updated our source code header to explicitly mention that we are GPL v2 or
[Rockbox.git] / apps / plugins / snake2.c
blobff868538f323200105cf0455d852bd6ee0b8f24b
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2003 Mat Holton
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
23 Snake2!
25 Board consists of a WIDTHxHEIGHT grid. If board element is 0 then nothing is
26 there otherwise it is part of the snake or a wall.
28 Head and Tail are stored
32 #include "plugin.h"
33 #ifdef HAVE_LCD_BITMAP
35 PLUGIN_HEADER
37 #define WIDTH 28
38 #define HEIGHT 16
40 #if (LCD_WIDTH >= 160) && (LCD_HEIGHT >= 128) && (LCD_DEPTH >= 1)
41 #include "snake2_header1.h"
42 #include "snake2_header2.h"
43 #include "snake2_left.h"
44 #include "snake2_right.h"
45 #include "snake2_bottom.h"
46 #define BMPHEIGHT_snake2_header BMPHEIGHT_snake2_header1
47 #define BMPWIDTH_snake2_header BMPWIDTH_snake2_header1
48 #endif
51 #if (LCD_WIDTH >= 320) && (LCD_HEIGHT >= 240)
52 #define MULTIPLIER 10 /*Modifier for porting on other screens*/
53 #define MODIFIER_1 10
54 #define MODIFIER_2 8
55 #define CENTER_X 20
56 #define CENTER_Y 55
57 #define TOP_X1 34 /* x-coord of the upperleft item (game type) */
58 #define TOP_X2 281 /* x-coord of the upperright item (maze type) */
59 #define TOP_X3 42 /* x-coord of the lowerleft item (speed) */
60 #define TOP_X4 274 /* x-coord of the lowerright item (hi-score) */
61 #define TOP_Y1 4 /* y-coord of the top row of items */
62 #define TOP_Y2 25 /* y-coord of the bottom row of items */
63 #elif (LCD_WIDTH >= 240) && (LCD_HEIGHT >= 168)
64 #define MULTIPLIER 8
65 #define MODIFIER_1 8
66 #define MODIFIER_2 6
67 #define CENTER_X 8
68 #define CENTER_Y 34
69 #define TOP_X1 34
70 #define TOP_X2 201
71 #define TOP_X3 42
72 #define TOP_X4 194
73 #define TOP_Y1 4
74 #define TOP_Y2 25
75 #elif (LCD_WIDTH >= 220) && (LCD_HEIGHT >= 176)
76 #define MULTIPLIER 7
77 #define MODIFIER_1 7
78 #define MODIFIER_2 5
79 #define CENTER_X 12
80 #define CENTER_Y 46
81 #define TOP_X1 34
82 #define TOP_X2 181
83 #define TOP_X3 42
84 #define TOP_X4 174
85 #define TOP_Y1 4
86 #define TOP_Y2 25
87 #elif (LCD_WIDTH >= 176) && (LCD_HEIGHT >= 132)
88 #define MULTIPLIER 5
89 #define MODIFIER_1 5
90 #define MODIFIER_2 3
91 #define CENTER_X 18
92 #define CENTER_Y 40
93 #define TOP_X1 34
94 #define TOP_X2 137
95 #define TOP_X3 42
96 #define TOP_X4 130
97 #define TOP_Y1 4
98 #define TOP_Y2 25
99 #elif (LCD_WIDTH >= 160) && (LCD_HEIGHT >= 128)
100 #define MULTIPLIER 5
101 #define MODIFIER_1 5
102 #define MODIFIER_2 3
103 #define CENTER_X 10
104 #define CENTER_Y 38
105 #define TOP_X1 34
106 #define TOP_X2 121
107 #define TOP_X3 42
108 #define TOP_X4 114
109 #define TOP_Y1 4
110 #define TOP_Y2 25
111 #else
112 #define MULTIPLIER 4
113 #define MODIFIER_1 4
114 #define MODIFIER_2 2
115 #define CENTER_X 0
116 #define CENTER_Y 0
118 #endif
120 /* variable button definitions */
121 #if CONFIG_KEYPAD == RECORDER_PAD
122 #define SNAKE2_LEFT BUTTON_LEFT
123 #define SNAKE2_RIGHT BUTTON_RIGHT
124 #define SNAKE2_UP BUTTON_UP
125 #define SNAKE2_DOWN BUTTON_DOWN
126 #define SNAKE2_QUIT BUTTON_OFF
127 #define SNAKE2_LEVEL_UP BUTTON_UP
128 #define SNAKE2_LEVEL_DOWN BUTTON_DOWN
129 #define SNAKE2_MAZE_NEXT BUTTON_RIGHT
130 #define SNAKE2_MAZE_LAST BUTTON_LEFT
131 #define SNAKE2_SELECT_TYPE BUTTON_F3
132 #define SNAKE2_PLAYPAUSE BUTTON_PLAY
133 #define SNAKE2_PLAYPAUSE_TEXT "Play"
135 #elif CONFIG_KEYPAD == ARCHOS_AV300_PAD
136 #define SNAKE2_LEFT BUTTON_LEFT
137 #define SNAKE2_RIGHT BUTTON_RIGHT
138 #define SNAKE2_UP BUTTON_UP
139 #define SNAKE2_DOWN BUTTON_DOWN
140 #define SNAKE2_QUIT BUTTON_OFF
141 #define SNAKE2_LEVEL_UP BUTTON_UP
142 #define SNAKE2_LEVEL_DOWN BUTTON_DOWN
143 #define SNAKE2_MAZE_NEXT BUTTON_RIGHT
144 #define SNAKE2_MAZE_LAST BUTTON_LEFT
145 #define SNAKE2_SELECT_TYPE BUTTON_F3
146 #define SNAKE2_PLAYPAUSE BUTTON_SELECT
147 #define SNAKE2_PLAYPAUSE_TEXT "Select"
149 #elif CONFIG_KEYPAD == ONDIO_PAD
150 #define SNAKE2_LEFT BUTTON_LEFT
151 #define SNAKE2_RIGHT BUTTON_RIGHT
152 #define SNAKE2_UP BUTTON_UP
153 #define SNAKE2_DOWN BUTTON_DOWN
154 #define SNAKE2_QUIT BUTTON_OFF
155 #define SNAKE2_LEVEL_UP BUTTON_UP
156 #define SNAKE2_LEVEL_DOWN BUTTON_DOWN
157 #define SNAKE2_MAZE_NEXT BUTTON_RIGHT
158 #define SNAKE2_SELECT_TYPE BUTTON_LEFT
159 #define SNAKE2_PLAYPAUSE BUTTON_MENU
160 #define SNAKE2_PLAYPAUSE_TEXT "Menu"
162 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
163 (CONFIG_KEYPAD == IRIVER_H300_PAD)
164 #define SNAKE2_LEFT BUTTON_LEFT
165 #define SNAKE2_RIGHT BUTTON_RIGHT
166 #define SNAKE2_UP BUTTON_UP
167 #define SNAKE2_DOWN BUTTON_DOWN
168 #define SNAKE2_QUIT BUTTON_OFF
169 #define SNAKE2_LEVEL_UP BUTTON_UP
170 #define SNAKE2_LEVEL_DOWN BUTTON_DOWN
171 #define SNAKE2_MAZE_NEXT BUTTON_RIGHT
172 #define SNAKE2_MAZE_LAST BUTTON_LEFT
173 #define SNAKE2_SELECT_TYPE BUTTON_MODE
174 #define SNAKE2_PLAYPAUSE BUTTON_ON
175 #define SNAKE2_PLAYPAUSE_TEXT "Play"
177 #define SNAKE2_RC_QUIT BUTTON_RC_STOP
178 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \
179 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
180 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
181 #define SNAKE2_LEFT BUTTON_LEFT
182 #define SNAKE2_RIGHT BUTTON_RIGHT
183 #define SNAKE2_UP BUTTON_MENU
184 #define SNAKE2_DOWN BUTTON_PLAY
185 #define SNAKE2_QUIT (BUTTON_SELECT | BUTTON_MENU)
186 #define SNAKE2_LEVEL_UP BUTTON_SCROLL_FWD
187 #define SNAKE2_LEVEL_DOWN BUTTON_SCROLL_BACK
188 #define SNAKE2_MAZE_NEXT BUTTON_RIGHT
189 #define SNAKE2_MAZE_LAST BUTTON_LEFT
190 #define SNAKE2_SELECT_TYPE BUTTON_PLAY
191 #define SNAKE2_PLAYPAUSE BUTTON_SELECT
192 #define SNAKE2_PLAYPAUSE_TEXT "Select"
194 #elif (CONFIG_KEYPAD == IAUDIO_X5M5_PAD)
195 #define SNAKE2_LEFT BUTTON_LEFT
196 #define SNAKE2_RIGHT BUTTON_RIGHT
197 #define SNAKE2_UP BUTTON_UP
198 #define SNAKE2_DOWN BUTTON_DOWN
199 #define SNAKE2_QUIT BUTTON_POWER
200 #define SNAKE2_LEVEL_UP BUTTON_UP
201 #define SNAKE2_LEVEL_DOWN BUTTON_DOWN
202 #define SNAKE2_MAZE_NEXT BUTTON_RIGHT
203 #define SNAKE2_MAZE_LAST BUTTON_LEFT
204 #define SNAKE2_SELECT_TYPE BUTTON_PLAY
205 #define SNAKE2_PLAYPAUSE BUTTON_SELECT
206 #define SNAKE2_PLAYPAUSE_TEXT "Select"
208 #elif (CONFIG_KEYPAD == GIGABEAT_PAD)
209 #define SNAKE2_LEFT BUTTON_LEFT
210 #define SNAKE2_RIGHT BUTTON_RIGHT
211 #define SNAKE2_UP BUTTON_UP
212 #define SNAKE2_DOWN BUTTON_DOWN
213 #define SNAKE2_QUIT BUTTON_POWER
214 #define SNAKE2_LEVEL_UP BUTTON_UP
215 #define SNAKE2_LEVEL_DOWN BUTTON_DOWN
216 #define SNAKE2_MAZE_NEXT BUTTON_RIGHT
217 #define SNAKE2_MAZE_LAST BUTTON_LEFT
218 #define SNAKE2_SELECT_TYPE BUTTON_MENU
219 #define SNAKE2_PLAYPAUSE BUTTON_SELECT
220 #define SNAKE2_PLAYPAUSE_TEXT "Select"
222 #elif (CONFIG_KEYPAD == SANSA_E200_PAD) || \
223 (CONFIG_KEYPAD == SANSA_C200_PAD)
224 #define SNAKE2_LEFT BUTTON_LEFT
225 #define SNAKE2_RIGHT BUTTON_RIGHT
226 #define SNAKE2_UP BUTTON_UP
227 #define SNAKE2_DOWN BUTTON_DOWN
228 #define SNAKE2_QUIT BUTTON_POWER
229 #define SNAKE2_LEVEL_UP BUTTON_UP
230 #define SNAKE2_LEVEL_DOWN BUTTON_DOWN
231 #define SNAKE2_MAZE_NEXT BUTTON_RIGHT
232 #define SNAKE2_MAZE_LAST BUTTON_LEFT
233 #define SNAKE2_SELECT_TYPE BUTTON_REC
234 #define SNAKE2_PLAYPAUSE BUTTON_SELECT
235 #define SNAKE2_PLAYPAUSE_TEXT "Select"
237 #elif (CONFIG_KEYPAD == IRIVER_H10_PAD)
238 #define SNAKE2_LEFT BUTTON_LEFT
239 #define SNAKE2_RIGHT BUTTON_RIGHT
240 #define SNAKE2_UP BUTTON_SCROLL_UP
241 #define SNAKE2_DOWN BUTTON_SCROLL_DOWN
242 #define SNAKE2_QUIT BUTTON_POWER
243 #define SNAKE2_LEVEL_UP BUTTON_SCROLL_UP
244 #define SNAKE2_LEVEL_DOWN BUTTON_SCROLL_DOWN
245 #define SNAKE2_MAZE_NEXT BUTTON_RIGHT
246 #define SNAKE2_MAZE_LAST BUTTON_LEFT
247 #define SNAKE2_SELECT_TYPE BUTTON_PLAY
248 #define SNAKE2_PLAYPAUSE BUTTON_FF
249 #define SNAKE2_PLAYPAUSE_TEXT "FF"
251 #elif (CONFIG_KEYPAD == GIGABEAT_S_PAD)
252 #define SNAKE2_LEFT BUTTON_LEFT
253 #define SNAKE2_RIGHT BUTTON_RIGHT
254 #define SNAKE2_UP BUTTON_UP
255 #define SNAKE2_DOWN BUTTON_DOWN
256 #define SNAKE2_QUIT BUTTON_BACK
257 #define SNAKE2_LEVEL_UP BUTTON_UP
258 #define SNAKE2_LEVEL_DOWN BUTTON_DOWN
259 #define SNAKE2_MAZE_NEXT BUTTON_RIGHT
260 #define SNAKE2_MAZE_LAST BUTTON_LEFT
261 #define SNAKE2_SELECT_TYPE BUTTON_MENU
262 #define SNAKE2_PLAYPAUSE BUTTON_SELECT
263 #define SNAKE2_PLAYPAUSE_TEXT "Select"
265 #elif (CONFIG_KEYPAD == MROBE100_PAD)
266 #define SNAKE2_LEFT BUTTON_LEFT
267 #define SNAKE2_RIGHT BUTTON_RIGHT
268 #define SNAKE2_UP BUTTON_UP
269 #define SNAKE2_DOWN BUTTON_DOWN
270 #define SNAKE2_QUIT BUTTON_POWER
271 #define SNAKE2_LEVEL_UP BUTTON_UP
272 #define SNAKE2_LEVEL_DOWN BUTTON_DOWN
273 #define SNAKE2_MAZE_NEXT BUTTON_RIGHT
274 #define SNAKE2_MAZE_LAST BUTTON_LEFT
275 #define SNAKE2_SELECT_TYPE BUTTON_MENU
276 #define SNAKE2_PLAYPAUSE BUTTON_SELECT
277 #define SNAKE2_PLAYPAUSE_TEXT "Select"
279 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
280 #define SNAKE2_LEFT BUTTON_RC_REW
281 #define SNAKE2_RIGHT BUTTON_RC_FF
282 #define SNAKE2_UP BUTTON_RC_VOL_UP
283 #define SNAKE2_DOWN BUTTON_RC_VOL_DOWN
284 #define SNAKE2_QUIT BUTTON_RC_REC
285 #define SNAKE2_LEVEL_UP BUTTON_RC_VOL_UP
286 #define SNAKE2_LEVEL_DOWN BUTTON_RC_VOL_DOWN
287 #define SNAKE2_MAZE_NEXT BUTTON_RC_FF
288 #define SNAKE2_MAZE_LAST BUTTON_RC_REW
289 #define SNAKE2_SELECT_TYPE BUTTON_RC_MODE
290 #define SNAKE2_PLAYPAUSE BUTTON_RC_PLAY
291 #define SNAKE2_PLAYPAUSE_TEXT "Play"
293 #elif (CONFIG_KEYPAD == COWOND2_PAD)
294 #define SNAKE2_QUIT BUTTON_POWER
296 #else
297 #error No keymap defined!
298 #endif
300 #ifdef HAVE_TOUCHPAD
301 #ifndef SNAKE2_LEFT
302 #define SNAKE2_LEFT BUTTON_MIDLEFT
303 #endif
304 #ifndef SNAKE2_RIGHT
305 #define SNAKE2_RIGHT BUTTON_MIDRIGHT
306 #endif
307 #ifndef SNAKE2_UP
308 #define SNAKE2_UP BUTTON_TOPMIDDLE
309 #endif
310 #ifndef SNAKE2_DOWN
311 #define SNAKE2_DOWN BUTTON_BOTTOMMIDDLE
312 #endif
313 #ifndef SNAKE2_QUIT
314 #define SNAKE2_QUIT BUTTON_TOPLEFT
315 #endif
316 #ifndef SNAKE2_LEVEL_UP
317 #define SNAKE2_LEVEL_UP BUTTON_TOPRIGHT
318 #endif
319 #ifndef SNAKE2_LEVEL_DOWN
320 #define SNAKE2_LEVEL_DOWN BUTTON_TOPLEFT
321 #endif
322 #ifndef SNAKE2_MAZE_NEXT
323 #define SNAKE2_MAZE_NEXT BUTTON_TOPMIDDLE
324 #endif
325 #ifndef SNAKE2_MAZE_LAST
326 #define SNAKE2_MAZE_LAST BUTTON_BOTTOMMIDDLE
327 #endif
328 #ifndef SNAKE2_SELECT_TYPE
329 #define SNAKE2_SELECT_TYPE BUTTON_BOTTOMLEFT
330 #endif
331 #ifndef SNAKE2_PLAYPAUSE
332 #define SNAKE2_PLAYPAUSE BUTTON_CENTER
333 #endif
334 #ifndef SNAKE2_PLAYPAUSE_TEXT
335 #define SNAKE2_PLAYPAUSE_TEXT "CENTER"
336 #endif
337 #endif
339 static int max_levels = 0;
340 static char (*level_cache)[HEIGHT][WIDTH];
342 /*Board itself - 2D int array*/
343 static int board[WIDTH][HEIGHT];
345 Buffer for sorting movement (in case user presses two movements during a
346 single frame
348 static int ardirectionbuffer[2];
349 static unsigned int score, hiscore = 0;
350 static int applex;
351 static int appley;
352 static int strwdt,strhgt; /*used for string width, height for orientation purposes*/
353 static int dir;
354 static int frames;
355 static int apple;
356 static int level = 4, speed = 5,dead = 0, quit = 0;
357 static int sillydir = 0, num_levels = 0;
358 static int level_from_file = 0;
359 static const struct plugin_api* rb;
360 static int headx, heady, tailx, taily, applecountdown = 5;
361 static int game_type = 0;
362 static int num_apples_to_get=1;
363 static int num_apples_to_got=0;
364 static int game_b_level=0;
365 static int applecount=0;
366 static char phscore[30];
368 #define NORTH 1
369 #define EAST 2
370 #define SOUTH 4
371 #define WEST 8
372 #define HEAD 16
374 #define EAST_NORTH 32
375 #define EAST_SOUTH 64
376 #define WEST_NORTH 128
377 #define WEST_SOUTH 256
379 #define NORTH_EAST 512
380 #define NORTH_WEST 1024
381 #define SOUTH_EAST 2048
382 #define SOUTH_WEST 4096
384 #define LEVELS_FILE PLUGIN_GAMES_DIR "/snake2.levels"
385 #define HISCORE_FILE PLUGIN_GAMES_DIR "/snake2.hs"
387 int load_all_levels(void)
389 int linecnt = 0;
390 int fd;
391 ssize_t size;
392 char buf[64]; /* Larger than WIDTH, to allow for whitespace after the
393 lines */
395 /* Init the level_cache pointer and
396 calculate how many levels that will fit */
397 level_cache = rb->plugin_get_buffer((size_t *)&size);
398 max_levels = size / (HEIGHT*WIDTH);
400 num_levels = 0;
402 /* open file */
403 if ((fd = rb->open(LEVELS_FILE, O_RDONLY)) < 0)
405 return -1;
408 while(rb->read_line(fd, buf, 64))
410 if(rb->strlen(buf) == 0) /* Separator? */
412 num_levels++;
413 if(num_levels > max_levels)
415 rb->splash(HZ, "Too many levels in file");
416 break;
418 continue;
421 rb->memcpy(level_cache[num_levels][linecnt], buf, WIDTH);
422 linecnt++;
423 if(linecnt == HEIGHT)
425 linecnt = 0;
429 rb->close(fd);
430 return 0;
433 /*Hi-Score reading and writing to file "/.rockbox/rocks/games/snake2.levels" function */
434 void iohiscore(void)
436 int fd;
437 unsigned int compare;
439 /* clear the buffer we're about to load the highscore data into */
440 rb->memset(phscore, 0, sizeof(phscore));
442 fd = rb->open(HISCORE_FILE,O_RDWR | O_CREAT);
444 /* highscore used to %d, is now %d\n
445 Deal with no file or bad file */
446 rb->read(fd,phscore, sizeof(phscore));
448 compare = rb->atoi(phscore);
450 if(hiscore > compare){
451 rb->lseek(fd,0,SEEK_SET);
452 rb->fdprintf(fd, "%d\n", hiscore);
454 else
455 hiscore = compare;
457 rb->close(fd);
462 ** Completely clear the board of walls and/or snake */
464 void clear_board( void)
466 int x,y;
468 for (x = 0; x < WIDTH; x++)
470 for (y = 0; y < HEIGHT; y++)
472 board[x][y] = 0;
477 int load_level( int level_number )
479 int x,y;
480 clear_board();
481 for(y = 0;y < HEIGHT;y++)
483 for(x = 0;x < WIDTH;x++)
485 switch(level_cache[level_number][y][x])
487 case '|':
488 board[x][y] = NORTH;
489 break;
491 case '-':
492 board[x][y] = EAST;
493 break;
495 case '+':
496 board[x][y] = HEAD;
497 break;
501 return 1;
505 ** Gets the currently chosen direction from the first place
506 ** in the direction buffer. If there is something in the
507 ** next part of the buffer then that is moved to the first place
509 void get_direction( void )
511 /*if 1st place is empty*/
512 if(ardirectionbuffer[0] != -1)
514 /*return this direction*/
515 dir = ardirectionbuffer[0];
516 ardirectionbuffer[0]=-1;
517 /*now see if one needs moving:*/
518 if(ardirectionbuffer[1] != -1)
520 /*there's a move waiting to be done
521 so move it into the space:*/
522 ardirectionbuffer[0] = ardirectionbuffer[1];
523 ardirectionbuffer[1] = -1;
529 ** Sets the direction
531 void set_direction(int newdir)
533 if(ardirectionbuffer[0] != newdir)
535 /*if 1st place is empty*/
536 if(ardirectionbuffer[0] == -1)
538 /*use 1st space:*/
539 ardirectionbuffer[0] = newdir;
541 else
543 /*use 2nd space:*/
544 if(ardirectionbuffer[0] != newdir) ardirectionbuffer[1] = newdir;
547 if(frames < 0) ardirectionbuffer[0] = newdir;
551 void new_level(int level)
553 load_level(level);
555 ardirectionbuffer[0] = -1;
556 ardirectionbuffer[1] = -1;
557 dir = EAST;
558 headx = WIDTH/2;
559 heady = HEIGHT/2;
560 tailx = headx - 4;
561 taily = heady;
562 applecountdown = 0;
563 /*Create a small snake to start off with*/
564 board[headx][heady] = dir;
565 board[headx-1][heady] = dir;
566 board[headx-2][heady] = dir;
567 board[headx-3][heady] = dir;
568 board[headx-4][heady] = dir;
569 num_apples_to_got=0;
572 void init_snake(void)
574 num_apples_to_get=1;
575 if(game_type == 1)
576 level_from_file = 1;
577 game_b_level=1;
578 new_level(level_from_file);
582 ** Draws the apple. If it doesn't exist then
583 ** a new one get's created.
585 void draw_apple( void )
587 int x,y;
589 #if LCD_WIDTH >= 160 && LCD_HEIGHT >= 128
590 char pscore[5], counter[4];
592 rb->lcd_bitmap(snake2_header2,0,0,BMPWIDTH_snake2_header, BMPHEIGHT_snake2_header);
593 rb->lcd_bitmap(snake2_left,0,BMPHEIGHT_snake2_header,BMPWIDTH_snake2_left, BMPHEIGHT_snake2_left);
594 rb->lcd_bitmap(snake2_right,LCD_WIDTH-BMPWIDTH_snake2_right,BMPHEIGHT_snake2_header,BMPWIDTH_snake2_right, BMPHEIGHT_snake2_right);
595 rb->lcd_bitmap(snake2_bottom,0,BMPHEIGHT_snake2_header+BMPHEIGHT_snake2_left,BMPWIDTH_snake2_bottom, BMPHEIGHT_snake2_bottom);
597 rb->snprintf(counter,sizeof(counter),"%d",applecount);
598 rb->lcd_getstringsize(counter,&strwdt,&strhgt);
599 rb->lcd_putsxy(TOP_X3-strwdt/2,TOP_Y2,counter);
601 rb->snprintf(pscore,sizeof(pscore),"%d",score);
602 rb->lcd_getstringsize(pscore,&strwdt,&strhgt);
603 rb->lcd_putsxy(TOP_X4-strwdt/2,TOP_Y2,pscore);
604 #endif
606 if (!apple)
610 x = (rb->rand() % (WIDTH-1))+1;
611 y = (rb->rand() % (HEIGHT-1))+1;
612 } while (board[x][y]);
613 apple=1;
614 board[x][y]=-1;
615 applex = x;appley = y;
617 rb->lcd_fillrect((CENTER_X+applex*MULTIPLIER)+1,CENTER_Y+appley*MULTIPLIER,MODIFIER_2,MODIFIER_1);
618 rb->lcd_fillrect(CENTER_X+applex*MULTIPLIER,(CENTER_Y+appley*MULTIPLIER)+1,MODIFIER_1,MODIFIER_2);
622 * x x *
623 * x x *
624 * x x *
625 * x x *
627 void draw_vertical_bit(int x, int y)
629 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER+1,CENTER_Y+y*MULTIPLIER,MODIFIER_2,MODIFIER_1);
633 * * * *
634 X X X X
635 X X X X
636 * * * *
638 void draw_horizontal_bit(int x, int y)
640 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER,CENTER_Y+y*MULTIPLIER+1,MODIFIER_1,MODIFIER_2);
644 * * * *
645 * * X X
646 * X X X
647 * X X *
649 void draw_n_to_e_bit(int x, int y)
651 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER+1,CENTER_Y+y*MULTIPLIER+2,MODIFIER_2,MODIFIER_2);
652 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER+2,CENTER_Y+y*MULTIPLIER+1,MODIFIER_2,MODIFIER_2);
656 * * * *
657 * * X X
658 * X X X
659 * X X *
661 void draw_w_to_s_bit(int x, int y)
663 draw_n_to_e_bit(x,y);
667 * * * *
668 X X * *
669 X X X *
670 * X X *
672 void draw_n_to_w_bit(int x, int y)
674 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER,CENTER_Y+y*MULTIPLIER+1,MODIFIER_2,MODIFIER_2);
675 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER+1,CENTER_Y+y*MULTIPLIER+2,MODIFIER_2,MODIFIER_2);
679 * * * *
680 X X * *
681 X X X *
682 * X X *
684 void draw_e_to_s_bit(int x, int y)
686 draw_n_to_w_bit(x, y);
690 * X X *
691 * X X X
692 * * X X
693 * * * *
695 void draw_s_to_e_bit(int x, int y)
697 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER+1,CENTER_Y+y*MULTIPLIER,MODIFIER_2,MODIFIER_2);
698 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER+2,CENTER_Y+y*MULTIPLIER+1,MODIFIER_2,MODIFIER_2);
702 * X X *
703 * X X X
704 * * X X
705 * * * *
707 void draw_w_to_n_bit(int x, int y)
709 draw_s_to_e_bit(x,y);
713 * X X *
714 X X X *
715 X X * *
716 * * * *
718 void draw_e_to_n_bit(int x, int y)
720 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER+1,CENTER_Y+y*MULTIPLIER,MODIFIER_2,MODIFIER_2);
721 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER,CENTER_Y+y*MULTIPLIER+1,MODIFIER_2,MODIFIER_2);
725 * X X *
726 X X X *
727 X X * *
728 * * * *
730 void draw_s_to_w_bit(int x, int y)
732 draw_e_to_n_bit(x, y);
736 ** Draws a wall/obsticals
738 void draw_boundary ( void )
740 int x, y;
742 /*TODO: Load levels from file!*/
744 /*top and bottom line*/
745 for(x=0; x < WIDTH; x++)
747 board[x][0] = EAST;
748 board[x][HEIGHT-1] = WEST;
751 /*left and right lines*/
752 for(y=0; y < HEIGHT; y++)
754 board[0][y] = NORTH;
755 board[WIDTH-1][y] = SOUTH;
758 /*corners:*/
759 board[0][0] = NORTH_EAST;
760 board[WIDTH-1][0] = EAST_SOUTH;
761 board[0][HEIGHT-1] = SOUTH_EAST;
762 board[WIDTH-1][HEIGHT-1] = EAST_NORTH;
766 ** Redraw the entire board
768 void redraw (void)
770 int x,y;
772 for (x = 0; x < WIDTH; x++)
774 for (y = 0; y < HEIGHT; y++)
776 switch (board[x][y])
778 case -1:
779 rb->lcd_fillrect((CENTER_X+x*MULTIPLIER)+1,CENTER_Y+y*MULTIPLIER,MODIFIER_2,MODIFIER_1);
780 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER,(CENTER_Y+y*MULTIPLIER)+1,MODIFIER_1,MODIFIER_2);
781 break;
782 case 0:
783 break;
785 case NORTH:
786 case SOUTH:
787 draw_vertical_bit(x,y);
788 break;
790 case EAST:
791 case WEST:
792 draw_horizontal_bit(x,y);
793 break;
795 default:
796 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER,CENTER_Y+y*MULTIPLIER,MODIFIER_1,MODIFIER_1);
797 break;
804 ** Draws the snake bit described by nCurrentBit at position x/y
805 ** deciding whether it's a corner bit by examing the nPrevious bit
807 void draw_snake_bit(int currentbit, int previousbit, int x, int y)
809 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
810 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER,CENTER_Y+y*MULTIPLIER,MODIFIER_1,MODIFIER_1);
811 rb->lcd_set_drawmode(DRMODE_SOLID);
813 switch(currentbit)
815 case(NORTH):
816 switch(previousbit)
818 case(SOUTH):
819 case(NORTH):
820 draw_vertical_bit(x,y);
821 break;
823 case(EAST):
824 draw_e_to_n_bit(x,y);
825 break;
827 case(WEST):
828 draw_w_to_n_bit(x,y);
829 break;
831 break;
833 case(EAST):
834 switch(previousbit)
836 case(WEST):
837 case(EAST):
838 draw_horizontal_bit(x,y);
839 break;
841 case(NORTH):
842 draw_n_to_e_bit(x,y);
843 break;
845 case(SOUTH):
846 draw_s_to_e_bit(x,y);
847 break;
849 break;
851 case(SOUTH):
852 switch(previousbit)
854 case(SOUTH):
855 case(NORTH):
856 draw_vertical_bit(x,y);
857 break;
859 case(EAST):
860 draw_e_to_s_bit(x,y);
861 break;
863 case(WEST):
864 draw_w_to_s_bit(x,y);
865 break;
867 break;
869 case(WEST):
870 switch(previousbit)
872 case(EAST):
873 case(WEST):
874 draw_horizontal_bit(x,y);
875 break;
877 case(SOUTH):
878 draw_s_to_w_bit(x,y);
879 break;
881 case(NORTH):
882 draw_n_to_w_bit(x,y);
883 break;
885 break;
890 ** Death 'sequence' and end game stuff.
892 void die (void)
894 int button;
895 bool done=false;
896 char pscore[20];
898 rb->splash(HZ*2, "Oops!");
900 rb->lcd_clear_display();
902 applecount=0;
904 rb->lcd_getstringsize("You died!",&strwdt,&strhgt);
905 rb->lcd_putsxy((LCD_WIDTH - strwdt)/2,strhgt,"You died!");
907 rb->snprintf(pscore,sizeof(pscore),"Your score: %d",score);
908 rb->lcd_getstringsize(pscore,&strwdt,&strhgt);
909 rb->lcd_putsxy((LCD_WIDTH - strwdt)/2,strhgt * 2 + 2,pscore);
911 if (score>hiscore)
913 hiscore=score;
914 rb->lcd_getstringsize("New high score!",&strwdt,&strhgt);
915 rb->lcd_putsxy((LCD_WIDTH - strwdt)/2,strhgt * 4 + 2,"New high score!");
917 else
919 rb->snprintf(phscore,sizeof(phscore),"High score: %d",hiscore);
920 rb->lcd_getstringsize(phscore,&strwdt,&strhgt);
921 rb->lcd_putsxy((LCD_WIDTH - strwdt)/2,strhgt * 5,phscore);
924 rb->snprintf(phscore,sizeof(phscore),"Press %s...",SNAKE2_PLAYPAUSE_TEXT);
925 rb->lcd_getstringsize(phscore,&strwdt,&strhgt);
926 rb->lcd_putsxy((LCD_WIDTH - strwdt)/2,strhgt * 7,phscore);
928 rb->lcd_update();
930 while(!done)
932 button=rb->button_get(true);
933 switch(button)
935 case SNAKE2_PLAYPAUSE:
936 done = true;
937 break;
941 dead=1;
945 ** Check for collision. TODO: Currently this
946 ** sets of the death sequence. What we want is it to only return a true/false
947 ** depending on whether a collision occured.
949 void collision ( int x, int y )
951 int bdeath=0;
954 switch (board[x][y])
956 case 0:
958 break;
959 case -1:
960 score = score + (1 * level);
961 apple=0;
962 applecountdown=2;
963 applecount++;
965 if(game_type==1)
967 if(num_apples_to_get == num_apples_to_got)
969 level_from_file++;
970 if(level_from_file >= num_levels)
972 level_from_file = 1;
973 /*and increase the number of apples to pick up
974 before level changes*/
975 num_apples_to_get+=2;
976 game_b_level++;
978 rb->splash(HZ, "Level Completed!");
979 rb->lcd_clear_display();
980 new_level(level_from_file);
981 rb->lcd_clear_display();
982 redraw();
983 rb->lcd_update();
985 else
986 num_apples_to_got++;
988 break;
989 default:
990 bdeath=1;
991 break;
994 if(bdeath==1)
996 die();
997 sillydir = dir;
998 frames = -110;
1002 void move( void )
1004 int taildir;
1005 /*this actually sets the dir variable.*/
1006 get_direction();
1007 /*draw head*/
1008 switch (dir)
1010 case (NORTH):
1011 board[headx][heady]=NORTH;
1012 heady--;
1013 break;
1014 case (EAST):
1015 board[headx][heady]=EAST;
1016 headx++;
1017 break;
1018 case (SOUTH):
1019 board[headx][heady]=SOUTH;
1020 heady++;
1021 break;
1022 case (WEST):
1023 board[headx][heady]=WEST;
1024 headx--;
1025 break;
1028 if(headx == WIDTH)
1029 headx = 0;
1030 else if(headx < 0)
1031 headx = WIDTH-1;
1033 if(heady == HEIGHT)
1034 heady = 0;
1035 else if(heady < 0)
1036 heady = HEIGHT-1;
1038 rb->lcd_fillrect(CENTER_X+headx*MULTIPLIER,CENTER_Y+heady*MULTIPLIER,MODIFIER_1,MODIFIER_1);
1040 /*clear tail*/
1041 if(applecountdown <= 0)
1043 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
1044 rb->lcd_fillrect(CENTER_X+tailx*MULTIPLIER,CENTER_Y+taily*MULTIPLIER,MODIFIER_1,MODIFIER_1);
1045 rb->lcd_set_drawmode(DRMODE_SOLID);
1047 taildir = board[tailx][taily];
1048 board[tailx][taily] = 0;
1050 switch (taildir)
1052 case(NORTH):
1053 taily--;
1054 break;
1056 case(EAST):
1057 tailx++;
1058 break;
1060 case(SOUTH):
1061 taily++;
1062 break;
1064 case(WEST):
1065 tailx--;
1066 break;
1069 if(tailx == WIDTH)
1070 tailx = 0;
1071 else if(tailx < 0)
1072 tailx = WIDTH-1;
1074 if(taily == HEIGHT)
1075 taily = 0;
1076 else if(taily < 0)
1077 taily = HEIGHT-1;
1079 else
1080 applecountdown--;
1083 void frame (void)
1085 int olddir, noldx, noldy, temp;
1086 noldx = headx;
1087 noldy = heady;
1088 olddir = 0;
1089 switch(dir)
1091 case(NORTH):
1092 if(heady == HEIGHT-1)
1093 temp = 0;
1094 else
1095 temp = heady + 1;
1097 olddir = board[headx][temp];
1098 break;
1100 case(EAST):
1101 if(headx == 0)
1102 temp = WIDTH-1;
1103 else
1104 temp = headx - 1;
1106 olddir = board[temp][heady];
1107 break;
1109 case(SOUTH):
1110 if(heady == 0)
1111 temp = HEIGHT-1;
1112 else
1113 temp = heady - 1;
1115 olddir = board[headx][temp];
1116 break;
1118 case(WEST):
1119 if(headx == WIDTH-1)
1120 temp = 0;
1121 else
1122 temp = headx + 1;
1124 olddir = board[temp][heady];
1125 break;
1128 move();
1131 now redraw the bit that was
1132 the tail, to something snake-like:
1134 draw_snake_bit(dir, olddir, noldx, noldy);
1136 collision(headx, heady);
1138 rb->lcd_update();
1141 void game_pause (void)
1143 int button;
1145 rb->lcd_clear_display();
1146 rb->lcd_getstringsize("Paused",&strwdt,&strhgt);
1147 rb->lcd_putsxy((LCD_WIDTH - strwdt)/2,LCD_HEIGHT/2,"Paused");
1149 rb->lcd_update();
1150 while (1)
1152 button = rb->button_get(true);
1153 switch (button)
1155 case SNAKE2_PLAYPAUSE:
1156 rb->lcd_clear_display();
1157 redraw();
1158 rb->lcd_update();
1159 rb->sleep(HZ/2);
1160 return;
1162 #ifdef SNAKE2_RC_QUIT
1163 case SNAKE2_RC_QUIT:
1164 #endif
1165 case SNAKE2_QUIT:
1166 dead = 1;
1167 quit = 1;
1168 return;
1170 default:
1171 if (rb->default_event_handler(button)==SYS_USB_CONNECTED) {
1172 dead = 1;
1173 quit = 2;
1174 return;
1176 break;
1181 void game (void)
1183 int button;
1185 rb->lcd_clear_display();
1186 redraw();
1187 rb->lcd_update();
1188 /*main loop:*/
1189 while (1)
1191 if(frames==5)
1193 frame();
1194 if(frames>0) frames=0;
1196 frames++;
1198 if(frames == 0)
1200 die();
1202 else
1204 if(frames < 0)
1206 if(sillydir != dir)
1208 /*it has, great set frames to a positive value again:*/
1209 frames = 1;
1214 if (dead) return;
1216 draw_apple();
1218 rb->sleep(HZ/speed);
1220 button = rb->button_get(false);
1222 #ifdef HAS_BUTTON_HOLD
1223 if (rb->button_hold())
1224 button = SNAKE2_PLAYPAUSE;
1225 #endif
1227 switch (button)
1229 case SNAKE2_UP:
1230 case SNAKE2_UP | BUTTON_REPEAT:
1231 if (dir != SOUTH) set_direction(NORTH);
1232 break;
1234 case SNAKE2_RIGHT:
1235 case SNAKE2_RIGHT | BUTTON_REPEAT:
1236 if (dir != WEST) set_direction(EAST);
1237 break;
1239 case SNAKE2_DOWN:
1240 case SNAKE2_DOWN | BUTTON_REPEAT:
1241 if (dir != NORTH) set_direction(SOUTH);
1242 break;
1244 case SNAKE2_LEFT:
1245 case SNAKE2_LEFT | BUTTON_REPEAT:
1246 if (dir != EAST) set_direction(WEST);
1247 break;
1249 #ifdef SNAKE2_RC_QUIT
1250 case SNAKE2_RC_QUIT:
1251 #endif
1252 case SNAKE2_QUIT:
1253 dead=1;
1254 return;
1256 case SNAKE2_PLAYPAUSE:
1257 game_pause();
1258 break;
1260 default:
1261 if (rb->default_event_handler(button)==SYS_USB_CONNECTED) {
1262 quit = 2;
1263 return;
1265 break;
1271 void game_init(void)
1273 int button;
1274 char plevel[30];
1276 dead=0;
1277 apple=0;
1278 score=0;
1279 applecount=0;
1281 clear_board();
1282 load_level( level_from_file );
1283 rb->lcd_clear_display();
1284 redraw();
1285 rb->lcd_update();
1287 while (1)
1289 #if LCD_WIDTH >= 160 && LCD_HEIGHT >= 128
1291 rb->lcd_bitmap(snake2_header1,0,0,BMPWIDTH_snake2_header, BMPHEIGHT_snake2_header);
1292 rb->lcd_bitmap(snake2_left,0,BMPHEIGHT_snake2_header,BMPWIDTH_snake2_left, BMPHEIGHT_snake2_left);
1293 rb->lcd_bitmap(snake2_right,LCD_WIDTH-BMPWIDTH_snake2_right,BMPHEIGHT_snake2_header,BMPWIDTH_snake2_right, BMPHEIGHT_snake2_right);
1294 rb->lcd_bitmap(snake2_bottom,0,BMPHEIGHT_snake2_header+BMPHEIGHT_snake2_left,BMPWIDTH_snake2_bottom, BMPHEIGHT_snake2_bottom);
1296 rb->snprintf(plevel,sizeof(plevel),"%d",level);
1297 rb->lcd_getstringsize(plevel,&strwdt,&strhgt);
1298 rb->lcd_putsxy(TOP_X3-strwdt/2,TOP_Y2, plevel);
1300 rb->snprintf(plevel,sizeof(plevel),"%d",level_from_file);
1301 rb->lcd_getstringsize(plevel,&strwdt,&strhgt);
1302 rb->lcd_putsxy(TOP_X2-strwdt/2,TOP_Y1, plevel);
1304 if(game_type==0){
1305 rb->lcd_getstringsize("A",&strwdt,&strhgt);
1306 rb->lcd_putsxy(TOP_X1,TOP_Y1,"A");
1308 else{
1309 rb->lcd_getstringsize("B",&strwdt,&strhgt);
1310 rb->lcd_putsxy(TOP_X1,TOP_Y1,"B");
1313 rb->snprintf(phscore,sizeof(phscore),"%d",hiscore);
1314 rb->lcd_getstringsize(phscore,&strwdt,&strhgt);
1315 rb->lcd_putsxy(TOP_X4-strwdt/2,TOP_Y2, phscore);
1317 #else
1318 rb->snprintf(plevel,sizeof(plevel),"Speed: %02d",level);
1319 rb->lcd_getstringsize("Speed: 00",&strwdt,&strhgt);
1320 rb->lcd_putsxy((LCD_WIDTH - strwdt)/2,strhgt+4, plevel);
1322 rb->snprintf(plevel,sizeof(plevel),"Maze: %d",level_from_file);
1323 rb->lcd_getstringsize(plevel,&strwdt,&strhgt);
1324 rb->lcd_putsxy((LCD_WIDTH - strwdt)/2,strhgt*2+4, plevel);
1326 if(game_type==0){
1327 rb->lcd_getstringsize("Game Type: A ",&strwdt,&strhgt);
1328 rb->lcd_putsxy((LCD_WIDTH - strwdt)/2,strhgt*3+4,"Game Type: A");
1330 else{
1331 rb->lcd_getstringsize("Game Type: B ",&strwdt,&strhgt);
1332 rb->lcd_putsxy((LCD_WIDTH - strwdt)/2,strhgt*3+4,"Game Type: B");
1335 rb->snprintf(phscore,sizeof(phscore),"Hi Score: %d",hiscore);
1336 rb->lcd_getstringsize(phscore,&strwdt,&strhgt);
1337 rb->lcd_putsxy((LCD_WIDTH - strwdt)/2,strhgt*4+4, phscore);
1338 #endif
1340 rb->lcd_update();
1342 button=rb->button_get(true);
1343 switch (button)
1345 case SNAKE2_LEVEL_UP:
1346 case SNAKE2_LEVEL_UP|BUTTON_REPEAT:
1347 if (level<10)
1348 level+=1;
1349 break;
1350 case SNAKE2_LEVEL_DOWN:
1351 case SNAKE2_LEVEL_DOWN|BUTTON_REPEAT:
1352 if (level>1)
1353 level-=1;
1354 break;
1355 case SNAKE2_QUIT:
1356 quit=1;
1357 return;
1358 break;
1359 case SNAKE2_PLAYPAUSE:
1360 speed = level*20;
1361 return;
1362 break;
1363 case SNAKE2_SELECT_TYPE:
1364 if(game_type==0)game_type=1; else game_type=0;
1365 break;
1366 case SNAKE2_MAZE_NEXT:
1367 rb->lcd_set_drawmode(DRMODE_BG|DRMODE_INVERSEVID);
1368 rb->lcd_fillrect(CENTER_X, CENTER_Y, CENTER_X+WIDTH*MULTIPLIER,
1369 CENTER_Y+HEIGHT*MULTIPLIER);
1370 rb->lcd_set_drawmode(DRMODE_SOLID);
1371 if(level_from_file < num_levels)
1372 level_from_file++;
1373 else
1374 level_from_file = 0;
1375 load_level( level_from_file );
1376 redraw();
1377 break;
1378 #ifdef SNAKE2_MAZE_LAST
1379 case SNAKE2_MAZE_LAST:
1380 rb->lcd_set_drawmode(DRMODE_BG|DRMODE_INVERSEVID);
1381 rb->lcd_fillrect(CENTER_X, CENTER_Y, CENTER_X+WIDTH*MULTIPLIER,
1382 CENTER_Y+HEIGHT*MULTIPLIER);
1383 rb->lcd_set_drawmode(DRMODE_SOLID);
1384 if(level_from_file > 0)
1385 level_from_file--;
1386 else
1387 level_from_file = num_levels;
1388 load_level( level_from_file );
1389 redraw();
1390 break;
1391 #endif
1392 default:
1393 if (rb->default_event_handler(button)==SYS_USB_CONNECTED) {
1394 quit = 2;
1395 return;
1397 break;
1403 enum plugin_status plugin_start(const struct plugin_api* api, const void* parameter)
1405 (void)(parameter);
1406 rb = api;
1408 /* Lets use the default font */
1409 rb->lcd_setfont(FONT_SYSFIXED);
1410 #if LCD_DEPTH > 1
1411 rb->lcd_set_backdrop(NULL);
1412 #endif
1413 #ifdef HAVE_LCD_COLOR
1414 rb->lcd_set_foreground(LCD_BLACK);
1415 rb->lcd_set_background(LCD_WHITE);
1416 #endif
1418 load_all_levels();
1420 if (num_levels == 0) {
1421 rb->splash(HZ*2, "Failed loading levels!");
1422 return PLUGIN_OK;
1425 iohiscore();
1427 while(quit==0)
1429 game_init();
1430 rb->lcd_clear_display();
1431 frames=1;
1433 if(quit==0)
1435 init_snake();
1437 /*Start Game:*/
1438 game();
1442 iohiscore();
1443 return (quit==1) ? PLUGIN_OK : PLUGIN_USB_CONNECTED;
1446 #endif