fix red
[kugel-rb.git] / apps / plugins / snake2.c
blobd858976a3191a8d15234ebbb904c4d4a8dae020f
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|BUTTON_REPEAT
229 #define SNAKE2_PLAYPAUSE_TEXT "Hold 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 == COWOND2_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 == ONDAVX747_PAD) || CONFIG_KEYPAD == MROBE500_PAD
289 #define SNAKE2_QUIT BUTTON_POWER
291 #elif (CONFIG_KEYPAD == SAMSUNG_YH_PAD)
292 #define SNAKE2_LEFT BUTTON_LEFT
293 #define SNAKE2_RIGHT BUTTON_RIGHT
294 #define SNAKE2_UP BUTTON_UP
295 #define SNAKE2_DOWN BUTTON_DOWN
296 #define SNAKE2_QUIT BUTTON_REC
297 #define SNAKE2_PLAYPAUSE BUTTON_PLAY
298 #define SNAKE2_PLAYPAUSE_TEXT "Play"
300 #else
301 #error No keymap defined!
302 #endif
304 #ifdef HAVE_TOUCHSCREEN
305 #ifndef SNAKE2_LEFT
306 #define SNAKE2_LEFT BUTTON_MIDLEFT
307 #endif
308 #ifndef SNAKE2_RIGHT
309 #define SNAKE2_RIGHT BUTTON_MIDRIGHT
310 #endif
311 #ifndef SNAKE2_UP
312 #define SNAKE2_UP BUTTON_TOPMIDDLE
313 #endif
314 #ifndef SNAKE2_DOWN
315 #define SNAKE2_DOWN BUTTON_BOTTOMMIDDLE
316 #endif
317 #ifndef SNAKE2_QUIT
318 #define SNAKE2_QUIT BUTTON_TOPLEFT
319 #endif
320 #ifndef SNAKE2_PLAYPAUSE
321 #define SNAKE2_PLAYPAUSE BUTTON_CENTER
322 #endif
323 #ifndef SNAKE2_PLAYPAUSE_TEXT
324 #define SNAKE2_PLAYPAUSE_TEXT "CENTER"
325 #endif
326 #endif
328 static int max_levels = 0;
329 static char (*level_cache)[HEIGHT][WIDTH];
331 /*Board itself - 2D int array*/
332 static int board[WIDTH][HEIGHT];
334 Buffer for sorting movement (in case user presses two movements during a
335 single frame
337 static int ardirectionbuffer[2];
338 static int score;
339 static int applex;
340 static int appley;
341 static int dir;
342 static int frames;
343 static int apple;
344 static int level = 4, speed = 5,dead = 0, quit = 0;
345 static int sillydir = 0, num_levels = 0;
346 static int level_from_file = 0;
347 static int headx, heady, tailx, taily, applecountdown = 5;
348 static int game_type = 0;
349 static int num_apples_to_get=1;
350 static int num_apples_to_got=0;
351 static int game_b_level=0;
352 static int applecount=0;
353 /* used for string width, height for orientation purposes */
354 static int strwdt, strhgt;
355 static char strbuf[32];
357 #define NUM_SCORES 5
358 static struct highscore highscores[NUM_SCORES];
360 #define NORTH 1
361 #define EAST 2
362 #define SOUTH 4
363 #define WEST 8
364 #define HEAD 16
366 #define EAST_NORTH 32
367 #define EAST_SOUTH 64
368 #define WEST_NORTH 128
369 #define WEST_SOUTH 256
371 #define NORTH_EAST 512
372 #define NORTH_WEST 1024
373 #define SOUTH_EAST 2048
374 #define SOUTH_WEST 4096
376 #define LEVELS_FILE PLUGIN_GAMES_DIR "/snake2.levels"
377 #define SCORE_FILE PLUGIN_GAMES_DIR "/snake2.score"
379 int load_all_levels(void)
381 int linecnt = 0;
382 int fd;
383 ssize_t size;
384 char buf[64]; /* Larger than WIDTH, to allow for whitespace after the
385 lines */
387 /* Init the level_cache pointer and
388 calculate how many levels that will fit */
389 level_cache = rb->plugin_get_buffer((size_t *)&size);
390 max_levels = size / (HEIGHT*WIDTH);
392 num_levels = 0;
394 /* open file */
395 if ((fd = rb->open(LEVELS_FILE, O_RDONLY)) < 0)
397 return -1;
400 while(rb->read_line(fd, buf, 64) > 0)
402 if(rb->strlen(buf) == 0) /* Separator? */
404 num_levels++;
405 if(num_levels > max_levels)
407 rb->splash(HZ, "Too many levels in file");
408 break;
410 continue;
413 rb->memcpy(level_cache[num_levels][linecnt], buf, WIDTH);
414 linecnt++;
415 if(linecnt == HEIGHT)
417 linecnt = 0;
421 rb->close(fd);
422 return 0;
426 ** Completely clear the board of walls and/or snake
429 void clear_board( void)
431 int x,y;
433 for (x = 0; x < WIDTH; x++)
435 for (y = 0; y < HEIGHT; y++)
437 board[x][y] = 0;
442 int load_level( int level_number )
444 int x,y;
445 clear_board();
446 for(y = 0;y < HEIGHT;y++)
448 for(x = 0;x < WIDTH;x++)
450 switch(level_cache[level_number][y][x])
452 case '|':
453 board[x][y] = NORTH;
454 break;
456 case '-':
457 board[x][y] = EAST;
458 break;
460 case '+':
461 board[x][y] = HEAD;
462 break;
466 return 1;
470 ** Gets the currently chosen direction from the first place
471 ** in the direction buffer. If there is something in the
472 ** next part of the buffer then that is moved to the first place
474 void get_direction( void )
476 /*if 1st place is empty*/
477 if(ardirectionbuffer[0] != -1)
479 /*return this direction*/
480 dir = ardirectionbuffer[0];
481 ardirectionbuffer[0]=-1;
482 /*now see if one needs moving:*/
483 if(ardirectionbuffer[1] != -1)
485 /*there's a move waiting to be done
486 so move it into the space:*/
487 ardirectionbuffer[0] = ardirectionbuffer[1];
488 ardirectionbuffer[1] = -1;
494 ** Sets the direction
496 void set_direction(int newdir)
498 if(ardirectionbuffer[0] != newdir)
500 /*if 1st place is empty*/
501 if(ardirectionbuffer[0] == -1)
503 /*use 1st space:*/
504 ardirectionbuffer[0] = newdir;
506 else
508 /*use 2nd space:*/
509 if(ardirectionbuffer[0] != newdir) ardirectionbuffer[1] = newdir;
512 if(frames < 0) ardirectionbuffer[0] = newdir;
516 void new_level(int level)
518 load_level(level);
520 ardirectionbuffer[0] = -1;
521 ardirectionbuffer[1] = -1;
522 dir = EAST;
523 headx = WIDTH/2;
524 heady = HEIGHT/2;
525 tailx = headx - 4;
526 taily = heady;
527 applecountdown = 0;
528 /*Create a small snake to start off with*/
529 board[headx][heady] = dir;
530 board[headx-1][heady] = dir;
531 board[headx-2][heady] = dir;
532 board[headx-3][heady] = dir;
533 board[headx-4][heady] = dir;
534 num_apples_to_got=0;
537 void init_snake(void)
539 num_apples_to_get=1;
540 if(game_type == 1)
541 level_from_file = 1;
542 game_b_level=1;
543 new_level(level_from_file);
546 #if (LCD_WIDTH >= 160) && (LCD_HEIGHT >= 128)
547 void draw_frame_bitmap(int header_type)
549 rb->lcd_bitmap(header_type==1? snake2_header1: snake2_header2, 0, 0,
550 BMPWIDTH_snake2_header, BMPHEIGHT_snake2_header);
551 rb->lcd_bitmap(snake2_left, 0, BMPHEIGHT_snake2_header,
552 BMPWIDTH_snake2_left, BMPHEIGHT_snake2_left);
553 rb->lcd_bitmap(snake2_right,
554 LCD_WIDTH - BMPWIDTH_snake2_right, BMPHEIGHT_snake2_header,
555 BMPWIDTH_snake2_right, BMPHEIGHT_snake2_right);
556 rb->lcd_bitmap(snake2_bottom,
557 0, BMPHEIGHT_snake2_header + BMPHEIGHT_snake2_left,
558 BMPWIDTH_snake2_bottom, BMPHEIGHT_snake2_bottom);
560 #endif
563 ** Draws the apple. If it doesn't exist then
564 ** a new one get's created.
566 void draw_apple_bit(int x, int y)
568 rb->lcd_fillrect((CENTER_X+x*MULTIPLIER)+1, CENTER_Y+y*MULTIPLIER,
569 MODIFIER_2, MODIFIER_1);
570 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER, (CENTER_Y+y*MULTIPLIER)+1,
571 MODIFIER_1, MODIFIER_2);
574 void draw_apple( void )
576 int x,y;
578 #if LCD_WIDTH >= 160 && LCD_HEIGHT >= 128
579 draw_frame_bitmap(2);
581 rb->snprintf(strbuf, sizeof(strbuf), "%d", applecount);
582 rb->lcd_getstringsize(strbuf, &strwdt, &strhgt);
583 rb->lcd_putsxy(TOP_X3 - strwdt/2, TOP_Y2, strbuf);
585 rb->snprintf(strbuf, sizeof(strbuf), "%d", score);
586 rb->lcd_getstringsize(strbuf, &strwdt, &strhgt);
587 rb->lcd_putsxy(TOP_X4 - strwdt/2, TOP_Y2, strbuf);
588 #endif
590 if (!apple)
594 x = (rb->rand() % (WIDTH-1))+1;
595 y = (rb->rand() % (HEIGHT-1))+1;
596 } while (board[x][y]);
597 apple = 1;
598 board[x][y] = -1;
599 applex = x;appley = y;
601 draw_apple_bit(applex, appley);
605 * x x *
606 * x x *
607 * x x *
608 * x x *
610 void draw_vertical_bit(int x, int y)
612 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER+1, CENTER_Y+y*MULTIPLIER,
613 MODIFIER_2, MODIFIER_1);
617 * * * *
618 X X X X
619 X X X X
620 * * * *
622 void draw_horizontal_bit(int x, int y)
624 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER, CENTER_Y+y*MULTIPLIER+1,
625 MODIFIER_1, MODIFIER_2);
629 * * * *
630 * * X X
631 * X X X
632 * X X *
634 void draw_n_to_e_bit(int x, int y)
636 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER+1, CENTER_Y+y*MULTIPLIER+2,
637 MODIFIER_2, MODIFIER_2);
638 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER+2, CENTER_Y+y*MULTIPLIER+1,
639 MODIFIER_2, MODIFIER_2);
643 * * * *
644 * * X X
645 * X X X
646 * X X *
648 void draw_w_to_s_bit(int x, int y)
650 draw_n_to_e_bit(x,y);
654 * * * *
655 X X * *
656 X X X *
657 * X X *
659 void draw_n_to_w_bit(int x, int y)
661 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER, CENTER_Y+y*MULTIPLIER+1,
662 MODIFIER_2, MODIFIER_2);
663 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER+1, CENTER_Y+y*MULTIPLIER+2,
664 MODIFIER_2, MODIFIER_2);
668 * * * *
669 X X * *
670 X X X *
671 * X X *
673 void draw_e_to_s_bit(int x, int y)
675 draw_n_to_w_bit(x, y);
679 * X X *
680 * X X X
681 * * X X
682 * * * *
684 void draw_s_to_e_bit(int x, int y)
686 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER+1, CENTER_Y+y*MULTIPLIER,
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 * X X *
694 * X X X
695 * * X X
696 * * * *
698 void draw_w_to_n_bit(int x, int y)
700 draw_s_to_e_bit(x,y);
704 * X X *
705 X X X *
706 X X * *
707 * * * *
709 void draw_e_to_n_bit(int x, int y)
711 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER+1, CENTER_Y+y*MULTIPLIER,
712 MODIFIER_2, MODIFIER_2);
713 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER, CENTER_Y+y*MULTIPLIER+1,
714 MODIFIER_2, MODIFIER_2);
718 * X X *
719 X X X *
720 X X * *
721 * * * *
723 void draw_s_to_w_bit(int x, int y)
725 draw_e_to_n_bit(x, y);
728 void draw_head_bit(int x, int y)
730 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER, CENTER_Y+y*MULTIPLIER,
731 MODIFIER_1, MODIFIER_1);
735 ** Draws a wall/obsticals
737 void draw_boundary ( void )
739 int x, y;
741 /*TODO: Load levels from file!*/
743 /*top and bottom line*/
744 for(x=0; x < WIDTH; x++)
746 board[x][0] = EAST;
747 board[x][HEIGHT-1] = WEST;
750 /*left and right lines*/
751 for(y=0; y < HEIGHT; y++)
753 board[0][y] = NORTH;
754 board[WIDTH-1][y] = SOUTH;
757 /*corners:*/
758 board[0][0] = NORTH_EAST;
759 board[WIDTH-1][0] = EAST_SOUTH;
760 board[0][HEIGHT-1] = SOUTH_EAST;
761 board[WIDTH-1][HEIGHT-1] = EAST_NORTH;
765 ** Redraw the entire board
767 void redraw (void)
769 int x,y;
771 #ifdef HAVE_LCD_COLOR
772 rb->lcd_set_foreground(LCD_BLACK);
773 rb->lcd_set_background(LCD_WHITE);
774 #endif
776 rb->lcd_clear_display();
778 for (x = 0; x < WIDTH; x++)
780 for (y = 0; y < HEIGHT; y++)
782 switch (board[x][y])
784 case -1:
785 draw_apple_bit(x, y);
786 break;
787 case 0:
788 break;
790 case NORTH:
791 case SOUTH:
792 draw_vertical_bit(x,y);
793 break;
795 case EAST:
796 case WEST:
797 draw_horizontal_bit(x,y);
798 break;
800 default:
801 draw_head_bit(x, y);
802 break;
807 #if LCD_WIDTH >= 160 && LCD_HEIGHT >= 128
808 draw_frame_bitmap(2);
810 rb->snprintf(strbuf, sizeof(strbuf), "%d", applecount);
811 rb->lcd_getstringsize(strbuf, &strwdt, &strhgt);
812 rb->lcd_putsxy(TOP_X3 - strwdt/2, TOP_Y2, strbuf);
814 rb->snprintf(strbuf, sizeof(strbuf), "%d", score);
815 rb->lcd_getstringsize(strbuf, &strwdt, &strhgt);
816 rb->lcd_putsxy(TOP_X4 - strwdt/2, TOP_Y2, strbuf);
817 #endif
821 ** Draws the snake bit described by nCurrentBit at position x/y
822 ** deciding whether it's a corner bit by examing the nPrevious bit
824 void draw_snake_bit(int currentbit, int previousbit, int x, int y)
826 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
827 draw_head_bit(x, y);
828 rb->lcd_set_drawmode(DRMODE_SOLID);
830 switch(currentbit)
832 case(NORTH):
833 switch(previousbit)
835 case(SOUTH):
836 case(NORTH):
837 draw_vertical_bit(x,y);
838 break;
840 case(EAST):
841 draw_e_to_n_bit(x,y);
842 break;
844 case(WEST):
845 draw_w_to_n_bit(x,y);
846 break;
848 break;
850 case(EAST):
851 switch(previousbit)
853 case(WEST):
854 case(EAST):
855 draw_horizontal_bit(x,y);
856 break;
858 case(NORTH):
859 draw_n_to_e_bit(x,y);
860 break;
862 case(SOUTH):
863 draw_s_to_e_bit(x,y);
864 break;
866 break;
868 case(SOUTH):
869 switch(previousbit)
871 case(SOUTH):
872 case(NORTH):
873 draw_vertical_bit(x,y);
874 break;
876 case(EAST):
877 draw_e_to_s_bit(x,y);
878 break;
880 case(WEST):
881 draw_w_to_s_bit(x,y);
882 break;
884 break;
886 case(WEST):
887 switch(previousbit)
889 case(EAST):
890 case(WEST):
891 draw_horizontal_bit(x,y);
892 break;
894 case(SOUTH):
895 draw_s_to_w_bit(x,y);
896 break;
898 case(NORTH):
899 draw_n_to_w_bit(x,y);
900 break;
902 break;
906 void redraw_snake(void)
908 int x = tailx, y = taily;
909 int olddir, newdir = board[x][y];
911 while (x != headx || y != heady)
913 olddir = newdir;
915 switch (olddir)
917 case(NORTH):
918 y--;
919 break;
921 case(EAST):
922 x++;
923 break;
925 case(SOUTH):
926 y++;
927 break;
929 case(WEST):
930 x--;
931 break;
934 if(x == WIDTH)
935 x = 0;
936 else if(x < 0)
937 x = WIDTH-1;
939 if(y == HEIGHT)
940 y = 0;
941 else if(y < 0)
942 y = HEIGHT-1;
944 newdir = board[x][y];
945 if(olddir != newdir)
946 draw_snake_bit(newdir, olddir, x, y);
951 ** Death 'sequence' and end game stuff.
953 void die (void)
955 int button;
956 bool done=false;
958 rb->splash(HZ*2, "Oops!");
960 rb->lcd_clear_display();
962 applecount=0;
964 rb->lcd_getstringsize("You died!",&strwdt,&strhgt);
965 rb->lcd_putsxy((LCD_WIDTH - strwdt)/2,strhgt,"You died!");
967 rb->snprintf(strbuf, sizeof(strbuf), "Your score: %d", score);
968 rb->lcd_getstringsize(strbuf, &strwdt, &strhgt);
969 rb->lcd_putsxy((LCD_WIDTH - strwdt)/2, strhgt * 2 + 2, strbuf);
971 if (highscore_update(score, level_from_file, game_type==0?"Type A":"Type B",
972 highscores, NUM_SCORES) == 0)
974 rb->lcd_getstringsize("New high score!",&strwdt,&strhgt);
975 rb->lcd_putsxy((LCD_WIDTH - strwdt)/2,strhgt * 4 + 2,"New high score!");
977 else
979 rb->snprintf(strbuf, sizeof(strbuf), "High score: %d", highscores[0].score);
980 rb->lcd_getstringsize(strbuf, &strwdt, &strhgt);
981 rb->lcd_putsxy((LCD_WIDTH - strwdt)/2, strhgt * 5, strbuf);
984 rb->snprintf(strbuf, sizeof(strbuf), "Press %s...", SNAKE2_PLAYPAUSE_TEXT);
985 rb->lcd_getstringsize(strbuf, &strwdt, &strhgt);
986 rb->lcd_putsxy((LCD_WIDTH - strwdt)/2, strhgt * 7, strbuf);
988 rb->lcd_update();
990 while(!done)
992 button=rb->button_get(true);
993 switch(button)
995 case SNAKE2_PLAYPAUSE:
996 done = true;
997 break;
1001 dead=1;
1005 ** Check for collision. TODO: Currently this
1006 ** sets of the death sequence. What we want is it to only return a true/false
1007 ** depending on whether a collision occured.
1009 void collision ( int x, int y )
1011 int bdeath=0;
1014 switch (board[x][y])
1016 case 0:
1018 break;
1019 case -1:
1020 score = score + (1 * level);
1021 apple=0;
1022 applecountdown=2;
1023 applecount++;
1025 if(game_type==1)
1027 if(num_apples_to_get == num_apples_to_got)
1029 level_from_file++;
1030 if(level_from_file >= num_levels)
1032 level_from_file = 1;
1033 /*and increase the number of apples to pick up
1034 before level changes*/
1035 num_apples_to_get+=2;
1036 game_b_level++;
1038 rb->splash(HZ, "Level Completed!");
1039 new_level(level_from_file);
1040 redraw();
1041 rb->lcd_update();
1043 else
1044 num_apples_to_got++;
1046 break;
1047 default:
1048 bdeath=1;
1049 break;
1052 if(bdeath==1)
1054 die();
1055 sillydir = dir;
1056 frames = -110;
1060 void move( void )
1062 int taildir;
1063 /*this actually sets the dir variable.*/
1064 get_direction();
1065 /*draw head*/
1066 switch (dir)
1068 case (NORTH):
1069 board[headx][heady]=NORTH;
1070 heady--;
1071 break;
1072 case (EAST):
1073 board[headx][heady]=EAST;
1074 headx++;
1075 break;
1076 case (SOUTH):
1077 board[headx][heady]=SOUTH;
1078 heady++;
1079 break;
1080 case (WEST):
1081 board[headx][heady]=WEST;
1082 headx--;
1083 break;
1086 if(headx == WIDTH)
1087 headx = 0;
1088 else if(headx < 0)
1089 headx = WIDTH-1;
1091 if(heady == HEIGHT)
1092 heady = 0;
1093 else if(heady < 0)
1094 heady = HEIGHT-1;
1096 draw_head_bit(headx, heady);
1098 /*clear tail*/
1099 if(applecountdown <= 0)
1101 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
1102 draw_head_bit(tailx, taily);
1103 rb->lcd_set_drawmode(DRMODE_SOLID);
1105 taildir = board[tailx][taily];
1106 board[tailx][taily] = 0;
1108 switch (taildir)
1110 case(NORTH):
1111 taily--;
1112 break;
1114 case(EAST):
1115 tailx++;
1116 break;
1118 case(SOUTH):
1119 taily++;
1120 break;
1122 case(WEST):
1123 tailx--;
1124 break;
1127 if(tailx == WIDTH)
1128 tailx = 0;
1129 else if(tailx < 0)
1130 tailx = WIDTH-1;
1132 if(taily == HEIGHT)
1133 taily = 0;
1134 else if(taily < 0)
1135 taily = HEIGHT-1;
1137 else
1138 applecountdown--;
1141 void frame (void)
1143 int olddir, noldx, noldy, temp;
1144 noldx = headx;
1145 noldy = heady;
1146 olddir = 0;
1147 switch(dir)
1149 case(NORTH):
1150 if(heady == HEIGHT-1)
1151 temp = 0;
1152 else
1153 temp = heady + 1;
1155 olddir = board[headx][temp];
1156 break;
1158 case(EAST):
1159 if(headx == 0)
1160 temp = WIDTH-1;
1161 else
1162 temp = headx - 1;
1164 olddir = board[temp][heady];
1165 break;
1167 case(SOUTH):
1168 if(heady == 0)
1169 temp = HEIGHT-1;
1170 else
1171 temp = heady - 1;
1173 olddir = board[headx][temp];
1174 break;
1176 case(WEST):
1177 if(headx == WIDTH-1)
1178 temp = 0;
1179 else
1180 temp = headx + 1;
1182 olddir = board[temp][heady];
1183 break;
1186 move();
1189 now redraw the bit that was
1190 the tail, to something snake-like:
1192 draw_snake_bit(dir, olddir, noldx, noldy);
1194 collision(headx, heady);
1196 rb->lcd_update();
1199 void game_pause (void)
1201 int button;
1203 rb->lcd_clear_display();
1204 rb->lcd_getstringsize("Paused",&strwdt,&strhgt);
1205 rb->lcd_putsxy((LCD_WIDTH - strwdt)/2,LCD_HEIGHT/2,"Paused");
1207 rb->lcd_update();
1208 while (1)
1210 button = rb->button_get(true);
1211 switch (button)
1213 case SNAKE2_PLAYPAUSE:
1214 redraw();
1215 redraw_snake();
1216 draw_head_bit(headx, heady);
1217 rb->lcd_update();
1218 rb->sleep(HZ/2);
1219 return;
1221 #ifdef SNAKE2_RC_QUIT
1222 case SNAKE2_RC_QUIT:
1223 #endif
1224 case SNAKE2_QUIT:
1225 dead = 1;
1226 quit = 1;
1227 return;
1229 default:
1230 if (rb->default_event_handler(button)==SYS_USB_CONNECTED) {
1231 dead = 1;
1232 quit = 2;
1233 return;
1235 break;
1240 void game (void)
1242 int button;
1244 redraw();
1245 rb->lcd_update();
1246 /*main loop:*/
1247 while (1)
1249 if(frames==5)
1251 frame();
1252 if(frames > 0) frames = 0;
1254 frames++;
1256 if(frames == 0)
1258 die();
1260 else
1262 if(frames < 0)
1264 if(sillydir != dir)
1266 /*it has, great set frames to a positive value again:*/
1267 frames = 1;
1272 if (dead) return;
1274 draw_apple();
1276 rb->sleep(HZ/speed);
1278 button = rb->button_get(false);
1280 #ifdef HAS_BUTTON_HOLD
1281 if (rb->button_hold())
1282 button = SNAKE2_PLAYPAUSE;
1283 #endif
1285 switch (button)
1287 case SNAKE2_UP:
1288 case SNAKE2_UP | BUTTON_REPEAT:
1289 if (dir != SOUTH) set_direction(NORTH);
1290 break;
1292 case SNAKE2_RIGHT:
1293 case SNAKE2_RIGHT | BUTTON_REPEAT:
1294 if (dir != WEST) set_direction(EAST);
1295 break;
1297 case SNAKE2_DOWN:
1298 case SNAKE2_DOWN | BUTTON_REPEAT:
1299 if (dir != NORTH) set_direction(SOUTH);
1300 break;
1302 case SNAKE2_LEFT:
1303 case SNAKE2_LEFT | BUTTON_REPEAT:
1304 if (dir != EAST) set_direction(WEST);
1305 break;
1307 #ifdef SNAKE2_RC_QUIT
1308 case SNAKE2_RC_QUIT:
1309 #endif
1310 case SNAKE2_QUIT:
1311 quit = 1;
1312 return;
1314 case SNAKE2_PLAYPAUSE:
1315 game_pause();
1316 break;
1318 default:
1319 if (rb->default_event_handler(button)==SYS_USB_CONNECTED) {
1320 quit = 2;
1321 return;
1323 break;
1329 void select_maze(void)
1331 int button;
1333 clear_board();
1334 load_level( level_from_file );
1335 redraw();
1336 rb->lcd_update();
1338 while (1)
1340 #if LCD_WIDTH >= 160 && LCD_HEIGHT >= 128
1341 draw_frame_bitmap(1);
1343 rb->snprintf(strbuf, sizeof(strbuf), "%d", level);
1344 rb->lcd_getstringsize(strbuf, &strwdt, &strhgt);
1345 rb->lcd_putsxy(TOP_X3 - strwdt/2, TOP_Y2, strbuf);
1347 rb->snprintf(strbuf, sizeof(strbuf), "%d", level_from_file);
1348 rb->lcd_getstringsize(strbuf, &strwdt, &strhgt);
1349 rb->lcd_putsxy(TOP_X2 - strwdt/2, TOP_Y1, strbuf);
1351 rb->strcpy(strbuf, game_type==0? "A": "B");
1352 rb->lcd_getstringsize(strbuf, &strwdt, &strhgt);
1353 rb->lcd_putsxy(TOP_X1, TOP_Y1, strbuf);
1355 rb->snprintf(strbuf, sizeof(strbuf), "%d", highscores[0].score);
1356 rb->lcd_getstringsize(strbuf, &strwdt, &strhgt);
1357 rb->lcd_putsxy(TOP_X4 - strwdt/2, TOP_Y2, strbuf);
1359 #else
1360 rb->snprintf(strbuf, sizeof(strbuf), "Maze: %d", level_from_file);
1361 rb->lcd_getstringsize(strbuf, &strwdt, &strhgt);
1362 rb->lcd_putsxy((WIDTH*MULTIPLIER - strwdt)/2,
1363 (HEIGHT*MULTIPLIER - strhgt)/2, strbuf);
1364 #endif
1366 rb->lcd_update();
1368 button = rb->button_get(true);
1369 switch (button)
1371 case SNAKE2_QUIT:
1372 case SNAKE2_PLAYPAUSE:
1373 return;
1374 break;
1375 case SNAKE2_UP:
1376 case SNAKE2_RIGHT:
1377 if(level_from_file < num_levels)
1378 level_from_file++;
1379 else
1380 level_from_file = 0;
1381 load_level( level_from_file );
1382 redraw();
1383 break;
1384 case SNAKE2_DOWN:
1385 case SNAKE2_LEFT:
1386 if(level_from_file > 0)
1387 level_from_file--;
1388 else
1389 level_from_file = num_levels;
1390 load_level( level_from_file );
1391 redraw();
1392 break;
1393 default:
1394 if (rb->default_event_handler(button)==SYS_USB_CONNECTED) {
1395 quit = 2;
1396 return;
1398 break;
1404 void game_init(void)
1406 int selection = 0;
1408 static const struct opt_items type_options[] = {
1409 { "Type A", -1 },
1410 { "Type B", -1 },
1413 MENUITEM_STRINGLIST(menu, "Snake2 Menu", NULL,
1414 "Start New Game",
1415 "Game Type", "Select Maze", "Speed",
1416 "High Scores",
1417 "Playback Control", "Quit");
1419 rb->button_clear_queue();
1421 dead = 0;
1422 apple = 0;
1423 score = 0;
1424 applecount = 0;
1426 while (1) {
1427 switch (rb->do_menu(&menu, &selection, NULL, false)) {
1428 case 0:
1429 speed = level*20;
1430 return;
1431 case 1:
1432 rb->set_option("Game Type", &game_type, INT,
1433 type_options, 2, NULL);
1434 break;
1435 case 2:
1436 select_maze();
1437 if(quit) return;
1438 break;
1439 case 3:
1440 rb->set_int("Speed", "", UNIT_INT, &level,
1441 NULL, 1, 1, 10, NULL);
1442 break;
1443 case 4:
1444 highscore_show(NUM_SCORES, highscores, NUM_SCORES, true);
1445 break;
1446 case 5:
1447 playback_control(NULL);
1448 break;
1449 case 6:
1450 quit = 1;
1451 return;
1452 case MENU_ATTACHED_USB:
1453 quit = 2;
1454 return;
1455 default:
1456 break;
1461 enum plugin_status plugin_start(const void* parameter)
1463 (void)(parameter);
1465 /* Lets use the default font */
1466 rb->lcd_setfont(FONT_SYSFIXED);
1467 #if LCD_DEPTH > 1
1468 rb->lcd_set_backdrop(NULL);
1469 #endif
1471 load_all_levels();
1473 if (num_levels == 0) {
1474 rb->splash(HZ*2, "Failed loading levels!");
1475 return PLUGIN_OK;
1478 highscore_load(SCORE_FILE, highscores, NUM_SCORES);
1480 while(quit==0)
1482 game_init();
1483 if(quit)
1484 break;
1486 rb->lcd_clear_display();
1487 frames=1;
1489 init_snake();
1491 /*Start Game:*/
1492 game();
1495 highscore_save(SCORE_FILE, highscores, NUM_SCORES);
1497 return (quit==1) ? PLUGIN_OK : PLUGIN_USB_CONNECTED;
1500 #endif