Fix warning about missing newline at the EOF
[maemo-rb.git] / apps / plugins / snake2.c
blobbd0257d2be99f0a9c37851c8310554678ec97cea
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"
34 #include "lib/highscore.h"
35 #include "lib/playback_control.h"
39 #define WIDTH 28
40 #define HEIGHT 16
42 #if (LCD_WIDTH >= 160) && (LCD_HEIGHT >= 128)
43 #include "pluginbitmaps/snake2_header1.h"
44 #include "pluginbitmaps/snake2_header2.h"
45 #include "pluginbitmaps/snake2_left.h"
46 #include "pluginbitmaps/snake2_right.h"
47 #include "pluginbitmaps/snake2_bottom.h"
48 #define BMPHEIGHT_snake2_header BMPHEIGHT_snake2_header1
49 #define BMPWIDTH_snake2_header BMPWIDTH_snake2_header1
50 #endif
52 #if (LCD_WIDTH >= 640) && (LCD_HEIGHT >= 480)
53 #define MULTIPLIER 20 /*Modifier for porting on other screens*/
54 #define MODIFIER_1 20
55 #define MODIFIER_2 16
56 #define CENTER_X 40
57 #define CENTER_Y 110
58 #define TOP_X1 68 /* x-coord of the upperleft item (game type) */
59 #define TOP_X2 562 /* x-coord of the upperright item (maze type) */
60 #define TOP_X3 84 /* x-coord of the lowerleft item (speed) */
61 #define TOP_X4 548 /* x-coord of the lowerright item (hi-score) */
62 #define TOP_Y1 8 /* y-coord of the top row of items */
63 #define TOP_Y2 50 /* y-coord of the bottom row of items */
64 #elif (LCD_WIDTH >= 320) && (LCD_HEIGHT >= 240)
65 #define MULTIPLIER 10 /*Modifier for porting on other screens*/
66 #define MODIFIER_1 10
67 #define MODIFIER_2 8
68 #define CENTER_X 20
69 #define CENTER_Y 55
70 #define TOP_X1 34 /* x-coord of the upperleft item (game type) */
71 #define TOP_X2 281 /* x-coord of the upperright item (maze type) */
72 #define TOP_X3 42 /* x-coord of the lowerleft item (speed) */
73 #define TOP_X4 274 /* x-coord of the lowerright item (hi-score) */
74 #define TOP_Y1 4 /* y-coord of the top row of items */
75 #define TOP_Y2 25 /* y-coord of the bottom row of items */
76 #elif (LCD_WIDTH >= 240) && (LCD_HEIGHT >= 168)
77 #define MULTIPLIER 8
78 #define MODIFIER_1 8
79 #define MODIFIER_2 6
80 #define CENTER_X 8
81 #define CENTER_Y 34
82 #define TOP_X1 34
83 #define TOP_X2 201
84 #define TOP_X3 42
85 #define TOP_X4 194
86 #define TOP_Y1 4
87 #define TOP_Y2 25
88 #elif (LCD_WIDTH >= 220) && (LCD_HEIGHT >= 176)
89 #define MULTIPLIER 7
90 #define MODIFIER_1 7
91 #define MODIFIER_2 5
92 #define CENTER_X 12
93 #define CENTER_Y 46
94 #define TOP_X1 34
95 #define TOP_X2 181
96 #define TOP_X3 42
97 #define TOP_X4 174
98 #define TOP_Y1 4
99 #define TOP_Y2 25
100 #elif (LCD_WIDTH >= 176) && (LCD_HEIGHT >= 132)
101 #define MULTIPLIER 5
102 #define MODIFIER_1 5
103 #define MODIFIER_2 3
104 #define CENTER_X 18
105 #define CENTER_Y 40
106 #define TOP_X1 34
107 #define TOP_X2 137
108 #define TOP_X3 42
109 #define TOP_X4 130
110 #define TOP_Y1 4
111 #define TOP_Y2 25
112 #elif (LCD_WIDTH >= 160) && (LCD_HEIGHT >= 128)
113 #define MULTIPLIER 5
114 #define MODIFIER_1 5
115 #define MODIFIER_2 3
116 #define CENTER_X 10
117 #define CENTER_Y 38
118 #define TOP_X1 34
119 #define TOP_X2 121
120 #define TOP_X3 42
121 #define TOP_X4 114
122 #define TOP_Y1 4
123 #define TOP_Y2 25
124 #else
125 #define MULTIPLIER 4
126 #define MODIFIER_1 4
127 #define MODIFIER_2 2
128 #define CENTER_X 0
129 #define CENTER_Y 0
131 #endif
133 /* variable button definitions */
134 #if CONFIG_KEYPAD == RECORDER_PAD
135 #define SNAKE2_LEFT BUTTON_LEFT
136 #define SNAKE2_RIGHT BUTTON_RIGHT
137 #define SNAKE2_UP BUTTON_UP
138 #define SNAKE2_DOWN BUTTON_DOWN
139 #define SNAKE2_QUIT BUTTON_OFF
140 #define SNAKE2_PLAYPAUSE BUTTON_PLAY
141 #define SNAKE2_PLAYPAUSE_TEXT "Play"
143 #elif CONFIG_KEYPAD == ARCHOS_AV300_PAD
144 #define SNAKE2_LEFT BUTTON_LEFT
145 #define SNAKE2_RIGHT BUTTON_RIGHT
146 #define SNAKE2_UP BUTTON_UP
147 #define SNAKE2_DOWN BUTTON_DOWN
148 #define SNAKE2_QUIT BUTTON_OFF
149 #define SNAKE2_PLAYPAUSE BUTTON_SELECT
150 #define SNAKE2_PLAYPAUSE_TEXT "Select"
152 #elif CONFIG_KEYPAD == ONDIO_PAD
153 #define SNAKE2_LEFT BUTTON_LEFT
154 #define SNAKE2_RIGHT BUTTON_RIGHT
155 #define SNAKE2_UP BUTTON_UP
156 #define SNAKE2_DOWN BUTTON_DOWN
157 #define SNAKE2_QUIT BUTTON_OFF
158 #define SNAKE2_PLAYPAUSE BUTTON_MENU
159 #define SNAKE2_PLAYPAUSE_TEXT "Menu"
161 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
162 (CONFIG_KEYPAD == IRIVER_H300_PAD)
163 #define SNAKE2_LEFT BUTTON_LEFT
164 #define SNAKE2_RIGHT BUTTON_RIGHT
165 #define SNAKE2_UP BUTTON_UP
166 #define SNAKE2_DOWN BUTTON_DOWN
167 #define SNAKE2_QUIT BUTTON_OFF
168 #define SNAKE2_PLAYPAUSE BUTTON_ON
169 #define SNAKE2_PLAYPAUSE_TEXT "Play"
171 #define SNAKE2_RC_QUIT BUTTON_RC_STOP
173 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \
174 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
175 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
176 #define SNAKE2_LEFT BUTTON_LEFT
177 #define SNAKE2_RIGHT BUTTON_RIGHT
178 #define SNAKE2_UP BUTTON_MENU
179 #define SNAKE2_DOWN BUTTON_PLAY
180 #define SNAKE2_QUIT (BUTTON_SELECT | BUTTON_MENU)
181 #define SNAKE2_PLAYPAUSE BUTTON_SELECT
182 #define SNAKE2_PLAYPAUSE_TEXT "Select"
184 #elif (CONFIG_KEYPAD == IAUDIO_X5M5_PAD)
185 #define SNAKE2_LEFT BUTTON_LEFT
186 #define SNAKE2_RIGHT BUTTON_RIGHT
187 #define SNAKE2_UP BUTTON_UP
188 #define SNAKE2_DOWN BUTTON_DOWN
189 #define SNAKE2_QUIT BUTTON_POWER
190 #define SNAKE2_PLAYPAUSE BUTTON_SELECT
191 #define SNAKE2_PLAYPAUSE_TEXT "Select"
193 #elif (CONFIG_KEYPAD == GIGABEAT_PAD)
194 #define SNAKE2_LEFT BUTTON_LEFT
195 #define SNAKE2_RIGHT BUTTON_RIGHT
196 #define SNAKE2_UP BUTTON_UP
197 #define SNAKE2_DOWN BUTTON_DOWN
198 #define SNAKE2_QUIT BUTTON_POWER
199 #define SNAKE2_PLAYPAUSE BUTTON_SELECT
200 #define SNAKE2_PLAYPAUSE_TEXT "Select"
202 #elif (CONFIG_KEYPAD == SANSA_E200_PAD) || \
203 (CONFIG_KEYPAD == SANSA_C200_PAD) || \
204 (CONFIG_KEYPAD == SANSA_CONNECT_PAD)
205 #define SNAKE2_LEFT BUTTON_LEFT
206 #define SNAKE2_RIGHT BUTTON_RIGHT
207 #define SNAKE2_UP BUTTON_UP
208 #define SNAKE2_DOWN BUTTON_DOWN
209 #define SNAKE2_QUIT BUTTON_POWER
210 #define SNAKE2_PLAYPAUSE BUTTON_SELECT
211 #define SNAKE2_PLAYPAUSE_TEXT "Select"
213 #elif (CONFIG_KEYPAD == SANSA_CLIP_PAD) || \
214 (CONFIG_KEYPAD == SANSA_M200_PAD)
215 #define SNAKE2_LEFT BUTTON_LEFT
216 #define SNAKE2_RIGHT BUTTON_RIGHT
217 #define SNAKE2_UP BUTTON_UP
218 #define SNAKE2_DOWN BUTTON_DOWN
219 #define SNAKE2_QUIT BUTTON_POWER
220 #define SNAKE2_PLAYPAUSE BUTTON_SELECT
221 #define SNAKE2_PLAYPAUSE_TEXT "Select"
223 #elif (CONFIG_KEYPAD == SANSA_FUZE_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_HOME|BUTTON_REPEAT)
229 #define SNAKE2_PLAYPAUSE BUTTON_SELECT
230 #define SNAKE2_PLAYPAUSE_TEXT "Select"
232 #elif (CONFIG_KEYPAD == IRIVER_H10_PAD)
233 #define SNAKE2_LEFT BUTTON_LEFT
234 #define SNAKE2_RIGHT BUTTON_RIGHT
235 #define SNAKE2_UP BUTTON_SCROLL_UP
236 #define SNAKE2_DOWN BUTTON_SCROLL_DOWN
237 #define SNAKE2_QUIT BUTTON_POWER
238 #define SNAKE2_PLAYPAUSE BUTTON_FF
239 #define SNAKE2_PLAYPAUSE_TEXT "FF"
241 #elif (CONFIG_KEYPAD == GIGABEAT_S_PAD) || \
242 (CONFIG_KEYPAD == SAMSUNG_YPR0_PAD)
243 #define SNAKE2_LEFT BUTTON_LEFT
244 #define SNAKE2_RIGHT BUTTON_RIGHT
245 #define SNAKE2_UP BUTTON_UP
246 #define SNAKE2_DOWN BUTTON_DOWN
247 #define SNAKE2_QUIT BUTTON_BACK
248 #define SNAKE2_PLAYPAUSE BUTTON_SELECT
249 #define SNAKE2_PLAYPAUSE_TEXT "Select"
251 #elif (CONFIG_KEYPAD == MROBE100_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_POWER
257 #define SNAKE2_PLAYPAUSE BUTTON_SELECT
258 #define SNAKE2_PLAYPAUSE_TEXT "Select"
260 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
261 #define SNAKE2_LEFT BUTTON_RC_REW
262 #define SNAKE2_RIGHT BUTTON_RC_FF
263 #define SNAKE2_UP BUTTON_RC_VOL_UP
264 #define SNAKE2_DOWN BUTTON_RC_VOL_DOWN
265 #define SNAKE2_QUIT BUTTON_RC_REC
266 #define SNAKE2_PLAYPAUSE BUTTON_RC_PLAY
267 #define SNAKE2_PLAYPAUSE_TEXT "Play"
269 #elif (CONFIG_KEYPAD == COWON_D2_PAD)
270 #define SNAKE2_QUIT BUTTON_POWER
272 #elif CONFIG_KEYPAD == CREATIVEZVM_PAD
273 #define SNAKE2_LEFT BUTTON_LEFT
274 #define SNAKE2_RIGHT BUTTON_RIGHT
275 #define SNAKE2_UP BUTTON_UP
276 #define SNAKE2_DOWN BUTTON_DOWN
277 #define SNAKE2_QUIT BUTTON_BACK
278 #define SNAKE2_PLAYPAUSE BUTTON_PLAY
279 #define SNAKE2_PLAYPAUSE_TEXT "Play"
281 #elif (CONFIG_KEYPAD == PHILIPS_HDD1630_PAD) || \
282 (CONFIG_KEYPAD == PHILIPS_HDD6330_PAD)
283 #define SNAKE2_LEFT BUTTON_LEFT
284 #define SNAKE2_RIGHT BUTTON_RIGHT
285 #define SNAKE2_UP BUTTON_UP
286 #define SNAKE2_DOWN BUTTON_DOWN
287 #define SNAKE2_QUIT BUTTON_POWER
288 #define SNAKE2_PLAYPAUSE BUTTON_VIEW
289 #define SNAKE2_PLAYPAUSE_TEXT "View"
291 #elif CONFIG_KEYPAD == PHILIPS_SA9200_PAD
292 #define SNAKE2_LEFT BUTTON_PREV
293 #define SNAKE2_RIGHT BUTTON_NEXT
294 #define SNAKE2_UP BUTTON_UP
295 #define SNAKE2_DOWN BUTTON_DOWN
296 #define SNAKE2_QUIT BUTTON_POWER
297 #define SNAKE2_PLAYPAUSE BUTTON_RIGHT
298 #define SNAKE2_PLAYPAUSE_TEXT "Right"
300 #elif (CONFIG_KEYPAD == ONDAVX747_PAD) || \
301 (CONFIG_KEYPAD == ONDAVX777_PAD) || \
302 CONFIG_KEYPAD == MROBE500_PAD
303 #define SNAKE2_QUIT BUTTON_POWER
305 #elif (CONFIG_KEYPAD == SAMSUNG_YH_PAD)
306 #define SNAKE2_LEFT BUTTON_LEFT
307 #define SNAKE2_RIGHT BUTTON_RIGHT
308 #define SNAKE2_UP BUTTON_UP
309 #define SNAKE2_DOWN BUTTON_DOWN
310 #define SNAKE2_QUIT BUTTON_REC
311 #define SNAKE2_PLAYPAUSE BUTTON_PLAY
312 #define SNAKE2_PLAYPAUSE_TEXT "Play"
314 #elif CONFIG_KEYPAD == PBELL_VIBE500_PAD
315 #define SNAKE2_LEFT BUTTON_PREV
316 #define SNAKE2_RIGHT BUTTON_NEXT
317 #define SNAKE2_UP BUTTON_UP
318 #define SNAKE2_DOWN BUTTON_DOWN
319 #define SNAKE2_QUIT BUTTON_REC
320 #define SNAKE2_PLAYPAUSE BUTTON_PLAY
321 #define SNAKE2_PLAYPAUSE_TEXT "Play"
323 #elif CONFIG_KEYPAD == MPIO_HD200_PAD
324 #define SNAKE2_LEFT BUTTON_VOL_DOWN
325 #define SNAKE2_RIGHT BUTTON_VOL_UP
326 #define SNAKE2_UP BUTTON_REW
327 #define SNAKE2_DOWN BUTTON_FF
328 #define SNAKE2_QUIT (BUTTON_REC | BUTTON_PLAY)
329 #define SNAKE2_PLAYPAUSE BUTTON_PLAY
330 #define SNAKE2_PLAYPAUSE_TEXT "Play"
332 #elif CONFIG_KEYPAD == MPIO_HD300_PAD
333 #define SNAKE2_LEFT BUTTON_MENU
334 #define SNAKE2_RIGHT BUTTON_ENTER
335 #define SNAKE2_UP BUTTON_UP
336 #define SNAKE2_DOWN BUTTON_DOWN
337 #define SNAKE2_QUIT (BUTTON_REC|BUTTON_REPEAT)
338 #define SNAKE2_PLAYPAUSE BUTTON_PLAY
339 #define SNAKE2_PLAYPAUSE_TEXT "Play"
341 #elif CONFIG_KEYPAD == SANSA_FUZEPLUS_PAD
342 #define SNAKE2_LEFT BUTTON_LEFT
343 #define SNAKE2_RIGHT BUTTON_RIGHT
344 #define SNAKE2_UP BUTTON_UP
345 #define SNAKE2_DOWN BUTTON_DOWN
346 #define SNAKE2_QUIT BUTTON_POWER
347 #define SNAKE2_PLAYPAUSE BUTTON_PLAYPAUSE
348 #define SNAKE2_PLAYPAUSE_TEXT "Play/Pause"
350 #else
351 #error No keymap defined!
352 #endif
354 #ifdef HAVE_TOUCHSCREEN
355 #ifndef SNAKE2_LEFT
356 #define SNAKE2_LEFT BUTTON_MIDLEFT
357 #endif
358 #ifndef SNAKE2_RIGHT
359 #define SNAKE2_RIGHT BUTTON_MIDRIGHT
360 #endif
361 #ifndef SNAKE2_UP
362 #define SNAKE2_UP BUTTON_TOPMIDDLE
363 #endif
364 #ifndef SNAKE2_DOWN
365 #define SNAKE2_DOWN BUTTON_BOTTOMMIDDLE
366 #endif
367 #ifndef SNAKE2_QUIT
368 #define SNAKE2_QUIT BUTTON_TOPLEFT
369 #endif
370 #ifndef SNAKE2_PLAYPAUSE
371 #define SNAKE2_PLAYPAUSE BUTTON_CENTER
372 #endif
373 #ifndef SNAKE2_PLAYPAUSE_TEXT
374 #define SNAKE2_PLAYPAUSE_TEXT "CENTER"
375 #endif
376 #endif
378 static int max_levels = 0;
379 static char (*level_cache)[HEIGHT][WIDTH];
381 /*Board itself - 2D int array*/
382 static int board[WIDTH][HEIGHT];
384 Buffer for sorting movement (in case user presses two movements during a
385 single frame
387 static int ardirectionbuffer[2];
388 static int score;
389 static int applex;
390 static int appley;
391 static int dir;
392 static int frames;
393 static int apple;
394 static int level = 4, speed = 5,dead = 0, quit = 0;
395 static int sillydir = 0, num_levels = 0;
396 static int level_from_file = 0;
397 static int headx, heady, tailx, taily, applecountdown = 5;
398 static int game_type = 0;
399 static int num_apples_to_get=1;
400 static int num_apples_to_got=0;
401 static int game_b_level=0;
402 static int applecount=0;
403 /* used for string width, height for orientation purposes */
404 static int strwdt, strhgt;
405 static char strbuf[32];
407 #define NUM_SCORES 5
408 static struct highscore highscores[NUM_SCORES];
410 #define NORTH 1
411 #define EAST 2
412 #define SOUTH 4
413 #define WEST 8
414 #define HEAD 16
416 #define EAST_NORTH 32
417 #define EAST_SOUTH 64
418 #define WEST_NORTH 128
419 #define WEST_SOUTH 256
421 #define NORTH_EAST 512
422 #define NORTH_WEST 1024
423 #define SOUTH_EAST 2048
424 #define SOUTH_WEST 4096
426 #define LEVELS_FILE PLUGIN_GAMES_DIR "/snake2.levels"
427 #define SCORE_FILE PLUGIN_GAMES_DATA_DIR "/snake2.score"
429 static int load_all_levels(void)
431 int linecnt = 0;
432 int fd;
433 size_t size;
434 char buf[64]; /* Larger than WIDTH, to allow for whitespace after the
435 lines */
437 /* Init the level_cache pointer and
438 calculate how many levels that will fit */
439 level_cache = rb->plugin_get_buffer(&size);
440 max_levels = size / (HEIGHT*WIDTH);
442 num_levels = 0;
444 /* open file */
445 if ((fd = rb->open(LEVELS_FILE, O_RDONLY)) < 0)
447 return -1;
450 while(rb->read_line(fd, buf, 64) > 0)
452 if(rb->strlen(buf) == 0) /* Separator? */
454 num_levels++;
455 if(num_levels > max_levels)
457 rb->splash(HZ, "Too many levels in file");
458 break;
460 continue;
463 rb->memcpy(level_cache[num_levels][linecnt], buf, WIDTH);
464 linecnt++;
465 if(linecnt == HEIGHT)
467 linecnt = 0;
471 rb->close(fd);
472 return 0;
476 ** Completely clear the board of walls and/or snake
479 static void clear_board( void)
481 int x,y;
483 for (x = 0; x < WIDTH; x++)
485 for (y = 0; y < HEIGHT; y++)
487 board[x][y] = 0;
492 static int load_level( int level_number )
494 int x,y;
495 clear_board();
496 for(y = 0;y < HEIGHT;y++)
498 for(x = 0;x < WIDTH;x++)
500 switch(level_cache[level_number][y][x])
502 case '|':
503 board[x][y] = NORTH;
504 break;
506 case '-':
507 board[x][y] = EAST;
508 break;
510 case '+':
511 board[x][y] = HEAD;
512 break;
516 return 1;
520 ** Gets the currently chosen direction from the first place
521 ** in the direction buffer. If there is something in the
522 ** next part of the buffer then that is moved to the first place
524 static void get_direction( void )
526 /*if 1st place is empty*/
527 if(ardirectionbuffer[0] != -1)
529 /*return this direction*/
530 dir = ardirectionbuffer[0];
531 ardirectionbuffer[0]=-1;
532 /*now see if one needs moving:*/
533 if(ardirectionbuffer[1] != -1)
535 /*there's a move waiting to be done
536 so move it into the space:*/
537 ardirectionbuffer[0] = ardirectionbuffer[1];
538 ardirectionbuffer[1] = -1;
544 ** Sets the direction
546 static void set_direction(int newdir)
548 if(ardirectionbuffer[0] != newdir)
550 /*if 1st place is empty*/
551 if(ardirectionbuffer[0] == -1)
553 /*use 1st space:*/
554 ardirectionbuffer[0] = newdir;
556 else
558 /*use 2nd space:*/
559 if(ardirectionbuffer[0] != newdir) ardirectionbuffer[1] = newdir;
562 if(frames < 0) ardirectionbuffer[0] = newdir;
566 static void new_level(int level)
568 load_level(level);
570 ardirectionbuffer[0] = -1;
571 ardirectionbuffer[1] = -1;
572 dir = EAST;
573 headx = WIDTH/2;
574 heady = HEIGHT/2;
575 tailx = headx - 4;
576 taily = heady;
577 applecountdown = 0;
578 /*Create a small snake to start off with*/
579 board[headx][heady] = dir;
580 board[headx-1][heady] = dir;
581 board[headx-2][heady] = dir;
582 board[headx-3][heady] = dir;
583 board[headx-4][heady] = dir;
584 num_apples_to_got=0;
587 static void init_snake(void)
589 num_apples_to_get=1;
590 if(game_type == 1)
591 level_from_file = 1;
592 game_b_level=1;
593 new_level(level_from_file);
596 #if (LCD_WIDTH >= 160) && (LCD_HEIGHT >= 128)
597 static void draw_frame_bitmap(int header_type)
599 rb->lcd_bitmap(header_type==1? snake2_header1: snake2_header2, 0, 0,
600 BMPWIDTH_snake2_header, BMPHEIGHT_snake2_header);
601 rb->lcd_bitmap(snake2_left, 0, BMPHEIGHT_snake2_header,
602 BMPWIDTH_snake2_left, BMPHEIGHT_snake2_left);
603 rb->lcd_bitmap(snake2_right,
604 LCD_WIDTH - BMPWIDTH_snake2_right, BMPHEIGHT_snake2_header,
605 BMPWIDTH_snake2_right, BMPHEIGHT_snake2_right);
606 rb->lcd_bitmap(snake2_bottom,
607 0, BMPHEIGHT_snake2_header + BMPHEIGHT_snake2_left,
608 BMPWIDTH_snake2_bottom, BMPHEIGHT_snake2_bottom);
610 #endif
613 ** Draws the apple. If it doesn't exist then
614 ** a new one get's created.
616 static void draw_apple_bit(int x, int y)
618 rb->lcd_fillrect((CENTER_X+x*MULTIPLIER)+1, CENTER_Y+y*MULTIPLIER,
619 MODIFIER_2, MODIFIER_1);
620 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER, (CENTER_Y+y*MULTIPLIER)+1,
621 MODIFIER_1, MODIFIER_2);
624 static void draw_apple( void )
626 int x,y;
628 #if LCD_WIDTH >= 160 && LCD_HEIGHT >= 128
629 draw_frame_bitmap(2);
631 rb->snprintf(strbuf, sizeof(strbuf), "%d", applecount);
632 rb->lcd_getstringsize(strbuf, &strwdt, &strhgt);
633 rb->lcd_putsxy(TOP_X3 - strwdt/2, TOP_Y2, strbuf);
635 rb->snprintf(strbuf, sizeof(strbuf), "%d", score);
636 rb->lcd_getstringsize(strbuf, &strwdt, &strhgt);
637 rb->lcd_putsxy(TOP_X4 - strwdt/2, TOP_Y2, strbuf);
638 #endif
640 if (!apple)
644 x = (rb->rand() % (WIDTH-1))+1;
645 y = (rb->rand() % (HEIGHT-1))+1;
646 } while (board[x][y]);
647 apple = 1;
648 board[x][y] = -1;
649 applex = x;appley = y;
651 draw_apple_bit(applex, appley);
655 * x x *
656 * x x *
657 * x x *
658 * x x *
660 static void draw_vertical_bit(int x, int y)
662 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER+1, CENTER_Y+y*MULTIPLIER,
663 MODIFIER_2, MODIFIER_1);
667 * * * *
668 X X X X
669 X X X X
670 * * * *
672 static void draw_horizontal_bit(int x, int y)
674 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER, CENTER_Y+y*MULTIPLIER+1,
675 MODIFIER_1, MODIFIER_2);
679 * * * *
680 * * X X
681 * X X X
682 * X X *
684 static void draw_n_to_e_bit(int x, int y)
686 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER+1, CENTER_Y+y*MULTIPLIER+2,
687 MODIFIER_2, MODIFIER_2);
688 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER+2, CENTER_Y+y*MULTIPLIER+1,
689 MODIFIER_2, MODIFIER_2);
693 * * * *
694 * * X X
695 * X X X
696 * X X *
698 static void draw_w_to_s_bit(int x, int y)
700 draw_n_to_e_bit(x,y);
704 * * * *
705 X X * *
706 X X X *
707 * X X *
709 static void draw_n_to_w_bit(int x, int y)
711 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER, CENTER_Y+y*MULTIPLIER+1,
712 MODIFIER_2, MODIFIER_2);
713 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER+1, CENTER_Y+y*MULTIPLIER+2,
714 MODIFIER_2, MODIFIER_2);
718 * * * *
719 X X * *
720 X X X *
721 * X X *
723 static void draw_e_to_s_bit(int x, int y)
725 draw_n_to_w_bit(x, y);
729 * X X *
730 * X X X
731 * * X X
732 * * * *
734 static void draw_s_to_e_bit(int x, int y)
736 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER+1, CENTER_Y+y*MULTIPLIER,
737 MODIFIER_2, MODIFIER_2);
738 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER+2, CENTER_Y+y*MULTIPLIER+1,
739 MODIFIER_2, MODIFIER_2);
743 * X X *
744 * X X X
745 * * X X
746 * * * *
748 static void draw_w_to_n_bit(int x, int y)
750 draw_s_to_e_bit(x,y);
754 * X X *
755 X X X *
756 X X * *
757 * * * *
759 static void draw_e_to_n_bit(int x, int y)
761 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER+1, CENTER_Y+y*MULTIPLIER,
762 MODIFIER_2, MODIFIER_2);
763 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER, CENTER_Y+y*MULTIPLIER+1,
764 MODIFIER_2, MODIFIER_2);
768 * X X *
769 X X X *
770 X X * *
771 * * * *
773 static void draw_s_to_w_bit(int x, int y)
775 draw_e_to_n_bit(x, y);
778 static void draw_head_bit(int x, int y)
780 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER, CENTER_Y+y*MULTIPLIER,
781 MODIFIER_1, MODIFIER_1);
784 #if 0 /* unused */
786 ** Draws a wall/obsticals
788 static void draw_boundary ( void )
790 int x, y;
792 /*TODO: Load levels from file!*/
794 /*top and bottom line*/
795 for(x=0; x < WIDTH; x++)
797 board[x][0] = EAST;
798 board[x][HEIGHT-1] = WEST;
801 /*left and right lines*/
802 for(y=0; y < HEIGHT; y++)
804 board[0][y] = NORTH;
805 board[WIDTH-1][y] = SOUTH;
808 /*corners:*/
809 board[0][0] = NORTH_EAST;
810 board[WIDTH-1][0] = EAST_SOUTH;
811 board[0][HEIGHT-1] = SOUTH_EAST;
812 board[WIDTH-1][HEIGHT-1] = EAST_NORTH;
814 #endif
817 ** Redraw the entire board
819 static void redraw (void)
821 int x,y;
823 #ifdef HAVE_LCD_COLOR
824 rb->lcd_set_foreground(LCD_BLACK);
825 rb->lcd_set_background(LCD_WHITE);
826 #endif
828 rb->lcd_clear_display();
830 for (x = 0; x < WIDTH; x++)
832 for (y = 0; y < HEIGHT; y++)
834 switch (board[x][y])
836 case -1:
837 draw_apple_bit(x, y);
838 break;
839 case 0:
840 break;
842 case NORTH:
843 case SOUTH:
844 draw_vertical_bit(x,y);
845 break;
847 case EAST:
848 case WEST:
849 draw_horizontal_bit(x,y);
850 break;
852 default:
853 draw_head_bit(x, y);
854 break;
859 #if LCD_WIDTH >= 160 && LCD_HEIGHT >= 128
860 draw_frame_bitmap(2);
862 rb->snprintf(strbuf, sizeof(strbuf), "%d", applecount);
863 rb->lcd_getstringsize(strbuf, &strwdt, &strhgt);
864 rb->lcd_putsxy(TOP_X3 - strwdt/2, TOP_Y2, strbuf);
866 rb->snprintf(strbuf, sizeof(strbuf), "%d", score);
867 rb->lcd_getstringsize(strbuf, &strwdt, &strhgt);
868 rb->lcd_putsxy(TOP_X4 - strwdt/2, TOP_Y2, strbuf);
869 #endif
873 ** Draws the snake bit described by nCurrentBit at position x/y
874 ** deciding whether it's a corner bit by examing the nPrevious bit
876 static void draw_snake_bit(int currentbit, int previousbit, int x, int y)
878 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
879 draw_head_bit(x, y);
880 rb->lcd_set_drawmode(DRMODE_SOLID);
882 switch(currentbit)
884 case(NORTH):
885 switch(previousbit)
887 case(SOUTH):
888 case(NORTH):
889 draw_vertical_bit(x,y);
890 break;
892 case(EAST):
893 draw_e_to_n_bit(x,y);
894 break;
896 case(WEST):
897 draw_w_to_n_bit(x,y);
898 break;
900 break;
902 case(EAST):
903 switch(previousbit)
905 case(WEST):
906 case(EAST):
907 draw_horizontal_bit(x,y);
908 break;
910 case(NORTH):
911 draw_n_to_e_bit(x,y);
912 break;
914 case(SOUTH):
915 draw_s_to_e_bit(x,y);
916 break;
918 break;
920 case(SOUTH):
921 switch(previousbit)
923 case(SOUTH):
924 case(NORTH):
925 draw_vertical_bit(x,y);
926 break;
928 case(EAST):
929 draw_e_to_s_bit(x,y);
930 break;
932 case(WEST):
933 draw_w_to_s_bit(x,y);
934 break;
936 break;
938 case(WEST):
939 switch(previousbit)
941 case(EAST):
942 case(WEST):
943 draw_horizontal_bit(x,y);
944 break;
946 case(SOUTH):
947 draw_s_to_w_bit(x,y);
948 break;
950 case(NORTH):
951 draw_n_to_w_bit(x,y);
952 break;
954 break;
958 static void redraw_snake(void)
960 int x = tailx, y = taily;
961 int olddir, newdir = board[x][y];
963 while (x != headx || y != heady)
965 olddir = newdir;
967 switch (olddir)
969 case(NORTH):
970 y--;
971 break;
973 case(EAST):
974 x++;
975 break;
977 case(SOUTH):
978 y++;
979 break;
981 case(WEST):
982 x--;
983 break;
986 if(x == WIDTH)
987 x = 0;
988 else if(x < 0)
989 x = WIDTH-1;
991 if(y == HEIGHT)
992 y = 0;
993 else if(y < 0)
994 y = HEIGHT-1;
996 newdir = board[x][y];
997 if(olddir != newdir)
998 draw_snake_bit(newdir, olddir, x, y);
1003 ** Death 'sequence' and end game stuff.
1005 static void die (void)
1007 int button;
1008 bool done=false;
1010 rb->splash(HZ*2, "Oops!");
1012 rb->lcd_clear_display();
1014 applecount=0;
1016 rb->lcd_getstringsize("You died!",&strwdt,&strhgt);
1017 rb->lcd_putsxy((LCD_WIDTH - strwdt)/2,strhgt,"You died!");
1019 rb->snprintf(strbuf, sizeof(strbuf), "Your score: %d", score);
1020 rb->lcd_getstringsize(strbuf, &strwdt, &strhgt);
1021 rb->lcd_putsxy((LCD_WIDTH - strwdt)/2, strhgt * 2 + 2, strbuf);
1023 if (highscore_update(score, level_from_file, game_type==0?"Type A":"Type B",
1024 highscores, NUM_SCORES) == 0)
1026 rb->lcd_getstringsize("New high score!",&strwdt,&strhgt);
1027 rb->lcd_putsxy((LCD_WIDTH - strwdt)/2,strhgt * 4 + 2,"New high score!");
1029 else
1031 rb->snprintf(strbuf, sizeof(strbuf), "High score: %d", highscores[0].score);
1032 rb->lcd_getstringsize(strbuf, &strwdt, &strhgt);
1033 rb->lcd_putsxy((LCD_WIDTH - strwdt)/2, strhgt * 5, strbuf);
1036 rb->snprintf(strbuf, sizeof(strbuf), "Press %s...", SNAKE2_PLAYPAUSE_TEXT);
1037 rb->lcd_getstringsize(strbuf, &strwdt, &strhgt);
1038 rb->lcd_putsxy((LCD_WIDTH - strwdt)/2, strhgt * 7, strbuf);
1040 rb->lcd_update();
1042 while(!done)
1044 button=rb->button_get(true);
1045 switch(button)
1047 case SNAKE2_PLAYPAUSE:
1048 done = true;
1049 break;
1053 dead=1;
1057 ** Check for collision. TODO: Currently this
1058 ** sets of the death sequence. What we want is it to only return a true/false
1059 ** depending on whether a collision occured.
1061 static void collision ( int x, int y )
1063 int bdeath=0;
1066 switch (board[x][y])
1068 case 0:
1070 break;
1071 case -1:
1072 score = score + (1 * level);
1073 apple=0;
1074 applecountdown=2;
1075 applecount++;
1077 if(game_type==1)
1079 if(num_apples_to_get == num_apples_to_got)
1081 level_from_file++;
1082 if(level_from_file >= num_levels)
1084 level_from_file = 1;
1085 /*and increase the number of apples to pick up
1086 before level changes*/
1087 num_apples_to_get+=2;
1088 game_b_level++;
1090 rb->splash(HZ, "Level Completed!");
1091 new_level(level_from_file);
1092 redraw();
1093 rb->lcd_update();
1095 else
1096 num_apples_to_got++;
1098 break;
1099 default:
1100 bdeath=1;
1101 break;
1104 if(bdeath==1)
1106 die();
1107 sillydir = dir;
1108 frames = -110;
1112 static void move( void )
1114 int taildir;
1115 /*this actually sets the dir variable.*/
1116 get_direction();
1117 /*draw head*/
1118 switch (dir)
1120 case (NORTH):
1121 board[headx][heady]=NORTH;
1122 heady--;
1123 break;
1124 case (EAST):
1125 board[headx][heady]=EAST;
1126 headx++;
1127 break;
1128 case (SOUTH):
1129 board[headx][heady]=SOUTH;
1130 heady++;
1131 break;
1132 case (WEST):
1133 board[headx][heady]=WEST;
1134 headx--;
1135 break;
1138 if(headx == WIDTH)
1139 headx = 0;
1140 else if(headx < 0)
1141 headx = WIDTH-1;
1143 if(heady == HEIGHT)
1144 heady = 0;
1145 else if(heady < 0)
1146 heady = HEIGHT-1;
1148 draw_head_bit(headx, heady);
1150 /*clear tail*/
1151 if(applecountdown <= 0)
1153 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
1154 draw_head_bit(tailx, taily);
1155 rb->lcd_set_drawmode(DRMODE_SOLID);
1157 taildir = board[tailx][taily];
1158 board[tailx][taily] = 0;
1160 switch (taildir)
1162 case(NORTH):
1163 taily--;
1164 break;
1166 case(EAST):
1167 tailx++;
1168 break;
1170 case(SOUTH):
1171 taily++;
1172 break;
1174 case(WEST):
1175 tailx--;
1176 break;
1179 if(tailx == WIDTH)
1180 tailx = 0;
1181 else if(tailx < 0)
1182 tailx = WIDTH-1;
1184 if(taily == HEIGHT)
1185 taily = 0;
1186 else if(taily < 0)
1187 taily = HEIGHT-1;
1189 else
1190 applecountdown--;
1193 static void frame (void)
1195 int olddir, noldx, noldy, temp;
1196 noldx = headx;
1197 noldy = heady;
1198 olddir = 0;
1199 switch(dir)
1201 case(NORTH):
1202 if(heady == HEIGHT-1)
1203 temp = 0;
1204 else
1205 temp = heady + 1;
1207 olddir = board[headx][temp];
1208 break;
1210 case(EAST):
1211 if(headx == 0)
1212 temp = WIDTH-1;
1213 else
1214 temp = headx - 1;
1216 olddir = board[temp][heady];
1217 break;
1219 case(SOUTH):
1220 if(heady == 0)
1221 temp = HEIGHT-1;
1222 else
1223 temp = heady - 1;
1225 olddir = board[headx][temp];
1226 break;
1228 case(WEST):
1229 if(headx == WIDTH-1)
1230 temp = 0;
1231 else
1232 temp = headx + 1;
1234 olddir = board[temp][heady];
1235 break;
1238 move();
1241 now redraw the bit that was
1242 the tail, to something snake-like:
1244 draw_snake_bit(dir, olddir, noldx, noldy);
1246 collision(headx, heady);
1248 rb->lcd_update();
1251 static void game_pause (void)
1253 int button;
1255 rb->lcd_clear_display();
1256 rb->lcd_getstringsize("Paused",&strwdt,&strhgt);
1257 rb->lcd_putsxy((LCD_WIDTH - strwdt)/2,LCD_HEIGHT/2,"Paused");
1259 rb->lcd_update();
1260 while (1)
1262 button = rb->button_get(true);
1263 switch (button)
1265 case SNAKE2_PLAYPAUSE:
1266 redraw();
1267 redraw_snake();
1268 draw_head_bit(headx, heady);
1269 rb->lcd_update();
1270 rb->sleep(HZ/2);
1271 return;
1273 #ifdef SNAKE2_RC_QUIT
1274 case SNAKE2_RC_QUIT:
1275 #endif
1276 case SNAKE2_QUIT:
1277 dead = 1;
1278 quit = 1;
1279 return;
1281 default:
1282 if (rb->default_event_handler(button)==SYS_USB_CONNECTED) {
1283 dead = 1;
1284 quit = 2;
1285 return;
1287 break;
1292 static void game (void)
1294 int button;
1296 redraw();
1297 rb->lcd_update();
1298 /*main loop:*/
1299 while (1)
1301 if(frames==5)
1303 frame();
1304 if(frames > 0) frames = 0;
1306 frames++;
1308 if(frames == 0)
1310 die();
1312 else
1314 if(frames < 0)
1316 if(sillydir != dir)
1318 /*it has, great set frames to a positive value again:*/
1319 frames = 1;
1324 if (dead) return;
1326 draw_apple();
1328 rb->sleep(HZ/speed);
1330 button = rb->button_get(false);
1332 #ifdef HAS_BUTTON_HOLD
1333 if (rb->button_hold())
1334 button = SNAKE2_PLAYPAUSE;
1335 #endif
1337 switch (button)
1339 case SNAKE2_UP:
1340 case SNAKE2_UP | BUTTON_REPEAT:
1341 if (dir != SOUTH) set_direction(NORTH);
1342 break;
1344 case SNAKE2_RIGHT:
1345 case SNAKE2_RIGHT | BUTTON_REPEAT:
1346 if (dir != WEST) set_direction(EAST);
1347 break;
1349 case SNAKE2_DOWN:
1350 case SNAKE2_DOWN | BUTTON_REPEAT:
1351 if (dir != NORTH) set_direction(SOUTH);
1352 break;
1354 case SNAKE2_LEFT:
1355 case SNAKE2_LEFT | BUTTON_REPEAT:
1356 if (dir != EAST) set_direction(WEST);
1357 break;
1359 #ifdef SNAKE2_RC_QUIT
1360 case SNAKE2_RC_QUIT:
1361 #endif
1362 case SNAKE2_QUIT:
1363 quit = 1;
1364 return;
1366 case SNAKE2_PLAYPAUSE:
1367 game_pause();
1368 break;
1370 default:
1371 if (rb->default_event_handler(button)==SYS_USB_CONNECTED) {
1372 quit = 2;
1373 return;
1375 break;
1381 static void select_maze(void)
1383 int button;
1385 clear_board();
1386 load_level( level_from_file );
1387 redraw();
1388 rb->lcd_update();
1390 while (1)
1392 #if LCD_WIDTH >= 160 && LCD_HEIGHT >= 128
1393 draw_frame_bitmap(1);
1395 rb->snprintf(strbuf, sizeof(strbuf), "%d", level);
1396 rb->lcd_getstringsize(strbuf, &strwdt, &strhgt);
1397 rb->lcd_putsxy(TOP_X3 - strwdt/2, TOP_Y2, strbuf);
1399 rb->snprintf(strbuf, sizeof(strbuf), "%d", level_from_file);
1400 rb->lcd_getstringsize(strbuf, &strwdt, &strhgt);
1401 rb->lcd_putsxy(TOP_X2 - strwdt/2, TOP_Y1, strbuf);
1403 rb->strcpy(strbuf, game_type==0? "A": "B");
1404 rb->lcd_getstringsize(strbuf, &strwdt, &strhgt);
1405 rb->lcd_putsxy(TOP_X1, TOP_Y1, strbuf);
1407 rb->snprintf(strbuf, sizeof(strbuf), "%d", highscores[0].score);
1408 rb->lcd_getstringsize(strbuf, &strwdt, &strhgt);
1409 rb->lcd_putsxy(TOP_X4 - strwdt/2, TOP_Y2, strbuf);
1411 #else
1412 rb->snprintf(strbuf, sizeof(strbuf), "Maze: %d", level_from_file);
1413 rb->lcd_getstringsize(strbuf, &strwdt, &strhgt);
1414 rb->lcd_putsxy((WIDTH*MULTIPLIER - strwdt)/2,
1415 (HEIGHT*MULTIPLIER - strhgt)/2, strbuf);
1416 #endif
1418 rb->lcd_update();
1420 button = rb->button_get(true);
1421 switch (button)
1423 case SNAKE2_QUIT:
1424 case SNAKE2_PLAYPAUSE:
1425 return;
1426 break;
1427 case SNAKE2_UP:
1428 case SNAKE2_RIGHT:
1429 if(level_from_file < num_levels)
1430 level_from_file++;
1431 else
1432 level_from_file = 0;
1433 load_level( level_from_file );
1434 redraw();
1435 break;
1436 case SNAKE2_DOWN:
1437 case SNAKE2_LEFT:
1438 if(level_from_file > 0)
1439 level_from_file--;
1440 else
1441 level_from_file = num_levels;
1442 load_level( level_from_file );
1443 redraw();
1444 break;
1445 default:
1446 if (rb->default_event_handler(button)==SYS_USB_CONNECTED) {
1447 quit = 2;
1448 return;
1450 break;
1456 static void game_init(void)
1458 int selection = 0;
1460 static const struct opt_items type_options[] = {
1461 { "Type A", -1 },
1462 { "Type B", -1 },
1465 MENUITEM_STRINGLIST(menu, "Snake2 Menu", NULL,
1466 "Start New Game",
1467 "Game Type", "Select Maze", "Speed",
1468 "High Scores",
1469 "Playback Control", "Quit");
1471 rb->button_clear_queue();
1473 dead = 0;
1474 apple = 0;
1475 score = 0;
1476 applecount = 0;
1478 while (1) {
1479 switch (rb->do_menu(&menu, &selection, NULL, false)) {
1480 case 0:
1481 speed = level*20;
1482 return;
1483 case 1:
1484 rb->set_option("Game Type", &game_type, INT,
1485 type_options, 2, NULL);
1486 break;
1487 case 2:
1488 select_maze();
1489 if(quit) return;
1490 break;
1491 case 3:
1492 rb->set_int("Speed", "", UNIT_INT, &level,
1493 NULL, 1, 1, 10, NULL);
1494 break;
1495 case 4:
1496 highscore_show(-1, highscores, NUM_SCORES, true);
1497 break;
1498 case 5:
1499 playback_control(NULL);
1500 break;
1501 case 6:
1502 quit = 1;
1503 return;
1504 case MENU_ATTACHED_USB:
1505 quit = 2;
1506 return;
1507 default:
1508 break;
1513 enum plugin_status plugin_start(const void* parameter)
1515 (void)(parameter);
1517 /* Lets use the default font */
1518 rb->lcd_setfont(FONT_SYSFIXED);
1519 #if LCD_DEPTH > 1
1520 rb->lcd_set_backdrop(NULL);
1521 #endif
1523 load_all_levels();
1525 if (num_levels == 0) {
1526 rb->splash(HZ*2, "Failed loading levels!");
1527 return PLUGIN_OK;
1530 highscore_load(SCORE_FILE, highscores, NUM_SCORES);
1532 while(quit==0)
1534 game_init();
1535 if(quit)
1536 break;
1538 rb->lcd_clear_display();
1539 frames=1;
1541 init_snake();
1543 /*Start Game:*/
1544 game();
1547 highscore_save(SCORE_FILE, highscores, NUM_SCORES);
1549 return (quit==1) ? PLUGIN_OK : PLUGIN_USB_CONNECTED;