Update the Swedish translation.
[kugel-rb.git] / apps / plugins / snake2.c
blob2a2665cab36cb858efa9fa66ce64e0d66b0a56a3
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 #define SNAKE2_UP BUTTON_MENU
200 #define SNAKE2_DOWN BUTTON_PLAY
201 #define SNAKE2_QUIT (BUTTON_SELECT | BUTTON_MENU)
202 #define SNAKE2_LEVEL_UP BUTTON_SCROLL_FWD
203 #define SNAKE2_LEVEL_DOWN BUTTON_SCROLL_BACK
204 #define SNAKE2_MAZE_NEXT BUTTON_RIGHT
205 #define SNAKE2_MAZE_LAST BUTTON_LEFT
206 #define SNAKE2_SELECT_TYPE BUTTON_PLAY
207 #define SNAKE2_PLAYPAUSE BUTTON_SELECT
208 #define SNAKE2_PLAYPAUSE_TEXT "Select"
210 #elif (CONFIG_KEYPAD == IAUDIO_X5M5_PAD)
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_PLAY
219 #define SNAKE2_PLAYPAUSE BUTTON_SELECT
220 #define SNAKE2_PLAYPAUSE_TEXT "Select"
222 #elif (CONFIG_KEYPAD == GIGABEAT_PAD)
223 #define SNAKE2_UP BUTTON_UP
224 #define SNAKE2_DOWN BUTTON_DOWN
225 #define SNAKE2_QUIT BUTTON_POWER
226 #define SNAKE2_LEVEL_UP BUTTON_UP
227 #define SNAKE2_LEVEL_DOWN BUTTON_DOWN
228 #define SNAKE2_MAZE_NEXT BUTTON_RIGHT
229 #define SNAKE2_MAZE_LAST BUTTON_LEFT
230 #define SNAKE2_SELECT_TYPE BUTTON_MENU
231 #define SNAKE2_PLAYPAUSE BUTTON_SELECT
232 #define SNAKE2_PLAYPAUSE_TEXT "Select"
234 #elif (CONFIG_KEYPAD == SANSA_E200_PAD)
235 #define SNAKE2_UP BUTTON_UP
236 #define SNAKE2_DOWN BUTTON_DOWN
237 #define SNAKE2_QUIT BUTTON_POWER
238 #define SNAKE2_LEVEL_UP BUTTON_UP
239 #define SNAKE2_LEVEL_DOWN BUTTON_DOWN
240 #define SNAKE2_MAZE_NEXT BUTTON_RIGHT
241 #define SNAKE2_MAZE_LAST BUTTON_LEFT
242 #define SNAKE2_SELECT_TYPE BUTTON_REC
243 #define SNAKE2_PLAYPAUSE BUTTON_SELECT
244 #define SNAKE2_PLAYPAUSE_TEXT "Select"
246 #elif (CONFIG_KEYPAD == IRIVER_H10_PAD)
247 #define SNAKE2_UP BUTTON_SCROLL_UP
248 #define SNAKE2_DOWN BUTTON_SCROLL_DOWN
249 #define SNAKE2_QUIT BUTTON_POWER
250 #define SNAKE2_LEVEL_UP BUTTON_SCROLL_UP
251 #define SNAKE2_LEVEL_DOWN BUTTON_SCROLL_DOWN
252 #define SNAKE2_MAZE_NEXT BUTTON_RIGHT
253 #define SNAKE2_MAZE_LAST BUTTON_LEFT
254 #define SNAKE2_SELECT_TYPE BUTTON_PLAY
255 #define SNAKE2_PLAYPAUSE BUTTON_FF
256 #define SNAKE2_PLAYPAUSE_TEXT "FF"
258 #else
259 #error "lacks keymapping"
260 #endif
262 static int max_levels = 0;
263 static char (*level_cache)[HEIGHT][WIDTH];
265 /*Board itself - 2D int array*/
266 static int board[WIDTH][HEIGHT];
268 Buffer for sorting movement (in case user presses two movements during a
269 single frame
271 static int ardirectionbuffer[2];
272 static unsigned int score, hiscore = 0;
273 static int applex;
274 static int appley;
275 static int strwdt,strhgt; /*used for string width, height for orientation purposes*/
276 static int dir;
277 static int frames;
278 static int apple;
279 static int level = 4, speed = 5,dead = 0, quit = 0;
280 static int sillydir = 0, num_levels = 0;
281 static int level_from_file = 0;
282 static struct plugin_api* rb;
283 static int headx, heady, tailx, taily, applecountdown = 5;
284 static int game_type = 0;
285 static int num_apples_to_get=1;
286 static int num_apples_to_got=0;
287 static int game_b_level=0;
288 static int applecount=0;
289 static char phscore[30];
291 #if (LCD_WIDTH >= 160) && (LCD_HEIGHT >= 128)
292 #ifdef HAVE_LCD_COLOR
293 extern const unsigned short snake2_header1[];
294 extern const unsigned short snake2_header2[];
295 extern const unsigned short snake2_left[];
296 extern const unsigned short snake2_right[];
297 extern const unsigned short snake2_bottom[];
298 #else
299 extern const unsigned char snake2_header1[];
300 extern const unsigned char snake2_header2[];
301 extern const unsigned char snake2_left[];
302 extern const unsigned char snake2_right[];
303 extern const unsigned char snake2_bottom[];
304 #endif
305 #endif
307 #define NORTH 1
308 #define EAST 2
309 #define SOUTH 4
310 #define WEST 8
311 #define HEAD 16
313 #define EAST_NORTH 32
314 #define EAST_SOUTH 64
315 #define WEST_NORTH 128
316 #define WEST_SOUTH 256
318 #define NORTH_EAST 512
319 #define NORTH_WEST 1024
320 #define SOUTH_EAST 2048
321 #define SOUTH_WEST 4096
323 #define LEVELS_FILE PLUGIN_DIR "/snake2.levels"
324 #define HISCORE_FILE PLUGIN_DIR "/snake2.hs"
326 int load_all_levels(void)
328 int linecnt = 0;
329 int fd;
330 ssize_t size;
331 char buf[64]; /* Larger than WIDTH, to allow for whitespace after the
332 lines */
334 /* Init the level_cache pointer and
335 calculate how many levels that will fit */
336 level_cache = rb->plugin_get_buffer((size_t *)&size);
337 max_levels = size / (HEIGHT*WIDTH);
339 num_levels = 0;
341 /* open file */
342 if ((fd = rb->open(LEVELS_FILE, O_RDONLY)) < 0)
344 return -1;
347 while(rb->read_line(fd, buf, 64))
349 if(rb->strlen(buf) == 0) /* Separator? */
351 num_levels++;
352 if(num_levels > max_levels)
354 rb->splash(HZ, "Too many levels in file");
355 break;
357 continue;
360 rb->memcpy(level_cache[num_levels][linecnt], buf, WIDTH);
361 linecnt++;
362 if(linecnt == HEIGHT)
364 linecnt = 0;
368 rb->close(fd);
369 return 0;
372 /*Hi-Score reading and writing to file "/.rockbox/snake2.levels" function */
373 void iohiscore(void)
375 int fd;
376 unsigned int compare;
378 /* clear the buffer we're about to load the highscore data into */
379 rb->memset(phscore, 0, sizeof(phscore));
381 fd = rb->open(HISCORE_FILE,O_RDWR | O_CREAT);
383 /* highscore used to %d, is now %d\n
384 Deal with no file or bad file */
385 rb->read(fd,phscore, sizeof(phscore));
387 compare = rb->atoi(phscore);
389 if(hiscore > compare){
390 rb->lseek(fd,0,SEEK_SET);
391 rb->fdprintf(fd, "%d\n", hiscore);
393 else
394 hiscore = compare;
396 rb->close(fd);
401 ** Completely clear the board of walls and/or snake */
403 void clear_board( void)
405 int x,y;
407 for (x = 0; x < WIDTH; x++)
409 for (y = 0; y < HEIGHT; y++)
411 board[x][y] = 0;
416 int load_level( int level_number )
418 int x,y;
419 clear_board();
420 for(y = 0;y < HEIGHT;y++)
422 for(x = 0;x < WIDTH;x++)
424 switch(level_cache[level_number][y][x])
426 case '|':
427 board[x][y] = NORTH;
428 break;
430 case '-':
431 board[x][y] = EAST;
432 break;
434 case '+':
435 board[x][y] = HEAD;
436 break;
440 return 1;
444 ** Gets the currently chosen direction from the first place
445 ** in the direction buffer. If there is something in the
446 ** next part of the buffer then that is moved to the first place
448 void get_direction( void )
450 /*if 1st place is empty*/
451 if(ardirectionbuffer[0] != -1)
453 /*return this direction*/
454 dir = ardirectionbuffer[0];
455 ardirectionbuffer[0]=-1;
456 /*now see if one needs moving:*/
457 if(ardirectionbuffer[1] != -1)
459 /*there's a move waiting to be done
460 so move it into the space:*/
461 ardirectionbuffer[0] = ardirectionbuffer[1];
462 ardirectionbuffer[1] = -1;
468 ** Sets the direction
470 void set_direction(int newdir)
472 if(ardirectionbuffer[0] != newdir)
474 /*if 1st place is empty*/
475 if(ardirectionbuffer[0] == -1)
477 /*use 1st space:*/
478 ardirectionbuffer[0] = newdir;
480 else
482 /*use 2nd space:*/
483 if(ardirectionbuffer[0] != newdir) ardirectionbuffer[1] = newdir;
486 if(frames < 0) ardirectionbuffer[0] = newdir;
490 void new_level(int level)
492 load_level(level);
494 ardirectionbuffer[0] = -1;
495 ardirectionbuffer[1] = -1;
496 dir = EAST;
497 headx = WIDTH/2;
498 heady = HEIGHT/2;
499 tailx = headx - 4;
500 taily = heady;
501 applecountdown = 0;
502 /*Create a small snake to start off with*/
503 board[headx][heady] = dir;
504 board[headx-1][heady] = dir;
505 board[headx-2][heady] = dir;
506 board[headx-3][heady] = dir;
507 board[headx-4][heady] = dir;
508 num_apples_to_got=0;
511 void init_snake(void)
513 num_apples_to_get=1;
514 if(game_type == 1)
515 level_from_file = 1;
516 game_b_level=1;
517 new_level(level_from_file);
521 ** Draws the apple. If it doesn't exist then
522 ** a new one get's created.
524 void draw_apple( void )
526 int x,y;
528 #if LCD_WIDTH >= 160 && LCD_HEIGHT >= 128
529 char pscore[5], counter[4];
531 rb->lcd_bitmap(snake2_header2,0,0,BMPWIDTH_snake2_header, BMPHEIGHT_snake2_header);
532 rb->lcd_bitmap(snake2_left,0,BMPHEIGHT_snake2_header,BMPWIDTH_snake2_left, BMPHEIGHT_snake2_left);
533 rb->lcd_bitmap(snake2_right,LCD_WIDTH-BMPWIDTH_snake2_right,BMPHEIGHT_snake2_header,BMPWIDTH_snake2_right, BMPHEIGHT_snake2_right);
534 rb->lcd_bitmap(snake2_bottom,0,BMPHEIGHT_snake2_header+BMPHEIGHT_snake2_left,BMPWIDTH_snake2_bottom, BMPHEIGHT_snake2_bottom);
536 rb->snprintf(counter,sizeof(counter),"%d",applecount);
537 rb->lcd_getstringsize(counter,&strwdt,&strhgt);
538 rb->lcd_putsxy(TOP_X3-strwdt/2,TOP_Y2,counter);
540 rb->snprintf(pscore,sizeof(pscore),"%d",score);
541 rb->lcd_getstringsize(pscore,&strwdt,&strhgt);
542 rb->lcd_putsxy(TOP_X4-strwdt/2,TOP_Y2,pscore);
543 #endif
545 if (!apple)
549 x = (rb->rand() % (WIDTH-1))+1;
550 y = (rb->rand() % (HEIGHT-1))+1;
551 } while (board[x][y]);
552 apple=1;
553 board[x][y]=-1;
554 applex = x;appley = y;
556 rb->lcd_fillrect((CENTER_X+applex*MULTIPLIER)+1,CENTER_Y+appley*MULTIPLIER,MODIFIER_2,MODIFIER_1);
557 rb->lcd_fillrect(CENTER_X+applex*MULTIPLIER,(CENTER_Y+appley*MULTIPLIER)+1,MODIFIER_1,MODIFIER_2);
561 * x x *
562 * x x *
563 * x x *
564 * x x *
566 void draw_vertical_bit(int x, int y)
568 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER+1,CENTER_Y+y*MULTIPLIER,MODIFIER_2,MODIFIER_1);
572 * * * *
573 X X X X
574 X X X X
575 * * * *
577 void draw_horizontal_bit(int x, int y)
579 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER,CENTER_Y+y*MULTIPLIER+1,MODIFIER_1,MODIFIER_2);
583 * * * *
584 * * X X
585 * X X X
586 * X X *
588 void draw_n_to_e_bit(int x, int y)
590 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER+1,CENTER_Y+y*MULTIPLIER+2,MODIFIER_2,MODIFIER_2);
591 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER+2,CENTER_Y+y*MULTIPLIER+1,MODIFIER_2,MODIFIER_2);
595 * * * *
596 * * X X
597 * X X X
598 * X X *
600 void draw_w_to_s_bit(int x, int y)
602 draw_n_to_e_bit(x,y);
606 * * * *
607 X X * *
608 X X X *
609 * X X *
611 void draw_n_to_w_bit(int x, int y)
613 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER,CENTER_Y+y*MULTIPLIER+1,MODIFIER_2,MODIFIER_2);
614 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER+1,CENTER_Y+y*MULTIPLIER+2,MODIFIER_2,MODIFIER_2);
618 * * * *
619 X X * *
620 X X X *
621 * X X *
623 void draw_e_to_s_bit(int x, int y)
625 draw_n_to_w_bit(x, y);
629 * X X *
630 * X X X
631 * * X X
632 * * * *
634 void draw_s_to_e_bit(int x, int y)
636 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER+1,CENTER_Y+y*MULTIPLIER,MODIFIER_2,MODIFIER_2);
637 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER+2,CENTER_Y+y*MULTIPLIER+1,MODIFIER_2,MODIFIER_2);
641 * X X *
642 * X X X
643 * * X X
644 * * * *
646 void draw_w_to_n_bit(int x, int y)
648 draw_s_to_e_bit(x,y);
652 * X X *
653 X X X *
654 X X * *
655 * * * *
657 void draw_e_to_n_bit(int x, int y)
659 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER+1,CENTER_Y+y*MULTIPLIER,MODIFIER_2,MODIFIER_2);
660 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER,CENTER_Y+y*MULTIPLIER+1,MODIFIER_2,MODIFIER_2);
664 * X X *
665 X X X *
666 X X * *
667 * * * *
669 void draw_s_to_w_bit(int x, int y)
671 draw_e_to_n_bit(x, y);
675 ** Draws a wall/obsticals
677 void draw_boundary ( void )
679 int x, y;
681 /*TODO: Load levels from file!*/
683 /*top and bottom line*/
684 for(x=0; x < WIDTH; x++)
686 board[x][0] = EAST;
687 board[x][HEIGHT-1] = WEST;
690 /*left and right lines*/
691 for(y=0; y < HEIGHT; y++)
693 board[0][y] = NORTH;
694 board[WIDTH-1][y] = SOUTH;
697 /*corners:*/
698 board[0][0] = NORTH_EAST;
699 board[WIDTH-1][0] = EAST_SOUTH;
700 board[0][HEIGHT-1] = SOUTH_EAST;
701 board[WIDTH-1][HEIGHT-1] = EAST_NORTH;
705 ** Redraw the entire board
707 void redraw (void)
709 int x,y;
711 for (x = 0; x < WIDTH; x++)
713 for (y = 0; y < HEIGHT; y++)
715 switch (board[x][y])
717 case -1:
718 rb->lcd_fillrect((CENTER_X+x*MULTIPLIER)+1,CENTER_Y+y*MULTIPLIER,MODIFIER_2,MODIFIER_1);
719 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER,(CENTER_Y+y*MULTIPLIER)+1,MODIFIER_1,MODIFIER_2);
720 break;
721 case 0:
722 break;
724 case NORTH:
725 case SOUTH:
726 draw_vertical_bit(x,y);
727 break;
729 case EAST:
730 case WEST:
731 draw_horizontal_bit(x,y);
732 break;
734 default:
735 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER,CENTER_Y+y*MULTIPLIER,MODIFIER_1,MODIFIER_1);
736 break;
743 ** Draws the snake bit described by nCurrentBit at position x/y
744 ** deciding whether it's a corner bit by examing the nPrevious bit
746 void draw_snake_bit(int currentbit, int previousbit, int x, int y)
748 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
749 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER,CENTER_Y+y*MULTIPLIER,MODIFIER_1,MODIFIER_1);
750 rb->lcd_set_drawmode(DRMODE_SOLID);
752 switch(currentbit)
754 case(NORTH):
755 switch(previousbit)
757 case(SOUTH):
758 case(NORTH):
759 draw_vertical_bit(x,y);
760 break;
762 case(EAST):
763 draw_e_to_n_bit(x,y);
764 break;
766 case(WEST):
767 draw_w_to_n_bit(x,y);
768 break;
770 break;
772 case(EAST):
773 switch(previousbit)
775 case(WEST):
776 case(EAST):
777 draw_horizontal_bit(x,y);
778 break;
780 case(NORTH):
781 draw_n_to_e_bit(x,y);
782 break;
784 case(SOUTH):
785 draw_s_to_e_bit(x,y);
786 break;
788 break;
790 case(SOUTH):
791 switch(previousbit)
793 case(SOUTH):
794 case(NORTH):
795 draw_vertical_bit(x,y);
796 break;
798 case(EAST):
799 draw_e_to_s_bit(x,y);
800 break;
802 case(WEST):
803 draw_w_to_s_bit(x,y);
804 break;
806 break;
808 case(WEST):
809 switch(previousbit)
811 case(EAST):
812 case(WEST):
813 draw_horizontal_bit(x,y);
814 break;
816 case(SOUTH):
817 draw_s_to_w_bit(x,y);
818 break;
820 case(NORTH):
821 draw_n_to_w_bit(x,y);
822 break;
824 break;
829 ** Death 'sequence' and end game stuff.
831 void die (void)
833 int button;
834 bool done=false;
835 char pscore[20];
837 rb->splash(HZ*2, "Oops!");
839 rb->lcd_clear_display();
841 applecount=0;
843 rb->lcd_getstringsize("You died!",&strwdt,&strhgt);
844 rb->lcd_putsxy((LCD_WIDTH - strwdt)/2,strhgt,"You died!");
846 rb->snprintf(pscore,sizeof(pscore),"Your score: %d",score);
847 rb->lcd_getstringsize(pscore,&strwdt,&strhgt);
848 rb->lcd_putsxy((LCD_WIDTH - strwdt)/2,strhgt * 2 + 2,pscore);
850 if (score>hiscore)
852 hiscore=score;
853 rb->lcd_getstringsize("New high score!",&strwdt,&strhgt);
854 rb->lcd_putsxy((LCD_WIDTH - strwdt)/2,strhgt * 4 + 2,"New high score!");
856 else
858 rb->snprintf(phscore,sizeof(phscore),"High score: %d",hiscore);
859 rb->lcd_getstringsize(phscore,&strwdt,&strhgt);
860 rb->lcd_putsxy((LCD_WIDTH - strwdt)/2,strhgt * 5,phscore);
863 rb->snprintf(phscore,sizeof(phscore),"Press %s...",SNAKE2_PLAYPAUSE_TEXT);
864 rb->lcd_getstringsize(phscore,&strwdt,&strhgt);
865 rb->lcd_putsxy((LCD_WIDTH - strwdt)/2,strhgt * 7,phscore);
867 rb->lcd_update();
869 while(!done)
871 button=rb->button_get(true);
872 switch(button)
874 case SNAKE2_PLAYPAUSE:
875 done = true;
876 break;
880 dead=1;
884 ** Check for collision. TODO: Currently this
885 ** sets of the death sequence. What we want is it to only return a true/false
886 ** depending on whether a collision occured.
888 void collision ( int x, int y )
890 int bdeath=0;
893 switch (board[x][y])
895 case 0:
897 break;
898 case -1:
899 score = score + (1 * level);
900 apple=0;
901 applecountdown=2;
902 applecount++;
904 if(game_type==1)
906 if(num_apples_to_get == num_apples_to_got)
908 level_from_file++;
909 if(level_from_file >= num_levels)
911 level_from_file = 1;
912 /*and increase the number of apples to pick up
913 before level changes*/
914 num_apples_to_get+=2;
915 game_b_level++;
917 rb->splash(HZ, "Level Completed!");
918 rb->lcd_clear_display();
919 new_level(level_from_file);
920 rb->lcd_clear_display();
921 redraw();
922 rb->lcd_update();
924 else
925 num_apples_to_got++;
927 break;
928 default:
929 bdeath=1;
930 break;
933 if(bdeath==1)
935 die();
936 sillydir = dir;
937 frames = -110;
941 void move( void )
943 int taildir;
944 /*this actually sets the dir variable.*/
945 get_direction();
946 /*draw head*/
947 switch (dir)
949 case (NORTH):
950 board[headx][heady]=NORTH;
951 heady--;
952 break;
953 case (EAST):
954 board[headx][heady]=EAST;
955 headx++;
956 break;
957 case (SOUTH):
958 board[headx][heady]=SOUTH;
959 heady++;
960 break;
961 case (WEST):
962 board[headx][heady]=WEST;
963 headx--;
964 break;
967 if(headx == WIDTH)
968 headx = 0;
969 else if(headx < 0)
970 headx = WIDTH-1;
972 if(heady == HEIGHT)
973 heady = 0;
974 else if(heady < 0)
975 heady = HEIGHT-1;
977 rb->lcd_fillrect(CENTER_X+headx*MULTIPLIER,CENTER_Y+heady*MULTIPLIER,MODIFIER_1,MODIFIER_1);
979 /*clear tail*/
980 if(applecountdown <= 0)
982 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
983 rb->lcd_fillrect(CENTER_X+tailx*MULTIPLIER,CENTER_Y+taily*MULTIPLIER,MODIFIER_1,MODIFIER_1);
984 rb->lcd_set_drawmode(DRMODE_SOLID);
986 taildir = board[tailx][taily];
987 board[tailx][taily] = 0;
989 switch (taildir)
991 case(NORTH):
992 taily--;
993 break;
995 case(EAST):
996 tailx++;
997 break;
999 case(SOUTH):
1000 taily++;
1001 break;
1003 case(WEST):
1004 tailx--;
1005 break;
1008 if(tailx == WIDTH)
1009 tailx = 0;
1010 else if(tailx < 0)
1011 tailx = WIDTH-1;
1013 if(taily == HEIGHT)
1014 taily = 0;
1015 else if(taily < 0)
1016 taily = HEIGHT-1;
1018 else
1019 applecountdown--;
1022 void frame (void)
1024 int olddir, noldx, noldy, temp;
1025 noldx = headx;
1026 noldy = heady;
1027 olddir = 0;
1028 switch(dir)
1030 case(NORTH):
1031 if(heady == HEIGHT-1)
1032 temp = 0;
1033 else
1034 temp = heady + 1;
1036 olddir = board[headx][temp];
1037 break;
1039 case(EAST):
1040 if(headx == 0)
1041 temp = WIDTH-1;
1042 else
1043 temp = headx - 1;
1045 olddir = board[temp][heady];
1046 break;
1048 case(SOUTH):
1049 if(heady == 0)
1050 temp = HEIGHT-1;
1051 else
1052 temp = heady - 1;
1054 olddir = board[headx][temp];
1055 break;
1057 case(WEST):
1058 if(headx == WIDTH-1)
1059 temp = 0;
1060 else
1061 temp = headx + 1;
1063 olddir = board[temp][heady];
1064 break;
1067 move();
1070 now redraw the bit that was
1071 the tail, to something snake-like:
1073 draw_snake_bit(dir, olddir, noldx, noldy);
1075 collision(headx, heady);
1077 rb->lcd_update();
1080 void game_pause (void)
1082 int button;
1084 rb->lcd_clear_display();
1085 rb->lcd_getstringsize("Paused",&strwdt,&strhgt);
1086 rb->lcd_putsxy((LCD_WIDTH - strwdt)/2,LCD_HEIGHT/2,"Paused");
1088 rb->lcd_update();
1089 while (1)
1091 button = rb->button_get(true);
1092 switch (button)
1094 case SNAKE2_PLAYPAUSE:
1095 rb->lcd_clear_display();
1096 redraw();
1097 rb->lcd_update();
1098 rb->sleep(HZ/2);
1099 return;
1101 #ifdef SNAKE2_RC_QUIT
1102 case SNAKE2_RC_QUIT:
1103 #endif
1104 case SNAKE2_QUIT:
1105 dead = 1;
1106 quit = 1;
1107 return;
1109 default:
1110 if (rb->default_event_handler(button)==SYS_USB_CONNECTED) {
1111 dead = 1;
1112 quit = 2;
1113 return;
1115 break;
1120 void game (void)
1122 int button;
1124 rb->lcd_clear_display();
1125 redraw();
1126 rb->lcd_update();
1127 /*main loop:*/
1128 while (1)
1130 if(frames==5)
1132 frame();
1133 if(frames>0) frames=0;
1135 frames++;
1137 if(frames == 0)
1139 die();
1141 else
1143 if(frames < 0)
1145 if(sillydir != dir)
1147 /*it has, great set frames to a positive value again:*/
1148 frames = 1;
1153 if (dead) return;
1155 draw_apple();
1157 rb->sleep(HZ/speed);
1159 button = rb->button_get(false);
1161 #ifdef HAS_BUTTON_HOLD
1162 if (rb->button_hold())
1163 button = SNAKE2_PLAYPAUSE;
1164 #endif
1166 switch (button)
1168 case SNAKE2_UP:
1169 case SNAKE2_UP | BUTTON_REPEAT:
1170 if (dir != SOUTH) set_direction(NORTH);
1171 break;
1173 case BUTTON_RIGHT:
1174 case BUTTON_RIGHT | BUTTON_REPEAT:
1175 if (dir != WEST) set_direction(EAST);
1176 break;
1178 case SNAKE2_DOWN:
1179 case SNAKE2_DOWN | BUTTON_REPEAT:
1180 if (dir != NORTH) set_direction(SOUTH);
1181 break;
1183 case BUTTON_LEFT:
1184 case BUTTON_LEFT | BUTTON_REPEAT:
1185 if (dir != EAST) set_direction(WEST);
1186 break;
1188 #ifdef SNAKE2_RC_QUIT
1189 case SNAKE2_RC_QUIT:
1190 #endif
1191 case SNAKE2_QUIT:
1192 dead=1;
1193 return;
1195 case SNAKE2_PLAYPAUSE:
1196 game_pause();
1197 break;
1199 default:
1200 if (rb->default_event_handler(button)==SYS_USB_CONNECTED) {
1201 quit = 2;
1202 return;
1204 break;
1210 void game_init(void)
1212 int button;
1213 char plevel[30];
1215 dead=0;
1216 apple=0;
1217 score=0;
1218 applecount=0;
1220 clear_board();
1221 load_level( level_from_file );
1222 rb->lcd_clear_display();
1223 redraw();
1224 rb->lcd_update();
1226 while (1)
1228 #if LCD_WIDTH >= 160 && LCD_HEIGHT >= 128
1230 rb->lcd_bitmap(snake2_header1,0,0,BMPWIDTH_snake2_header, BMPHEIGHT_snake2_header);
1231 rb->lcd_bitmap(snake2_left,0,BMPHEIGHT_snake2_header,BMPWIDTH_snake2_left, BMPHEIGHT_snake2_left);
1232 rb->lcd_bitmap(snake2_right,LCD_WIDTH-BMPWIDTH_snake2_right,BMPHEIGHT_snake2_header,BMPWIDTH_snake2_right, BMPHEIGHT_snake2_right);
1233 rb->lcd_bitmap(snake2_bottom,0,BMPHEIGHT_snake2_header+BMPHEIGHT_snake2_left,BMPWIDTH_snake2_bottom, BMPHEIGHT_snake2_bottom);
1235 rb->snprintf(plevel,sizeof(plevel),"%d",level);
1236 rb->lcd_getstringsize(plevel,&strwdt,&strhgt);
1237 rb->lcd_putsxy(TOP_X3-strwdt/2,TOP_Y2, plevel);
1239 rb->snprintf(plevel,sizeof(plevel),"%d",level_from_file);
1240 rb->lcd_getstringsize(plevel,&strwdt,&strhgt);
1241 rb->lcd_putsxy(TOP_X2-strwdt/2,TOP_Y1, plevel);
1243 if(game_type==0){
1244 rb->lcd_getstringsize("A",&strwdt,&strhgt);
1245 rb->lcd_putsxy(TOP_X1,TOP_Y1,"A");
1247 else{
1248 rb->lcd_getstringsize("B",&strwdt,&strhgt);
1249 rb->lcd_putsxy(TOP_X1,TOP_Y1,"B");
1252 rb->snprintf(phscore,sizeof(phscore),"%d",hiscore);
1253 rb->lcd_getstringsize(phscore,&strwdt,&strhgt);
1254 rb->lcd_putsxy(TOP_X4-strwdt/2,TOP_Y2, phscore);
1256 #else
1257 rb->snprintf(plevel,sizeof(plevel),"Speed: %02d",level);
1258 rb->lcd_getstringsize("Speed: 00",&strwdt,&strhgt);
1259 rb->lcd_putsxy((LCD_WIDTH - strwdt)/2,strhgt+4, plevel);
1261 rb->snprintf(plevel,sizeof(plevel),"Maze: %d",level_from_file);
1262 rb->lcd_getstringsize(plevel,&strwdt,&strhgt);
1263 rb->lcd_putsxy((LCD_WIDTH - strwdt)/2,strhgt*2+4, plevel);
1265 if(game_type==0){
1266 rb->lcd_getstringsize("Game Type: A ",&strwdt,&strhgt);
1267 rb->lcd_putsxy((LCD_WIDTH - strwdt)/2,strhgt*3+4,"Game Type: A");
1269 else{
1270 rb->lcd_getstringsize("Game Type: B ",&strwdt,&strhgt);
1271 rb->lcd_putsxy((LCD_WIDTH - strwdt)/2,strhgt*3+4,"Game Type: B");
1274 rb->snprintf(phscore,sizeof(phscore),"Hi Score: %d",hiscore);
1275 rb->lcd_getstringsize(phscore,&strwdt,&strhgt);
1276 rb->lcd_putsxy((LCD_WIDTH - strwdt)/2,strhgt*4+4, phscore);
1277 #endif
1279 rb->lcd_update();
1281 button=rb->button_get(true);
1282 switch (button)
1284 case SNAKE2_LEVEL_UP:
1285 case SNAKE2_LEVEL_UP|BUTTON_REPEAT:
1286 if (level<10)
1287 level+=1;
1288 break;
1289 case SNAKE2_LEVEL_DOWN:
1290 case SNAKE2_LEVEL_DOWN|BUTTON_REPEAT:
1291 if (level>1)
1292 level-=1;
1293 break;
1294 case SNAKE2_QUIT:
1295 quit=1;
1296 return;
1297 break;
1298 case SNAKE2_PLAYPAUSE:
1299 speed = level*20;
1300 return;
1301 break;
1302 case SNAKE2_SELECT_TYPE:
1303 if(game_type==0)game_type=1; else game_type=0;
1304 break;
1305 case SNAKE2_MAZE_NEXT:
1306 rb->lcd_set_drawmode(DRMODE_BG|DRMODE_INVERSEVID);
1307 rb->lcd_fillrect(CENTER_X, CENTER_Y, CENTER_X+WIDTH*MULTIPLIER,
1308 CENTER_Y+HEIGHT*MULTIPLIER);
1309 rb->lcd_set_drawmode(DRMODE_SOLID);
1310 if(level_from_file < num_levels)
1311 level_from_file++;
1312 else
1313 level_from_file = 0;
1314 load_level( level_from_file );
1315 redraw();
1316 break;
1317 #ifdef SNAKE2_MAZE_LAST
1318 case SNAKE2_MAZE_LAST:
1319 rb->lcd_set_drawmode(DRMODE_BG|DRMODE_INVERSEVID);
1320 rb->lcd_fillrect(CENTER_X, CENTER_Y, CENTER_X+WIDTH*MULTIPLIER,
1321 CENTER_Y+HEIGHT*MULTIPLIER);
1322 rb->lcd_set_drawmode(DRMODE_SOLID);
1323 if(level_from_file > 0)
1324 level_from_file--;
1325 else
1326 level_from_file = num_levels;
1327 load_level( level_from_file );
1328 redraw();
1329 break;
1330 #endif
1331 default:
1332 if (rb->default_event_handler(button)==SYS_USB_CONNECTED) {
1333 quit = 2;
1334 return;
1336 break;
1342 enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
1344 (void)(parameter);
1345 rb = api;
1347 /* Lets use the default font */
1348 rb->lcd_setfont(FONT_SYSFIXED);
1349 #if LCD_DEPTH > 1
1350 rb->lcd_set_backdrop(NULL);
1351 #endif
1352 #ifdef HAVE_LCD_COLOR
1353 rb->lcd_set_foreground(LCD_BLACK);
1354 rb->lcd_set_background(LCD_WHITE);
1355 #endif
1357 load_all_levels();
1359 if (num_levels == 0) {
1360 rb->splash(HZ*2, "Failed loading levels!");
1361 return PLUGIN_OK;
1364 iohiscore();
1366 while(quit==0)
1368 game_init();
1369 rb->lcd_clear_display();
1370 frames=1;
1372 if(quit==0)
1374 init_snake();
1376 /*Start Game:*/
1377 game();
1381 iohiscore();
1382 return (quit==1) ? PLUGIN_OK : PLUGIN_USB_CONNECTED;
1385 #endif