Doom plugin: In anticipation of moving to the EABI toolchain, because of its assumpti...
[kugel-rb.git] / apps / plugins / snake2.c
blob414d924c4a0e4b474e1086175cf000e0a57dbc36
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
34 #include "lib/highscore.h"
35 #include "lib/playback_control.h"
37 PLUGIN_HEADER
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 #define SNAKE2_LEFT BUTTON_LEFT
205 #define SNAKE2_RIGHT BUTTON_RIGHT
206 #define SNAKE2_UP BUTTON_UP
207 #define SNAKE2_DOWN BUTTON_DOWN
208 #define SNAKE2_QUIT BUTTON_POWER
209 #define SNAKE2_PLAYPAUSE BUTTON_SELECT
210 #define SNAKE2_PLAYPAUSE_TEXT "Select"
212 #elif (CONFIG_KEYPAD == SANSA_CLIP_PAD) || \
213 (CONFIG_KEYPAD == SANSA_M200_PAD)
214 #define SNAKE2_LEFT BUTTON_LEFT
215 #define SNAKE2_RIGHT BUTTON_RIGHT
216 #define SNAKE2_UP BUTTON_UP
217 #define SNAKE2_DOWN BUTTON_DOWN
218 #define SNAKE2_QUIT BUTTON_POWER
219 #define SNAKE2_PLAYPAUSE BUTTON_SELECT
220 #define SNAKE2_PLAYPAUSE_TEXT "Select"
222 #elif (CONFIG_KEYPAD == SANSA_FUZE_PAD)
223 #define SNAKE2_LEFT BUTTON_LEFT
224 #define SNAKE2_RIGHT BUTTON_RIGHT
225 #define SNAKE2_UP BUTTON_UP
226 #define SNAKE2_DOWN BUTTON_DOWN
227 #define SNAKE2_QUIT (BUTTON_HOME|BUTTON_REPEAT)
228 #define SNAKE2_PLAYPAUSE BUTTON_SELECT
229 #define SNAKE2_PLAYPAUSE_TEXT "Select"
231 #elif (CONFIG_KEYPAD == IRIVER_H10_PAD)
232 #define SNAKE2_LEFT BUTTON_LEFT
233 #define SNAKE2_RIGHT BUTTON_RIGHT
234 #define SNAKE2_UP BUTTON_SCROLL_UP
235 #define SNAKE2_DOWN BUTTON_SCROLL_DOWN
236 #define SNAKE2_QUIT BUTTON_POWER
237 #define SNAKE2_PLAYPAUSE BUTTON_FF
238 #define SNAKE2_PLAYPAUSE_TEXT "FF"
240 #elif (CONFIG_KEYPAD == GIGABEAT_S_PAD)
241 #define SNAKE2_LEFT BUTTON_LEFT
242 #define SNAKE2_RIGHT BUTTON_RIGHT
243 #define SNAKE2_UP BUTTON_UP
244 #define SNAKE2_DOWN BUTTON_DOWN
245 #define SNAKE2_QUIT BUTTON_BACK
246 #define SNAKE2_PLAYPAUSE BUTTON_SELECT
247 #define SNAKE2_PLAYPAUSE_TEXT "Select"
249 #elif (CONFIG_KEYPAD == MROBE100_PAD)
250 #define SNAKE2_LEFT BUTTON_LEFT
251 #define SNAKE2_RIGHT BUTTON_RIGHT
252 #define SNAKE2_UP BUTTON_UP
253 #define SNAKE2_DOWN BUTTON_DOWN
254 #define SNAKE2_QUIT BUTTON_POWER
255 #define SNAKE2_PLAYPAUSE BUTTON_SELECT
256 #define SNAKE2_PLAYPAUSE_TEXT "Select"
258 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
259 #define SNAKE2_LEFT BUTTON_RC_REW
260 #define SNAKE2_RIGHT BUTTON_RC_FF
261 #define SNAKE2_UP BUTTON_RC_VOL_UP
262 #define SNAKE2_DOWN BUTTON_RC_VOL_DOWN
263 #define SNAKE2_QUIT BUTTON_RC_REC
264 #define SNAKE2_PLAYPAUSE BUTTON_RC_PLAY
265 #define SNAKE2_PLAYPAUSE_TEXT "Play"
267 #elif (CONFIG_KEYPAD == COWON_D2_PAD)
268 #define SNAKE2_QUIT BUTTON_POWER
270 #elif CONFIG_KEYPAD == CREATIVEZVM_PAD
271 #define SNAKE2_LEFT BUTTON_LEFT
272 #define SNAKE2_RIGHT BUTTON_RIGHT
273 #define SNAKE2_UP BUTTON_UP
274 #define SNAKE2_DOWN BUTTON_DOWN
275 #define SNAKE2_QUIT BUTTON_BACK
276 #define SNAKE2_PLAYPAUSE BUTTON_PLAY
277 #define SNAKE2_PLAYPAUSE_TEXT "Play"
279 #elif CONFIG_KEYPAD == PHILIPS_HDD1630_PAD
280 #define SNAKE2_LEFT BUTTON_LEFT
281 #define SNAKE2_RIGHT BUTTON_RIGHT
282 #define SNAKE2_UP BUTTON_UP
283 #define SNAKE2_DOWN BUTTON_DOWN
284 #define SNAKE2_QUIT BUTTON_POWER
285 #define SNAKE2_PLAYPAUSE BUTTON_VIEW
286 #define SNAKE2_PLAYPAUSE_TEXT "View"
288 #elif CONFIG_KEYPAD == PHILIPS_SA9200_PAD
289 #define SNAKE2_LEFT BUTTON_PREV
290 #define SNAKE2_RIGHT BUTTON_NEXT
291 #define SNAKE2_UP BUTTON_UP
292 #define SNAKE2_DOWN BUTTON_DOWN
293 #define SNAKE2_QUIT BUTTON_POWER
294 #define SNAKE2_PLAYPAUSE BUTTON_RIGHT
295 #define SNAKE2_PLAYPAUSE_TEXT "Right"
297 #elif (CONFIG_KEYPAD == ONDAVX747_PAD) || \
298 (CONFIG_KEYPAD == ONDAVX777_PAD) || \
299 CONFIG_KEYPAD == MROBE500_PAD
300 #define SNAKE2_QUIT BUTTON_POWER
302 #elif (CONFIG_KEYPAD == SAMSUNG_YH_PAD)
303 #define SNAKE2_LEFT BUTTON_LEFT
304 #define SNAKE2_RIGHT BUTTON_RIGHT
305 #define SNAKE2_UP BUTTON_UP
306 #define SNAKE2_DOWN BUTTON_DOWN
307 #define SNAKE2_QUIT BUTTON_REC
308 #define SNAKE2_PLAYPAUSE BUTTON_PLAY
309 #define SNAKE2_PLAYPAUSE_TEXT "Play"
311 #elif CONFIG_KEYPAD == PBELL_VIBE500_PAD
312 #define SNAKE2_LEFT BUTTON_PREV
313 #define SNAKE2_RIGHT BUTTON_NEXT
314 #define SNAKE2_UP BUTTON_UP
315 #define SNAKE2_DOWN BUTTON_DOWN
316 #define SNAKE2_QUIT BUTTON_REC
317 #define SNAKE2_PLAYPAUSE BUTTON_PLAY
318 #define SNAKE2_PLAYPAUSE_TEXT "Play"
320 #elif CONFIG_KEYPAD == MPIO_HD200_PAD
321 #define SNAKE2_LEFT BUTTON_VOL_DOWN
322 #define SNAKE2_RIGHT BUTTON_VOL_UP
323 #define SNAKE2_UP BUTTON_PREV
324 #define SNAKE2_DOWN BUTTON_NEXT
325 #define SNAKE2_QUIT (BUTTON_REC | BUTTON_PLAY)
326 #define SNAKE2_PLAYPAUSE BUTTON_PLAY
327 #define SNAKE2_PLAYPAUSE_TEXT "Play"
329 #else
330 #error No keymap defined!
331 #endif
333 #ifdef HAVE_TOUCHSCREEN
334 #ifndef SNAKE2_LEFT
335 #define SNAKE2_LEFT BUTTON_MIDLEFT
336 #endif
337 #ifndef SNAKE2_RIGHT
338 #define SNAKE2_RIGHT BUTTON_MIDRIGHT
339 #endif
340 #ifndef SNAKE2_UP
341 #define SNAKE2_UP BUTTON_TOPMIDDLE
342 #endif
343 #ifndef SNAKE2_DOWN
344 #define SNAKE2_DOWN BUTTON_BOTTOMMIDDLE
345 #endif
346 #ifndef SNAKE2_QUIT
347 #define SNAKE2_QUIT BUTTON_TOPLEFT
348 #endif
349 #ifndef SNAKE2_PLAYPAUSE
350 #define SNAKE2_PLAYPAUSE BUTTON_CENTER
351 #endif
352 #ifndef SNAKE2_PLAYPAUSE_TEXT
353 #define SNAKE2_PLAYPAUSE_TEXT "CENTER"
354 #endif
355 #endif
357 static int max_levels = 0;
358 static char (*level_cache)[HEIGHT][WIDTH];
360 /*Board itself - 2D int array*/
361 static int board[WIDTH][HEIGHT];
363 Buffer for sorting movement (in case user presses two movements during a
364 single frame
366 static int ardirectionbuffer[2];
367 static int score;
368 static int applex;
369 static int appley;
370 static int dir;
371 static int frames;
372 static int apple;
373 static int level = 4, speed = 5,dead = 0, quit = 0;
374 static int sillydir = 0, num_levels = 0;
375 static int level_from_file = 0;
376 static int headx, heady, tailx, taily, applecountdown = 5;
377 static int game_type = 0;
378 static int num_apples_to_get=1;
379 static int num_apples_to_got=0;
380 static int game_b_level=0;
381 static int applecount=0;
382 /* used for string width, height for orientation purposes */
383 static int strwdt, strhgt;
384 static char strbuf[32];
386 #define NUM_SCORES 5
387 static struct highscore highscores[NUM_SCORES];
389 #define NORTH 1
390 #define EAST 2
391 #define SOUTH 4
392 #define WEST 8
393 #define HEAD 16
395 #define EAST_NORTH 32
396 #define EAST_SOUTH 64
397 #define WEST_NORTH 128
398 #define WEST_SOUTH 256
400 #define NORTH_EAST 512
401 #define NORTH_WEST 1024
402 #define SOUTH_EAST 2048
403 #define SOUTH_WEST 4096
405 #define LEVELS_FILE PLUGIN_GAMES_DIR "/snake2.levels"
406 #define SCORE_FILE PLUGIN_GAMES_DIR "/snake2.score"
408 int load_all_levels(void)
410 int linecnt = 0;
411 int fd;
412 size_t size;
413 char buf[64]; /* Larger than WIDTH, to allow for whitespace after the
414 lines */
416 /* Init the level_cache pointer and
417 calculate how many levels that will fit */
418 level_cache = rb->plugin_get_buffer(&size);
419 max_levels = size / (HEIGHT*WIDTH);
421 num_levels = 0;
423 /* open file */
424 if ((fd = rb->open(LEVELS_FILE, O_RDONLY)) < 0)
426 return -1;
429 while(rb->read_line(fd, buf, 64) > 0)
431 if(rb->strlen(buf) == 0) /* Separator? */
433 num_levels++;
434 if(num_levels > max_levels)
436 rb->splash(HZ, "Too many levels in file");
437 break;
439 continue;
442 rb->memcpy(level_cache[num_levels][linecnt], buf, WIDTH);
443 linecnt++;
444 if(linecnt == HEIGHT)
446 linecnt = 0;
450 rb->close(fd);
451 return 0;
455 ** Completely clear the board of walls and/or snake
458 void clear_board( void)
460 int x,y;
462 for (x = 0; x < WIDTH; x++)
464 for (y = 0; y < HEIGHT; y++)
466 board[x][y] = 0;
471 int load_level( int level_number )
473 int x,y;
474 clear_board();
475 for(y = 0;y < HEIGHT;y++)
477 for(x = 0;x < WIDTH;x++)
479 switch(level_cache[level_number][y][x])
481 case '|':
482 board[x][y] = NORTH;
483 break;
485 case '-':
486 board[x][y] = EAST;
487 break;
489 case '+':
490 board[x][y] = HEAD;
491 break;
495 return 1;
499 ** Gets the currently chosen direction from the first place
500 ** in the direction buffer. If there is something in the
501 ** next part of the buffer then that is moved to the first place
503 void get_direction( void )
505 /*if 1st place is empty*/
506 if(ardirectionbuffer[0] != -1)
508 /*return this direction*/
509 dir = ardirectionbuffer[0];
510 ardirectionbuffer[0]=-1;
511 /*now see if one needs moving:*/
512 if(ardirectionbuffer[1] != -1)
514 /*there's a move waiting to be done
515 so move it into the space:*/
516 ardirectionbuffer[0] = ardirectionbuffer[1];
517 ardirectionbuffer[1] = -1;
523 ** Sets the direction
525 void set_direction(int newdir)
527 if(ardirectionbuffer[0] != newdir)
529 /*if 1st place is empty*/
530 if(ardirectionbuffer[0] == -1)
532 /*use 1st space:*/
533 ardirectionbuffer[0] = newdir;
535 else
537 /*use 2nd space:*/
538 if(ardirectionbuffer[0] != newdir) ardirectionbuffer[1] = newdir;
541 if(frames < 0) ardirectionbuffer[0] = newdir;
545 void new_level(int level)
547 load_level(level);
549 ardirectionbuffer[0] = -1;
550 ardirectionbuffer[1] = -1;
551 dir = EAST;
552 headx = WIDTH/2;
553 heady = HEIGHT/2;
554 tailx = headx - 4;
555 taily = heady;
556 applecountdown = 0;
557 /*Create a small snake to start off with*/
558 board[headx][heady] = dir;
559 board[headx-1][heady] = dir;
560 board[headx-2][heady] = dir;
561 board[headx-3][heady] = dir;
562 board[headx-4][heady] = dir;
563 num_apples_to_got=0;
566 void init_snake(void)
568 num_apples_to_get=1;
569 if(game_type == 1)
570 level_from_file = 1;
571 game_b_level=1;
572 new_level(level_from_file);
575 #if (LCD_WIDTH >= 160) && (LCD_HEIGHT >= 128)
576 void draw_frame_bitmap(int header_type)
578 rb->lcd_bitmap(header_type==1? snake2_header1: snake2_header2, 0, 0,
579 BMPWIDTH_snake2_header, BMPHEIGHT_snake2_header);
580 rb->lcd_bitmap(snake2_left, 0, BMPHEIGHT_snake2_header,
581 BMPWIDTH_snake2_left, BMPHEIGHT_snake2_left);
582 rb->lcd_bitmap(snake2_right,
583 LCD_WIDTH - BMPWIDTH_snake2_right, BMPHEIGHT_snake2_header,
584 BMPWIDTH_snake2_right, BMPHEIGHT_snake2_right);
585 rb->lcd_bitmap(snake2_bottom,
586 0, BMPHEIGHT_snake2_header + BMPHEIGHT_snake2_left,
587 BMPWIDTH_snake2_bottom, BMPHEIGHT_snake2_bottom);
589 #endif
592 ** Draws the apple. If it doesn't exist then
593 ** a new one get's created.
595 void draw_apple_bit(int x, int y)
597 rb->lcd_fillrect((CENTER_X+x*MULTIPLIER)+1, CENTER_Y+y*MULTIPLIER,
598 MODIFIER_2, MODIFIER_1);
599 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER, (CENTER_Y+y*MULTIPLIER)+1,
600 MODIFIER_1, MODIFIER_2);
603 void draw_apple( void )
605 int x,y;
607 #if LCD_WIDTH >= 160 && LCD_HEIGHT >= 128
608 draw_frame_bitmap(2);
610 rb->snprintf(strbuf, sizeof(strbuf), "%d", applecount);
611 rb->lcd_getstringsize(strbuf, &strwdt, &strhgt);
612 rb->lcd_putsxy(TOP_X3 - strwdt/2, TOP_Y2, strbuf);
614 rb->snprintf(strbuf, sizeof(strbuf), "%d", score);
615 rb->lcd_getstringsize(strbuf, &strwdt, &strhgt);
616 rb->lcd_putsxy(TOP_X4 - strwdt/2, TOP_Y2, strbuf);
617 #endif
619 if (!apple)
623 x = (rb->rand() % (WIDTH-1))+1;
624 y = (rb->rand() % (HEIGHT-1))+1;
625 } while (board[x][y]);
626 apple = 1;
627 board[x][y] = -1;
628 applex = x;appley = y;
630 draw_apple_bit(applex, appley);
634 * x x *
635 * x x *
636 * x x *
637 * x x *
639 void draw_vertical_bit(int x, int y)
641 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER+1, CENTER_Y+y*MULTIPLIER,
642 MODIFIER_2, MODIFIER_1);
646 * * * *
647 X X X X
648 X X X X
649 * * * *
651 void draw_horizontal_bit(int x, int y)
653 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER, CENTER_Y+y*MULTIPLIER+1,
654 MODIFIER_1, MODIFIER_2);
658 * * * *
659 * * X X
660 * X X X
661 * X X *
663 void draw_n_to_e_bit(int x, int y)
665 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER+1, CENTER_Y+y*MULTIPLIER+2,
666 MODIFIER_2, MODIFIER_2);
667 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER+2, CENTER_Y+y*MULTIPLIER+1,
668 MODIFIER_2, MODIFIER_2);
672 * * * *
673 * * X X
674 * X X X
675 * X X *
677 void draw_w_to_s_bit(int x, int y)
679 draw_n_to_e_bit(x,y);
683 * * * *
684 X X * *
685 X X X *
686 * X X *
688 void draw_n_to_w_bit(int x, int y)
690 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER, CENTER_Y+y*MULTIPLIER+1,
691 MODIFIER_2, MODIFIER_2);
692 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER+1, CENTER_Y+y*MULTIPLIER+2,
693 MODIFIER_2, MODIFIER_2);
697 * * * *
698 X X * *
699 X X X *
700 * X X *
702 void draw_e_to_s_bit(int x, int y)
704 draw_n_to_w_bit(x, y);
708 * X X *
709 * X X X
710 * * X X
711 * * * *
713 void draw_s_to_e_bit(int x, int y)
715 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER+1, CENTER_Y+y*MULTIPLIER,
716 MODIFIER_2, MODIFIER_2);
717 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER+2, CENTER_Y+y*MULTIPLIER+1,
718 MODIFIER_2, MODIFIER_2);
722 * X X *
723 * X X X
724 * * X X
725 * * * *
727 void draw_w_to_n_bit(int x, int y)
729 draw_s_to_e_bit(x,y);
733 * X X *
734 X X X *
735 X X * *
736 * * * *
738 void draw_e_to_n_bit(int x, int y)
740 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER+1, CENTER_Y+y*MULTIPLIER,
741 MODIFIER_2, MODIFIER_2);
742 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER, CENTER_Y+y*MULTIPLIER+1,
743 MODIFIER_2, MODIFIER_2);
747 * X X *
748 X X X *
749 X X * *
750 * * * *
752 void draw_s_to_w_bit(int x, int y)
754 draw_e_to_n_bit(x, y);
757 void draw_head_bit(int x, int y)
759 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER, CENTER_Y+y*MULTIPLIER,
760 MODIFIER_1, MODIFIER_1);
764 ** Draws a wall/obsticals
766 void draw_boundary ( void )
768 int x, y;
770 /*TODO: Load levels from file!*/
772 /*top and bottom line*/
773 for(x=0; x < WIDTH; x++)
775 board[x][0] = EAST;
776 board[x][HEIGHT-1] = WEST;
779 /*left and right lines*/
780 for(y=0; y < HEIGHT; y++)
782 board[0][y] = NORTH;
783 board[WIDTH-1][y] = SOUTH;
786 /*corners:*/
787 board[0][0] = NORTH_EAST;
788 board[WIDTH-1][0] = EAST_SOUTH;
789 board[0][HEIGHT-1] = SOUTH_EAST;
790 board[WIDTH-1][HEIGHT-1] = EAST_NORTH;
794 ** Redraw the entire board
796 void redraw (void)
798 int x,y;
800 #ifdef HAVE_LCD_COLOR
801 rb->lcd_set_foreground(LCD_BLACK);
802 rb->lcd_set_background(LCD_WHITE);
803 #endif
805 rb->lcd_clear_display();
807 for (x = 0; x < WIDTH; x++)
809 for (y = 0; y < HEIGHT; y++)
811 switch (board[x][y])
813 case -1:
814 draw_apple_bit(x, y);
815 break;
816 case 0:
817 break;
819 case NORTH:
820 case SOUTH:
821 draw_vertical_bit(x,y);
822 break;
824 case EAST:
825 case WEST:
826 draw_horizontal_bit(x,y);
827 break;
829 default:
830 draw_head_bit(x, y);
831 break;
836 #if LCD_WIDTH >= 160 && LCD_HEIGHT >= 128
837 draw_frame_bitmap(2);
839 rb->snprintf(strbuf, sizeof(strbuf), "%d", applecount);
840 rb->lcd_getstringsize(strbuf, &strwdt, &strhgt);
841 rb->lcd_putsxy(TOP_X3 - strwdt/2, TOP_Y2, strbuf);
843 rb->snprintf(strbuf, sizeof(strbuf), "%d", score);
844 rb->lcd_getstringsize(strbuf, &strwdt, &strhgt);
845 rb->lcd_putsxy(TOP_X4 - strwdt/2, TOP_Y2, strbuf);
846 #endif
850 ** Draws the snake bit described by nCurrentBit at position x/y
851 ** deciding whether it's a corner bit by examing the nPrevious bit
853 void draw_snake_bit(int currentbit, int previousbit, int x, int y)
855 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
856 draw_head_bit(x, y);
857 rb->lcd_set_drawmode(DRMODE_SOLID);
859 switch(currentbit)
861 case(NORTH):
862 switch(previousbit)
864 case(SOUTH):
865 case(NORTH):
866 draw_vertical_bit(x,y);
867 break;
869 case(EAST):
870 draw_e_to_n_bit(x,y);
871 break;
873 case(WEST):
874 draw_w_to_n_bit(x,y);
875 break;
877 break;
879 case(EAST):
880 switch(previousbit)
882 case(WEST):
883 case(EAST):
884 draw_horizontal_bit(x,y);
885 break;
887 case(NORTH):
888 draw_n_to_e_bit(x,y);
889 break;
891 case(SOUTH):
892 draw_s_to_e_bit(x,y);
893 break;
895 break;
897 case(SOUTH):
898 switch(previousbit)
900 case(SOUTH):
901 case(NORTH):
902 draw_vertical_bit(x,y);
903 break;
905 case(EAST):
906 draw_e_to_s_bit(x,y);
907 break;
909 case(WEST):
910 draw_w_to_s_bit(x,y);
911 break;
913 break;
915 case(WEST):
916 switch(previousbit)
918 case(EAST):
919 case(WEST):
920 draw_horizontal_bit(x,y);
921 break;
923 case(SOUTH):
924 draw_s_to_w_bit(x,y);
925 break;
927 case(NORTH):
928 draw_n_to_w_bit(x,y);
929 break;
931 break;
935 void redraw_snake(void)
937 int x = tailx, y = taily;
938 int olddir, newdir = board[x][y];
940 while (x != headx || y != heady)
942 olddir = newdir;
944 switch (olddir)
946 case(NORTH):
947 y--;
948 break;
950 case(EAST):
951 x++;
952 break;
954 case(SOUTH):
955 y++;
956 break;
958 case(WEST):
959 x--;
960 break;
963 if(x == WIDTH)
964 x = 0;
965 else if(x < 0)
966 x = WIDTH-1;
968 if(y == HEIGHT)
969 y = 0;
970 else if(y < 0)
971 y = HEIGHT-1;
973 newdir = board[x][y];
974 if(olddir != newdir)
975 draw_snake_bit(newdir, olddir, x, y);
980 ** Death 'sequence' and end game stuff.
982 void die (void)
984 int button;
985 bool done=false;
987 rb->splash(HZ*2, "Oops!");
989 rb->lcd_clear_display();
991 applecount=0;
993 rb->lcd_getstringsize("You died!",&strwdt,&strhgt);
994 rb->lcd_putsxy((LCD_WIDTH - strwdt)/2,strhgt,"You died!");
996 rb->snprintf(strbuf, sizeof(strbuf), "Your score: %d", score);
997 rb->lcd_getstringsize(strbuf, &strwdt, &strhgt);
998 rb->lcd_putsxy((LCD_WIDTH - strwdt)/2, strhgt * 2 + 2, strbuf);
1000 if (highscore_update(score, level_from_file, game_type==0?"Type A":"Type B",
1001 highscores, NUM_SCORES) == 0)
1003 rb->lcd_getstringsize("New high score!",&strwdt,&strhgt);
1004 rb->lcd_putsxy((LCD_WIDTH - strwdt)/2,strhgt * 4 + 2,"New high score!");
1006 else
1008 rb->snprintf(strbuf, sizeof(strbuf), "High score: %d", highscores[0].score);
1009 rb->lcd_getstringsize(strbuf, &strwdt, &strhgt);
1010 rb->lcd_putsxy((LCD_WIDTH - strwdt)/2, strhgt * 5, strbuf);
1013 rb->snprintf(strbuf, sizeof(strbuf), "Press %s...", SNAKE2_PLAYPAUSE_TEXT);
1014 rb->lcd_getstringsize(strbuf, &strwdt, &strhgt);
1015 rb->lcd_putsxy((LCD_WIDTH - strwdt)/2, strhgt * 7, strbuf);
1017 rb->lcd_update();
1019 while(!done)
1021 button=rb->button_get(true);
1022 switch(button)
1024 case SNAKE2_PLAYPAUSE:
1025 done = true;
1026 break;
1030 dead=1;
1034 ** Check for collision. TODO: Currently this
1035 ** sets of the death sequence. What we want is it to only return a true/false
1036 ** depending on whether a collision occured.
1038 void collision ( int x, int y )
1040 int bdeath=0;
1043 switch (board[x][y])
1045 case 0:
1047 break;
1048 case -1:
1049 score = score + (1 * level);
1050 apple=0;
1051 applecountdown=2;
1052 applecount++;
1054 if(game_type==1)
1056 if(num_apples_to_get == num_apples_to_got)
1058 level_from_file++;
1059 if(level_from_file >= num_levels)
1061 level_from_file = 1;
1062 /*and increase the number of apples to pick up
1063 before level changes*/
1064 num_apples_to_get+=2;
1065 game_b_level++;
1067 rb->splash(HZ, "Level Completed!");
1068 new_level(level_from_file);
1069 redraw();
1070 rb->lcd_update();
1072 else
1073 num_apples_to_got++;
1075 break;
1076 default:
1077 bdeath=1;
1078 break;
1081 if(bdeath==1)
1083 die();
1084 sillydir = dir;
1085 frames = -110;
1089 void move( void )
1091 int taildir;
1092 /*this actually sets the dir variable.*/
1093 get_direction();
1094 /*draw head*/
1095 switch (dir)
1097 case (NORTH):
1098 board[headx][heady]=NORTH;
1099 heady--;
1100 break;
1101 case (EAST):
1102 board[headx][heady]=EAST;
1103 headx++;
1104 break;
1105 case (SOUTH):
1106 board[headx][heady]=SOUTH;
1107 heady++;
1108 break;
1109 case (WEST):
1110 board[headx][heady]=WEST;
1111 headx--;
1112 break;
1115 if(headx == WIDTH)
1116 headx = 0;
1117 else if(headx < 0)
1118 headx = WIDTH-1;
1120 if(heady == HEIGHT)
1121 heady = 0;
1122 else if(heady < 0)
1123 heady = HEIGHT-1;
1125 draw_head_bit(headx, heady);
1127 /*clear tail*/
1128 if(applecountdown <= 0)
1130 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
1131 draw_head_bit(tailx, taily);
1132 rb->lcd_set_drawmode(DRMODE_SOLID);
1134 taildir = board[tailx][taily];
1135 board[tailx][taily] = 0;
1137 switch (taildir)
1139 case(NORTH):
1140 taily--;
1141 break;
1143 case(EAST):
1144 tailx++;
1145 break;
1147 case(SOUTH):
1148 taily++;
1149 break;
1151 case(WEST):
1152 tailx--;
1153 break;
1156 if(tailx == WIDTH)
1157 tailx = 0;
1158 else if(tailx < 0)
1159 tailx = WIDTH-1;
1161 if(taily == HEIGHT)
1162 taily = 0;
1163 else if(taily < 0)
1164 taily = HEIGHT-1;
1166 else
1167 applecountdown--;
1170 void frame (void)
1172 int olddir, noldx, noldy, temp;
1173 noldx = headx;
1174 noldy = heady;
1175 olddir = 0;
1176 switch(dir)
1178 case(NORTH):
1179 if(heady == HEIGHT-1)
1180 temp = 0;
1181 else
1182 temp = heady + 1;
1184 olddir = board[headx][temp];
1185 break;
1187 case(EAST):
1188 if(headx == 0)
1189 temp = WIDTH-1;
1190 else
1191 temp = headx - 1;
1193 olddir = board[temp][heady];
1194 break;
1196 case(SOUTH):
1197 if(heady == 0)
1198 temp = HEIGHT-1;
1199 else
1200 temp = heady - 1;
1202 olddir = board[headx][temp];
1203 break;
1205 case(WEST):
1206 if(headx == WIDTH-1)
1207 temp = 0;
1208 else
1209 temp = headx + 1;
1211 olddir = board[temp][heady];
1212 break;
1215 move();
1218 now redraw the bit that was
1219 the tail, to something snake-like:
1221 draw_snake_bit(dir, olddir, noldx, noldy);
1223 collision(headx, heady);
1225 rb->lcd_update();
1228 void game_pause (void)
1230 int button;
1232 rb->lcd_clear_display();
1233 rb->lcd_getstringsize("Paused",&strwdt,&strhgt);
1234 rb->lcd_putsxy((LCD_WIDTH - strwdt)/2,LCD_HEIGHT/2,"Paused");
1236 rb->lcd_update();
1237 while (1)
1239 button = rb->button_get(true);
1240 switch (button)
1242 case SNAKE2_PLAYPAUSE:
1243 redraw();
1244 redraw_snake();
1245 draw_head_bit(headx, heady);
1246 rb->lcd_update();
1247 rb->sleep(HZ/2);
1248 return;
1250 #ifdef SNAKE2_RC_QUIT
1251 case SNAKE2_RC_QUIT:
1252 #endif
1253 case SNAKE2_QUIT:
1254 dead = 1;
1255 quit = 1;
1256 return;
1258 default:
1259 if (rb->default_event_handler(button)==SYS_USB_CONNECTED) {
1260 dead = 1;
1261 quit = 2;
1262 return;
1264 break;
1269 void game (void)
1271 int button;
1273 redraw();
1274 rb->lcd_update();
1275 /*main loop:*/
1276 while (1)
1278 if(frames==5)
1280 frame();
1281 if(frames > 0) frames = 0;
1283 frames++;
1285 if(frames == 0)
1287 die();
1289 else
1291 if(frames < 0)
1293 if(sillydir != dir)
1295 /*it has, great set frames to a positive value again:*/
1296 frames = 1;
1301 if (dead) return;
1303 draw_apple();
1305 rb->sleep(HZ/speed);
1307 button = rb->button_get(false);
1309 #ifdef HAS_BUTTON_HOLD
1310 if (rb->button_hold())
1311 button = SNAKE2_PLAYPAUSE;
1312 #endif
1314 switch (button)
1316 case SNAKE2_UP:
1317 case SNAKE2_UP | BUTTON_REPEAT:
1318 if (dir != SOUTH) set_direction(NORTH);
1319 break;
1321 case SNAKE2_RIGHT:
1322 case SNAKE2_RIGHT | BUTTON_REPEAT:
1323 if (dir != WEST) set_direction(EAST);
1324 break;
1326 case SNAKE2_DOWN:
1327 case SNAKE2_DOWN | BUTTON_REPEAT:
1328 if (dir != NORTH) set_direction(SOUTH);
1329 break;
1331 case SNAKE2_LEFT:
1332 case SNAKE2_LEFT | BUTTON_REPEAT:
1333 if (dir != EAST) set_direction(WEST);
1334 break;
1336 #ifdef SNAKE2_RC_QUIT
1337 case SNAKE2_RC_QUIT:
1338 #endif
1339 case SNAKE2_QUIT:
1340 quit = 1;
1341 return;
1343 case SNAKE2_PLAYPAUSE:
1344 game_pause();
1345 break;
1347 default:
1348 if (rb->default_event_handler(button)==SYS_USB_CONNECTED) {
1349 quit = 2;
1350 return;
1352 break;
1358 void select_maze(void)
1360 int button;
1362 clear_board();
1363 load_level( level_from_file );
1364 redraw();
1365 rb->lcd_update();
1367 while (1)
1369 #if LCD_WIDTH >= 160 && LCD_HEIGHT >= 128
1370 draw_frame_bitmap(1);
1372 rb->snprintf(strbuf, sizeof(strbuf), "%d", level);
1373 rb->lcd_getstringsize(strbuf, &strwdt, &strhgt);
1374 rb->lcd_putsxy(TOP_X3 - strwdt/2, TOP_Y2, strbuf);
1376 rb->snprintf(strbuf, sizeof(strbuf), "%d", level_from_file);
1377 rb->lcd_getstringsize(strbuf, &strwdt, &strhgt);
1378 rb->lcd_putsxy(TOP_X2 - strwdt/2, TOP_Y1, strbuf);
1380 rb->strcpy(strbuf, game_type==0? "A": "B");
1381 rb->lcd_getstringsize(strbuf, &strwdt, &strhgt);
1382 rb->lcd_putsxy(TOP_X1, TOP_Y1, strbuf);
1384 rb->snprintf(strbuf, sizeof(strbuf), "%d", highscores[0].score);
1385 rb->lcd_getstringsize(strbuf, &strwdt, &strhgt);
1386 rb->lcd_putsxy(TOP_X4 - strwdt/2, TOP_Y2, strbuf);
1388 #else
1389 rb->snprintf(strbuf, sizeof(strbuf), "Maze: %d", level_from_file);
1390 rb->lcd_getstringsize(strbuf, &strwdt, &strhgt);
1391 rb->lcd_putsxy((WIDTH*MULTIPLIER - strwdt)/2,
1392 (HEIGHT*MULTIPLIER - strhgt)/2, strbuf);
1393 #endif
1395 rb->lcd_update();
1397 button = rb->button_get(true);
1398 switch (button)
1400 case SNAKE2_QUIT:
1401 case SNAKE2_PLAYPAUSE:
1402 return;
1403 break;
1404 case SNAKE2_UP:
1405 case SNAKE2_RIGHT:
1406 if(level_from_file < num_levels)
1407 level_from_file++;
1408 else
1409 level_from_file = 0;
1410 load_level( level_from_file );
1411 redraw();
1412 break;
1413 case SNAKE2_DOWN:
1414 case SNAKE2_LEFT:
1415 if(level_from_file > 0)
1416 level_from_file--;
1417 else
1418 level_from_file = num_levels;
1419 load_level( level_from_file );
1420 redraw();
1421 break;
1422 default:
1423 if (rb->default_event_handler(button)==SYS_USB_CONNECTED) {
1424 quit = 2;
1425 return;
1427 break;
1433 void game_init(void)
1435 int selection = 0;
1437 static const struct opt_items type_options[] = {
1438 { "Type A", -1 },
1439 { "Type B", -1 },
1442 MENUITEM_STRINGLIST(menu, "Snake2 Menu", NULL,
1443 "Start New Game",
1444 "Game Type", "Select Maze", "Speed",
1445 "High Scores",
1446 "Playback Control", "Quit");
1448 rb->button_clear_queue();
1450 dead = 0;
1451 apple = 0;
1452 score = 0;
1453 applecount = 0;
1455 while (1) {
1456 switch (rb->do_menu(&menu, &selection, NULL, false)) {
1457 case 0:
1458 speed = level*20;
1459 return;
1460 case 1:
1461 rb->set_option("Game Type", &game_type, INT,
1462 type_options, 2, NULL);
1463 break;
1464 case 2:
1465 select_maze();
1466 if(quit) return;
1467 break;
1468 case 3:
1469 rb->set_int("Speed", "", UNIT_INT, &level,
1470 NULL, 1, 1, 10, NULL);
1471 break;
1472 case 4:
1473 highscore_show(-1, highscores, NUM_SCORES, true);
1474 break;
1475 case 5:
1476 playback_control(NULL);
1477 break;
1478 case 6:
1479 quit = 1;
1480 return;
1481 case MENU_ATTACHED_USB:
1482 quit = 2;
1483 return;
1484 default:
1485 break;
1490 enum plugin_status plugin_start(const void* parameter)
1492 (void)(parameter);
1494 /* Lets use the default font */
1495 rb->lcd_setfont(FONT_SYSFIXED);
1496 #if LCD_DEPTH > 1
1497 rb->lcd_set_backdrop(NULL);
1498 #endif
1500 load_all_levels();
1502 if (num_levels == 0) {
1503 rb->splash(HZ*2, "Failed loading levels!");
1504 return PLUGIN_OK;
1507 highscore_load(SCORE_FILE, highscores, NUM_SCORES);
1509 while(quit==0)
1511 game_init();
1512 if(quit)
1513 break;
1515 rb->lcd_clear_display();
1516 frames=1;
1518 init_snake();
1520 /*Start Game:*/
1521 game();
1524 highscore_save(SCORE_FILE, highscores, NUM_SCORES);
1526 return (quit==1) ? PLUGIN_OK : PLUGIN_USB_CONNECTED;
1529 #endif