1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
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 ****************************************************************************/
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
34 #include "lib/highscore.h"
35 #include "lib/playback_control.h"
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
52 #if (LCD_WIDTH >= 640) && (LCD_HEIGHT >= 480)
53 #define MULTIPLIER 20 /*Modifier for porting on other screens*/
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*/
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)
88 #elif (LCD_WIDTH >= 220) && (LCD_HEIGHT >= 176)
100 #elif (LCD_WIDTH >= 176) && (LCD_HEIGHT >= 132)
112 #elif (LCD_WIDTH >= 160) && (LCD_HEIGHT >= 128)
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_REW
334 #define SNAKE2_RIGHT BUTTON_FF
335 #define SNAKE2_UP BUTTON_UP
336 #define SNAKE2_DOWN BUTTON_DOWN
337 #define SNAKE2_QUIT (BUTTON_MENU|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 #elif (CONFIG_KEYPAD == HM60X_PAD) || \
351 (CONFIG_KEYPAD == HM801_PAD)
352 #define SNAKE2_LEFT BUTTON_LEFT
353 #define SNAKE2_RIGHT BUTTON_RIGHT
354 #define SNAKE2_UP BUTTON_UP
355 #define SNAKE2_DOWN BUTTON_DOWN
356 #define SNAKE2_QUIT BUTTON_POWER
357 #define SNAKE2_PLAYPAUSE BUTTON_SELECT
358 #define SNAKE2_PLAYPAUSE_TEXT "Select"
361 #error No keymap defined!
364 #ifdef HAVE_TOUCHSCREEN
366 #define SNAKE2_LEFT BUTTON_MIDLEFT
369 #define SNAKE2_RIGHT BUTTON_MIDRIGHT
372 #define SNAKE2_UP BUTTON_TOPMIDDLE
375 #define SNAKE2_DOWN BUTTON_BOTTOMMIDDLE
378 #define SNAKE2_QUIT BUTTON_TOPLEFT
380 #ifndef SNAKE2_PLAYPAUSE
381 #define SNAKE2_PLAYPAUSE BUTTON_CENTER
383 #ifndef SNAKE2_PLAYPAUSE_TEXT
384 #define SNAKE2_PLAYPAUSE_TEXT "CENTER"
388 static int max_levels
= 0;
389 static char (*level_cache
)[HEIGHT
][WIDTH
];
391 /*Board itself - 2D int array*/
392 static int board
[WIDTH
][HEIGHT
];
394 Buffer for sorting movement (in case user presses two movements during a
397 static int ardirectionbuffer
[2];
404 static int level
= 4, speed
= 5,dead
= 0, quit
= 0;
405 static int sillydir
= 0, num_levels
= 0;
406 static int level_from_file
= 0;
407 static int headx
, heady
, tailx
, taily
, applecountdown
= 5;
408 static int game_type
= 0;
409 static int num_apples_to_get
=1;
410 static int num_apples_to_got
=0;
411 static int game_b_level
=0;
412 static int applecount
=0;
413 /* used for string width, height for orientation purposes */
414 static int strwdt
, strhgt
;
415 static char strbuf
[32];
418 static struct highscore highscores
[NUM_SCORES
];
426 #define EAST_NORTH 32
427 #define EAST_SOUTH 64
428 #define WEST_NORTH 128
429 #define WEST_SOUTH 256
431 #define NORTH_EAST 512
432 #define NORTH_WEST 1024
433 #define SOUTH_EAST 2048
434 #define SOUTH_WEST 4096
436 #define LEVELS_FILE PLUGIN_GAMES_DIR "/snake2.levels"
437 #define SCORE_FILE PLUGIN_GAMES_DATA_DIR "/snake2.score"
439 static int load_all_levels(void)
444 char buf
[64]; /* Larger than WIDTH, to allow for whitespace after the
447 /* Init the level_cache pointer and
448 calculate how many levels that will fit */
449 level_cache
= rb
->plugin_get_buffer(&size
);
450 max_levels
= size
/ (HEIGHT
*WIDTH
);
455 if ((fd
= rb
->open(LEVELS_FILE
, O_RDONLY
)) < 0)
460 while(rb
->read_line(fd
, buf
, 64) > 0)
462 if(rb
->strlen(buf
) == 0) /* Separator? */
465 if(num_levels
> max_levels
)
467 rb
->splash(HZ
, "Too many levels in file");
473 rb
->memcpy(level_cache
[num_levels
][linecnt
], buf
, WIDTH
);
475 if(linecnt
== HEIGHT
)
486 ** Completely clear the board of walls and/or snake
489 static void clear_board( void)
493 for (x
= 0; x
< WIDTH
; x
++)
495 for (y
= 0; y
< HEIGHT
; y
++)
502 static int load_level( int level_number
)
506 for(y
= 0;y
< HEIGHT
;y
++)
508 for(x
= 0;x
< WIDTH
;x
++)
510 switch(level_cache
[level_number
][y
][x
])
530 ** Gets the currently chosen direction from the first place
531 ** in the direction buffer. If there is something in the
532 ** next part of the buffer then that is moved to the first place
534 static void get_direction( void )
536 /*if 1st place is empty*/
537 if(ardirectionbuffer
[0] != -1)
539 /*return this direction*/
540 dir
= ardirectionbuffer
[0];
541 ardirectionbuffer
[0]=-1;
542 /*now see if one needs moving:*/
543 if(ardirectionbuffer
[1] != -1)
545 /*there's a move waiting to be done
546 so move it into the space:*/
547 ardirectionbuffer
[0] = ardirectionbuffer
[1];
548 ardirectionbuffer
[1] = -1;
554 ** Sets the direction
556 static void set_direction(int newdir
)
558 if(ardirectionbuffer
[0] != newdir
)
560 /*if 1st place is empty*/
561 if(ardirectionbuffer
[0] == -1)
564 ardirectionbuffer
[0] = newdir
;
569 if(ardirectionbuffer
[0] != newdir
) ardirectionbuffer
[1] = newdir
;
572 if(frames
< 0) ardirectionbuffer
[0] = newdir
;
576 static void new_level(int level
)
580 ardirectionbuffer
[0] = -1;
581 ardirectionbuffer
[1] = -1;
588 /*Create a small snake to start off with*/
589 board
[headx
][heady
] = dir
;
590 board
[headx
-1][heady
] = dir
;
591 board
[headx
-2][heady
] = dir
;
592 board
[headx
-3][heady
] = dir
;
593 board
[headx
-4][heady
] = dir
;
597 static void init_snake(void)
603 new_level(level_from_file
);
606 #if (LCD_WIDTH >= 160) && (LCD_HEIGHT >= 128)
607 static void draw_frame_bitmap(int header_type
)
609 rb
->lcd_bitmap(header_type
==1? snake2_header1
: snake2_header2
, 0, 0,
610 BMPWIDTH_snake2_header
, BMPHEIGHT_snake2_header
);
611 rb
->lcd_bitmap(snake2_left
, 0, BMPHEIGHT_snake2_header
,
612 BMPWIDTH_snake2_left
, BMPHEIGHT_snake2_left
);
613 rb
->lcd_bitmap(snake2_right
,
614 LCD_WIDTH
- BMPWIDTH_snake2_right
, BMPHEIGHT_snake2_header
,
615 BMPWIDTH_snake2_right
, BMPHEIGHT_snake2_right
);
616 rb
->lcd_bitmap(snake2_bottom
,
617 0, BMPHEIGHT_snake2_header
+ BMPHEIGHT_snake2_left
,
618 BMPWIDTH_snake2_bottom
, BMPHEIGHT_snake2_bottom
);
623 ** Draws the apple. If it doesn't exist then
624 ** a new one get's created.
626 static void draw_apple_bit(int x
, int y
)
628 rb
->lcd_fillrect((CENTER_X
+x
*MULTIPLIER
)+1, CENTER_Y
+y
*MULTIPLIER
,
629 MODIFIER_2
, MODIFIER_1
);
630 rb
->lcd_fillrect(CENTER_X
+x
*MULTIPLIER
, (CENTER_Y
+y
*MULTIPLIER
)+1,
631 MODIFIER_1
, MODIFIER_2
);
634 static void draw_apple( void )
638 #if LCD_WIDTH >= 160 && LCD_HEIGHT >= 128
639 draw_frame_bitmap(2);
641 rb
->snprintf(strbuf
, sizeof(strbuf
), "%d", applecount
);
642 rb
->lcd_getstringsize(strbuf
, &strwdt
, &strhgt
);
643 rb
->lcd_putsxy(TOP_X3
- strwdt
/2, TOP_Y2
, strbuf
);
645 rb
->snprintf(strbuf
, sizeof(strbuf
), "%d", score
);
646 rb
->lcd_getstringsize(strbuf
, &strwdt
, &strhgt
);
647 rb
->lcd_putsxy(TOP_X4
- strwdt
/2, TOP_Y2
, strbuf
);
654 x
= (rb
->rand() % (WIDTH
-1))+1;
655 y
= (rb
->rand() % (HEIGHT
-1))+1;
656 } while (board
[x
][y
]);
659 applex
= x
;appley
= y
;
661 draw_apple_bit(applex
, appley
);
670 static void draw_vertical_bit(int x
, int y
)
672 rb
->lcd_fillrect(CENTER_X
+x
*MULTIPLIER
+1, CENTER_Y
+y
*MULTIPLIER
,
673 MODIFIER_2
, MODIFIER_1
);
682 static void draw_horizontal_bit(int x
, int y
)
684 rb
->lcd_fillrect(CENTER_X
+x
*MULTIPLIER
, CENTER_Y
+y
*MULTIPLIER
+1,
685 MODIFIER_1
, MODIFIER_2
);
694 static void draw_n_to_e_bit(int x
, int y
)
696 rb
->lcd_fillrect(CENTER_X
+x
*MULTIPLIER
+1, CENTER_Y
+y
*MULTIPLIER
+2,
697 MODIFIER_2
, MODIFIER_2
);
698 rb
->lcd_fillrect(CENTER_X
+x
*MULTIPLIER
+2, CENTER_Y
+y
*MULTIPLIER
+1,
699 MODIFIER_2
, MODIFIER_2
);
708 static void draw_w_to_s_bit(int x
, int y
)
710 draw_n_to_e_bit(x
,y
);
719 static void draw_n_to_w_bit(int x
, int y
)
721 rb
->lcd_fillrect(CENTER_X
+x
*MULTIPLIER
, CENTER_Y
+y
*MULTIPLIER
+1,
722 MODIFIER_2
, MODIFIER_2
);
723 rb
->lcd_fillrect(CENTER_X
+x
*MULTIPLIER
+1, CENTER_Y
+y
*MULTIPLIER
+2,
724 MODIFIER_2
, MODIFIER_2
);
733 static void draw_e_to_s_bit(int x
, int y
)
735 draw_n_to_w_bit(x
, y
);
744 static void draw_s_to_e_bit(int x
, int y
)
746 rb
->lcd_fillrect(CENTER_X
+x
*MULTIPLIER
+1, CENTER_Y
+y
*MULTIPLIER
,
747 MODIFIER_2
, MODIFIER_2
);
748 rb
->lcd_fillrect(CENTER_X
+x
*MULTIPLIER
+2, CENTER_Y
+y
*MULTIPLIER
+1,
749 MODIFIER_2
, MODIFIER_2
);
758 static void draw_w_to_n_bit(int x
, int y
)
760 draw_s_to_e_bit(x
,y
);
769 static void draw_e_to_n_bit(int x
, int y
)
771 rb
->lcd_fillrect(CENTER_X
+x
*MULTIPLIER
+1, CENTER_Y
+y
*MULTIPLIER
,
772 MODIFIER_2
, MODIFIER_2
);
773 rb
->lcd_fillrect(CENTER_X
+x
*MULTIPLIER
, CENTER_Y
+y
*MULTIPLIER
+1,
774 MODIFIER_2
, MODIFIER_2
);
783 static void draw_s_to_w_bit(int x
, int y
)
785 draw_e_to_n_bit(x
, y
);
788 static void draw_head_bit(int x
, int y
)
790 rb
->lcd_fillrect(CENTER_X
+x
*MULTIPLIER
, CENTER_Y
+y
*MULTIPLIER
,
791 MODIFIER_1
, MODIFIER_1
);
796 ** Draws a wall/obsticals
798 static void draw_boundary ( void )
802 /*TODO: Load levels from file!*/
804 /*top and bottom line*/
805 for(x
=0; x
< WIDTH
; x
++)
808 board
[x
][HEIGHT
-1] = WEST
;
811 /*left and right lines*/
812 for(y
=0; y
< HEIGHT
; y
++)
815 board
[WIDTH
-1][y
] = SOUTH
;
819 board
[0][0] = NORTH_EAST
;
820 board
[WIDTH
-1][0] = EAST_SOUTH
;
821 board
[0][HEIGHT
-1] = SOUTH_EAST
;
822 board
[WIDTH
-1][HEIGHT
-1] = EAST_NORTH
;
827 ** Redraw the entire board
829 static void redraw (void)
833 #ifdef HAVE_LCD_COLOR
834 rb
->lcd_set_foreground(LCD_BLACK
);
835 rb
->lcd_set_background(LCD_WHITE
);
838 rb
->lcd_clear_display();
840 for (x
= 0; x
< WIDTH
; x
++)
842 for (y
= 0; y
< HEIGHT
; y
++)
847 draw_apple_bit(x
, y
);
854 draw_vertical_bit(x
,y
);
859 draw_horizontal_bit(x
,y
);
869 #if LCD_WIDTH >= 160 && LCD_HEIGHT >= 128
870 draw_frame_bitmap(2);
872 rb
->snprintf(strbuf
, sizeof(strbuf
), "%d", applecount
);
873 rb
->lcd_getstringsize(strbuf
, &strwdt
, &strhgt
);
874 rb
->lcd_putsxy(TOP_X3
- strwdt
/2, TOP_Y2
, strbuf
);
876 rb
->snprintf(strbuf
, sizeof(strbuf
), "%d", score
);
877 rb
->lcd_getstringsize(strbuf
, &strwdt
, &strhgt
);
878 rb
->lcd_putsxy(TOP_X4
- strwdt
/2, TOP_Y2
, strbuf
);
883 ** Draws the snake bit described by nCurrentBit at position x/y
884 ** deciding whether it's a corner bit by examing the nPrevious bit
886 static void draw_snake_bit(int currentbit
, int previousbit
, int x
, int y
)
888 rb
->lcd_set_drawmode(DRMODE_SOLID
|DRMODE_INVERSEVID
);
890 rb
->lcd_set_drawmode(DRMODE_SOLID
);
899 draw_vertical_bit(x
,y
);
903 draw_e_to_n_bit(x
,y
);
907 draw_w_to_n_bit(x
,y
);
917 draw_horizontal_bit(x
,y
);
921 draw_n_to_e_bit(x
,y
);
925 draw_s_to_e_bit(x
,y
);
935 draw_vertical_bit(x
,y
);
939 draw_e_to_s_bit(x
,y
);
943 draw_w_to_s_bit(x
,y
);
953 draw_horizontal_bit(x
,y
);
957 draw_s_to_w_bit(x
,y
);
961 draw_n_to_w_bit(x
,y
);
968 static void redraw_snake(void)
970 int x
= tailx
, y
= taily
;
971 int olddir
, newdir
= board
[x
][y
];
973 while (x
!= headx
|| y
!= heady
)
1006 newdir
= board
[x
][y
];
1007 if(olddir
!= newdir
)
1008 draw_snake_bit(newdir
, olddir
, x
, y
);
1013 ** Death 'sequence' and end game stuff.
1015 static void die (void)
1020 rb
->splash(HZ
*2, "Oops!");
1022 rb
->lcd_clear_display();
1026 rb
->lcd_getstringsize("You died!",&strwdt
,&strhgt
);
1027 rb
->lcd_putsxy((LCD_WIDTH
- strwdt
)/2,strhgt
,"You died!");
1029 rb
->snprintf(strbuf
, sizeof(strbuf
), "Your score: %d", score
);
1030 rb
->lcd_getstringsize(strbuf
, &strwdt
, &strhgt
);
1031 rb
->lcd_putsxy((LCD_WIDTH
- strwdt
)/2, strhgt
* 2 + 2, strbuf
);
1033 if (highscore_update(score
, level_from_file
, game_type
==0?"Type A":"Type B",
1034 highscores
, NUM_SCORES
) == 0)
1036 rb
->lcd_getstringsize("New high score!",&strwdt
,&strhgt
);
1037 rb
->lcd_putsxy((LCD_WIDTH
- strwdt
)/2,strhgt
* 4 + 2,"New high score!");
1041 rb
->snprintf(strbuf
, sizeof(strbuf
), "High score: %d", highscores
[0].score
);
1042 rb
->lcd_getstringsize(strbuf
, &strwdt
, &strhgt
);
1043 rb
->lcd_putsxy((LCD_WIDTH
- strwdt
)/2, strhgt
* 5, strbuf
);
1046 rb
->snprintf(strbuf
, sizeof(strbuf
), "Press %s...", SNAKE2_PLAYPAUSE_TEXT
);
1047 rb
->lcd_getstringsize(strbuf
, &strwdt
, &strhgt
);
1048 rb
->lcd_putsxy((LCD_WIDTH
- strwdt
)/2, strhgt
* 7, strbuf
);
1054 button
=rb
->button_get(true);
1057 case SNAKE2_PLAYPAUSE
:
1067 ** Check for collision. TODO: Currently this
1068 ** sets of the death sequence. What we want is it to only return a true/false
1069 ** depending on whether a collision occured.
1071 static void collision ( int x
, int y
)
1076 switch (board
[x
][y
])
1082 score
= score
+ (1 * level
);
1089 if(num_apples_to_get
== num_apples_to_got
)
1092 if(level_from_file
>= num_levels
)
1094 level_from_file
= 1;
1095 /*and increase the number of apples to pick up
1096 before level changes*/
1097 num_apples_to_get
+=2;
1100 rb
->splash(HZ
, "Level Completed!");
1101 new_level(level_from_file
);
1106 num_apples_to_got
++;
1122 static void move( void )
1125 /*this actually sets the dir variable.*/
1131 board
[headx
][heady
]=NORTH
;
1135 board
[headx
][heady
]=EAST
;
1139 board
[headx
][heady
]=SOUTH
;
1143 board
[headx
][heady
]=WEST
;
1158 draw_head_bit(headx
, heady
);
1161 if(applecountdown
<= 0)
1163 rb
->lcd_set_drawmode(DRMODE_SOLID
|DRMODE_INVERSEVID
);
1164 draw_head_bit(tailx
, taily
);
1165 rb
->lcd_set_drawmode(DRMODE_SOLID
);
1167 taildir
= board
[tailx
][taily
];
1168 board
[tailx
][taily
] = 0;
1203 static void frame (void)
1205 int olddir
, noldx
, noldy
, temp
;
1212 if(heady
== HEIGHT
-1)
1217 olddir
= board
[headx
][temp
];
1226 olddir
= board
[temp
][heady
];
1235 olddir
= board
[headx
][temp
];
1239 if(headx
== WIDTH
-1)
1244 olddir
= board
[temp
][heady
];
1251 now redraw the bit that was
1252 the tail, to something snake-like:
1254 draw_snake_bit(dir
, olddir
, noldx
, noldy
);
1256 collision(headx
, heady
);
1261 static void game_pause (void)
1265 rb
->lcd_clear_display();
1266 rb
->lcd_getstringsize("Paused",&strwdt
,&strhgt
);
1267 rb
->lcd_putsxy((LCD_WIDTH
- strwdt
)/2,LCD_HEIGHT
/2,"Paused");
1272 button
= rb
->button_get(true);
1275 case SNAKE2_PLAYPAUSE
:
1278 draw_head_bit(headx
, heady
);
1283 #ifdef SNAKE2_RC_QUIT
1284 case SNAKE2_RC_QUIT
:
1292 if (rb
->default_event_handler(button
)==SYS_USB_CONNECTED
) {
1302 static void game (void)
1314 if(frames
> 0) frames
= 0;
1328 /*it has, great set frames to a positive value again:*/
1338 rb
->sleep(HZ
/speed
);
1340 button
= rb
->button_get(false);
1342 #ifdef HAS_BUTTON_HOLD
1343 if (rb
->button_hold())
1344 button
= SNAKE2_PLAYPAUSE
;
1350 case SNAKE2_UP
| BUTTON_REPEAT
:
1351 if (dir
!= SOUTH
) set_direction(NORTH
);
1355 case SNAKE2_RIGHT
| BUTTON_REPEAT
:
1356 if (dir
!= WEST
) set_direction(EAST
);
1360 case SNAKE2_DOWN
| BUTTON_REPEAT
:
1361 if (dir
!= NORTH
) set_direction(SOUTH
);
1365 case SNAKE2_LEFT
| BUTTON_REPEAT
:
1366 if (dir
!= EAST
) set_direction(WEST
);
1369 #ifdef SNAKE2_RC_QUIT
1370 case SNAKE2_RC_QUIT
:
1376 case SNAKE2_PLAYPAUSE
:
1381 if (rb
->default_event_handler(button
)==SYS_USB_CONNECTED
) {
1391 static void select_maze(void)
1396 load_level( level_from_file
);
1402 #if LCD_WIDTH >= 160 && LCD_HEIGHT >= 128
1403 draw_frame_bitmap(1);
1405 rb
->snprintf(strbuf
, sizeof(strbuf
), "%d", level
);
1406 rb
->lcd_getstringsize(strbuf
, &strwdt
, &strhgt
);
1407 rb
->lcd_putsxy(TOP_X3
- strwdt
/2, TOP_Y2
, strbuf
);
1409 rb
->snprintf(strbuf
, sizeof(strbuf
), "%d", level_from_file
);
1410 rb
->lcd_getstringsize(strbuf
, &strwdt
, &strhgt
);
1411 rb
->lcd_putsxy(TOP_X2
- strwdt
/2, TOP_Y1
, strbuf
);
1413 rb
->strcpy(strbuf
, game_type
==0? "A": "B");
1414 rb
->lcd_getstringsize(strbuf
, &strwdt
, &strhgt
);
1415 rb
->lcd_putsxy(TOP_X1
, TOP_Y1
, strbuf
);
1417 rb
->snprintf(strbuf
, sizeof(strbuf
), "%d", highscores
[0].score
);
1418 rb
->lcd_getstringsize(strbuf
, &strwdt
, &strhgt
);
1419 rb
->lcd_putsxy(TOP_X4
- strwdt
/2, TOP_Y2
, strbuf
);
1422 rb
->snprintf(strbuf
, sizeof(strbuf
), "Maze: %d", level_from_file
);
1423 rb
->lcd_getstringsize(strbuf
, &strwdt
, &strhgt
);
1424 rb
->lcd_putsxy((WIDTH
*MULTIPLIER
- strwdt
)/2,
1425 (HEIGHT
*MULTIPLIER
- strhgt
)/2, strbuf
);
1430 button
= rb
->button_get(true);
1434 case SNAKE2_PLAYPAUSE
:
1439 if(level_from_file
< num_levels
)
1442 level_from_file
= 0;
1443 load_level( level_from_file
);
1448 if(level_from_file
> 0)
1451 level_from_file
= num_levels
;
1452 load_level( level_from_file
);
1456 if (rb
->default_event_handler(button
)==SYS_USB_CONNECTED
) {
1466 static void game_init(void)
1470 static const struct opt_items type_options
[] = {
1475 MENUITEM_STRINGLIST(menu
, "Snake2 Menu", NULL
,
1477 "Game Type", "Select Maze", "Speed",
1479 "Playback Control", "Quit");
1481 rb
->button_clear_queue();
1489 switch (rb
->do_menu(&menu
, &selection
, NULL
, false)) {
1494 rb
->set_option("Game Type", &game_type
, INT
,
1495 type_options
, 2, NULL
);
1502 rb
->set_int("Speed", "", UNIT_INT
, &level
,
1503 NULL
, 1, 1, 10, NULL
);
1506 highscore_show(-1, highscores
, NUM_SCORES
, true);
1509 playback_control(NULL
);
1514 case MENU_ATTACHED_USB
:
1523 enum plugin_status
plugin_start(const void* parameter
)
1527 /* Lets use the default font */
1528 rb
->lcd_setfont(FONT_SYSFIXED
);
1530 rb
->lcd_set_backdrop(NULL
);
1535 if (num_levels
== 0) {
1536 rb
->splash(HZ
*2, "Failed loading levels!");
1540 highscore_load(SCORE_FILE
, highscores
, NUM_SCORES
);
1548 rb
->lcd_clear_display();
1557 highscore_save(SCORE_FILE
, highscores
, NUM_SCORES
);
1559 return (quit
==1) ? PLUGIN_OK
: PLUGIN_USB_CONNECTED
;