RaaA: Fix write locations of plugins
[maemo-rb.git] / apps / plugins / snake2.c
blob3d8b973074ce7ab661d1d02e2fd5b5d5df4539ed
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 #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 (CONFIG_KEYPAD == PHILIPS_HDD6330_PAD)
281 #define SNAKE2_LEFT BUTTON_LEFT
282 #define SNAKE2_RIGHT BUTTON_RIGHT
283 #define SNAKE2_UP BUTTON_UP
284 #define SNAKE2_DOWN BUTTON_DOWN
285 #define SNAKE2_QUIT BUTTON_POWER
286 #define SNAKE2_PLAYPAUSE BUTTON_VIEW
287 #define SNAKE2_PLAYPAUSE_TEXT "View"
289 #elif CONFIG_KEYPAD == PHILIPS_SA9200_PAD
290 #define SNAKE2_LEFT BUTTON_PREV
291 #define SNAKE2_RIGHT BUTTON_NEXT
292 #define SNAKE2_UP BUTTON_UP
293 #define SNAKE2_DOWN BUTTON_DOWN
294 #define SNAKE2_QUIT BUTTON_POWER
295 #define SNAKE2_PLAYPAUSE BUTTON_RIGHT
296 #define SNAKE2_PLAYPAUSE_TEXT "Right"
298 #elif (CONFIG_KEYPAD == ONDAVX747_PAD) || \
299 (CONFIG_KEYPAD == ONDAVX777_PAD) || \
300 CONFIG_KEYPAD == MROBE500_PAD
301 #define SNAKE2_QUIT BUTTON_POWER
303 #elif (CONFIG_KEYPAD == SAMSUNG_YH_PAD)
304 #define SNAKE2_LEFT BUTTON_LEFT
305 #define SNAKE2_RIGHT BUTTON_RIGHT
306 #define SNAKE2_UP BUTTON_UP
307 #define SNAKE2_DOWN BUTTON_DOWN
308 #define SNAKE2_QUIT BUTTON_REC
309 #define SNAKE2_PLAYPAUSE BUTTON_PLAY
310 #define SNAKE2_PLAYPAUSE_TEXT "Play"
312 #elif CONFIG_KEYPAD == PBELL_VIBE500_PAD
313 #define SNAKE2_LEFT BUTTON_PREV
314 #define SNAKE2_RIGHT BUTTON_NEXT
315 #define SNAKE2_UP BUTTON_UP
316 #define SNAKE2_DOWN BUTTON_DOWN
317 #define SNAKE2_QUIT BUTTON_REC
318 #define SNAKE2_PLAYPAUSE BUTTON_PLAY
319 #define SNAKE2_PLAYPAUSE_TEXT "Play"
321 #elif CONFIG_KEYPAD == MPIO_HD200_PAD
322 #define SNAKE2_LEFT BUTTON_VOL_DOWN
323 #define SNAKE2_RIGHT BUTTON_VOL_UP
324 #define SNAKE2_UP BUTTON_REW
325 #define SNAKE2_DOWN BUTTON_FF
326 #define SNAKE2_QUIT (BUTTON_REC | BUTTON_PLAY)
327 #define SNAKE2_PLAYPAUSE BUTTON_PLAY
328 #define SNAKE2_PLAYPAUSE_TEXT "Play"
330 #elif CONFIG_KEYPAD == MPIO_HD300_PAD
331 #define SNAKE2_LEFT BUTTON_MENU
332 #define SNAKE2_RIGHT BUTTON_ENTER
333 #define SNAKE2_UP BUTTON_UP
334 #define SNAKE2_DOWN BUTTON_DOWN
335 #define SNAKE2_QUIT (BUTTON_REC|BUTTON_REPEAT)
336 #define SNAKE2_PLAYPAUSE BUTTON_PLAY
337 #define SNAKE2_PLAYPAUSE_TEXT "Play"
339 #else
340 #error No keymap defined!
341 #endif
343 #ifdef HAVE_TOUCHSCREEN
344 #ifndef SNAKE2_LEFT
345 #define SNAKE2_LEFT BUTTON_MIDLEFT
346 #endif
347 #ifndef SNAKE2_RIGHT
348 #define SNAKE2_RIGHT BUTTON_MIDRIGHT
349 #endif
350 #ifndef SNAKE2_UP
351 #define SNAKE2_UP BUTTON_TOPMIDDLE
352 #endif
353 #ifndef SNAKE2_DOWN
354 #define SNAKE2_DOWN BUTTON_BOTTOMMIDDLE
355 #endif
356 #ifndef SNAKE2_QUIT
357 #define SNAKE2_QUIT BUTTON_TOPLEFT
358 #endif
359 #ifndef SNAKE2_PLAYPAUSE
360 #define SNAKE2_PLAYPAUSE BUTTON_CENTER
361 #endif
362 #ifndef SNAKE2_PLAYPAUSE_TEXT
363 #define SNAKE2_PLAYPAUSE_TEXT "CENTER"
364 #endif
365 #endif
367 static int max_levels = 0;
368 static char (*level_cache)[HEIGHT][WIDTH];
370 /*Board itself - 2D int array*/
371 static int board[WIDTH][HEIGHT];
373 Buffer for sorting movement (in case user presses two movements during a
374 single frame
376 static int ardirectionbuffer[2];
377 static int score;
378 static int applex;
379 static int appley;
380 static int dir;
381 static int frames;
382 static int apple;
383 static int level = 4, speed = 5,dead = 0, quit = 0;
384 static int sillydir = 0, num_levels = 0;
385 static int level_from_file = 0;
386 static int headx, heady, tailx, taily, applecountdown = 5;
387 static int game_type = 0;
388 static int num_apples_to_get=1;
389 static int num_apples_to_got=0;
390 static int game_b_level=0;
391 static int applecount=0;
392 /* used for string width, height for orientation purposes */
393 static int strwdt, strhgt;
394 static char strbuf[32];
396 #define NUM_SCORES 5
397 static struct highscore highscores[NUM_SCORES];
399 #define NORTH 1
400 #define EAST 2
401 #define SOUTH 4
402 #define WEST 8
403 #define HEAD 16
405 #define EAST_NORTH 32
406 #define EAST_SOUTH 64
407 #define WEST_NORTH 128
408 #define WEST_SOUTH 256
410 #define NORTH_EAST 512
411 #define NORTH_WEST 1024
412 #define SOUTH_EAST 2048
413 #define SOUTH_WEST 4096
415 #define LEVELS_FILE PLUGIN_GAMES_DIR "/snake2.levels"
416 #define SCORE_FILE PLUGIN_GAMES_DATA_DIR "/snake2.score"
418 int load_all_levels(void)
420 int linecnt = 0;
421 int fd;
422 size_t size;
423 char buf[64]; /* Larger than WIDTH, to allow for whitespace after the
424 lines */
426 /* Init the level_cache pointer and
427 calculate how many levels that will fit */
428 level_cache = rb->plugin_get_buffer(&size);
429 max_levels = size / (HEIGHT*WIDTH);
431 num_levels = 0;
433 /* open file */
434 if ((fd = rb->open(LEVELS_FILE, O_RDONLY)) < 0)
436 return -1;
439 while(rb->read_line(fd, buf, 64) > 0)
441 if(rb->strlen(buf) == 0) /* Separator? */
443 num_levels++;
444 if(num_levels > max_levels)
446 rb->splash(HZ, "Too many levels in file");
447 break;
449 continue;
452 rb->memcpy(level_cache[num_levels][linecnt], buf, WIDTH);
453 linecnt++;
454 if(linecnt == HEIGHT)
456 linecnt = 0;
460 rb->close(fd);
461 return 0;
465 ** Completely clear the board of walls and/or snake
468 void clear_board( void)
470 int x,y;
472 for (x = 0; x < WIDTH; x++)
474 for (y = 0; y < HEIGHT; y++)
476 board[x][y] = 0;
481 int load_level( int level_number )
483 int x,y;
484 clear_board();
485 for(y = 0;y < HEIGHT;y++)
487 for(x = 0;x < WIDTH;x++)
489 switch(level_cache[level_number][y][x])
491 case '|':
492 board[x][y] = NORTH;
493 break;
495 case '-':
496 board[x][y] = EAST;
497 break;
499 case '+':
500 board[x][y] = HEAD;
501 break;
505 return 1;
509 ** Gets the currently chosen direction from the first place
510 ** in the direction buffer. If there is something in the
511 ** next part of the buffer then that is moved to the first place
513 void get_direction( void )
515 /*if 1st place is empty*/
516 if(ardirectionbuffer[0] != -1)
518 /*return this direction*/
519 dir = ardirectionbuffer[0];
520 ardirectionbuffer[0]=-1;
521 /*now see if one needs moving:*/
522 if(ardirectionbuffer[1] != -1)
524 /*there's a move waiting to be done
525 so move it into the space:*/
526 ardirectionbuffer[0] = ardirectionbuffer[1];
527 ardirectionbuffer[1] = -1;
533 ** Sets the direction
535 void set_direction(int newdir)
537 if(ardirectionbuffer[0] != newdir)
539 /*if 1st place is empty*/
540 if(ardirectionbuffer[0] == -1)
542 /*use 1st space:*/
543 ardirectionbuffer[0] = newdir;
545 else
547 /*use 2nd space:*/
548 if(ardirectionbuffer[0] != newdir) ardirectionbuffer[1] = newdir;
551 if(frames < 0) ardirectionbuffer[0] = newdir;
555 void new_level(int level)
557 load_level(level);
559 ardirectionbuffer[0] = -1;
560 ardirectionbuffer[1] = -1;
561 dir = EAST;
562 headx = WIDTH/2;
563 heady = HEIGHT/2;
564 tailx = headx - 4;
565 taily = heady;
566 applecountdown = 0;
567 /*Create a small snake to start off with*/
568 board[headx][heady] = dir;
569 board[headx-1][heady] = dir;
570 board[headx-2][heady] = dir;
571 board[headx-3][heady] = dir;
572 board[headx-4][heady] = dir;
573 num_apples_to_got=0;
576 void init_snake(void)
578 num_apples_to_get=1;
579 if(game_type == 1)
580 level_from_file = 1;
581 game_b_level=1;
582 new_level(level_from_file);
585 #if (LCD_WIDTH >= 160) && (LCD_HEIGHT >= 128)
586 void draw_frame_bitmap(int header_type)
588 rb->lcd_bitmap(header_type==1? snake2_header1: snake2_header2, 0, 0,
589 BMPWIDTH_snake2_header, BMPHEIGHT_snake2_header);
590 rb->lcd_bitmap(snake2_left, 0, BMPHEIGHT_snake2_header,
591 BMPWIDTH_snake2_left, BMPHEIGHT_snake2_left);
592 rb->lcd_bitmap(snake2_right,
593 LCD_WIDTH - BMPWIDTH_snake2_right, BMPHEIGHT_snake2_header,
594 BMPWIDTH_snake2_right, BMPHEIGHT_snake2_right);
595 rb->lcd_bitmap(snake2_bottom,
596 0, BMPHEIGHT_snake2_header + BMPHEIGHT_snake2_left,
597 BMPWIDTH_snake2_bottom, BMPHEIGHT_snake2_bottom);
599 #endif
602 ** Draws the apple. If it doesn't exist then
603 ** a new one get's created.
605 void draw_apple_bit(int x, int y)
607 rb->lcd_fillrect((CENTER_X+x*MULTIPLIER)+1, CENTER_Y+y*MULTIPLIER,
608 MODIFIER_2, MODIFIER_1);
609 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER, (CENTER_Y+y*MULTIPLIER)+1,
610 MODIFIER_1, MODIFIER_2);
613 void draw_apple( void )
615 int x,y;
617 #if LCD_WIDTH >= 160 && LCD_HEIGHT >= 128
618 draw_frame_bitmap(2);
620 rb->snprintf(strbuf, sizeof(strbuf), "%d", applecount);
621 rb->lcd_getstringsize(strbuf, &strwdt, &strhgt);
622 rb->lcd_putsxy(TOP_X3 - strwdt/2, TOP_Y2, strbuf);
624 rb->snprintf(strbuf, sizeof(strbuf), "%d", score);
625 rb->lcd_getstringsize(strbuf, &strwdt, &strhgt);
626 rb->lcd_putsxy(TOP_X4 - strwdt/2, TOP_Y2, strbuf);
627 #endif
629 if (!apple)
633 x = (rb->rand() % (WIDTH-1))+1;
634 y = (rb->rand() % (HEIGHT-1))+1;
635 } while (board[x][y]);
636 apple = 1;
637 board[x][y] = -1;
638 applex = x;appley = y;
640 draw_apple_bit(applex, appley);
644 * x x *
645 * x x *
646 * x x *
647 * x x *
649 void draw_vertical_bit(int x, int y)
651 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER+1, CENTER_Y+y*MULTIPLIER,
652 MODIFIER_2, MODIFIER_1);
656 * * * *
657 X X X X
658 X X X X
659 * * * *
661 void draw_horizontal_bit(int x, int y)
663 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER, CENTER_Y+y*MULTIPLIER+1,
664 MODIFIER_1, MODIFIER_2);
668 * * * *
669 * * X X
670 * X X X
671 * X X *
673 void draw_n_to_e_bit(int x, int y)
675 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER+1, CENTER_Y+y*MULTIPLIER+2,
676 MODIFIER_2, MODIFIER_2);
677 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER+2, CENTER_Y+y*MULTIPLIER+1,
678 MODIFIER_2, MODIFIER_2);
682 * * * *
683 * * X X
684 * X X X
685 * X X *
687 void draw_w_to_s_bit(int x, int y)
689 draw_n_to_e_bit(x,y);
693 * * * *
694 X X * *
695 X X X *
696 * X X *
698 void draw_n_to_w_bit(int x, int y)
700 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER, CENTER_Y+y*MULTIPLIER+1,
701 MODIFIER_2, MODIFIER_2);
702 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER+1, CENTER_Y+y*MULTIPLIER+2,
703 MODIFIER_2, MODIFIER_2);
707 * * * *
708 X X * *
709 X X X *
710 * X X *
712 void draw_e_to_s_bit(int x, int y)
714 draw_n_to_w_bit(x, y);
718 * X X *
719 * X X X
720 * * X X
721 * * * *
723 void draw_s_to_e_bit(int x, int y)
725 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER+1, CENTER_Y+y*MULTIPLIER,
726 MODIFIER_2, MODIFIER_2);
727 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER+2, CENTER_Y+y*MULTIPLIER+1,
728 MODIFIER_2, MODIFIER_2);
732 * X X *
733 * X X X
734 * * X X
735 * * * *
737 void draw_w_to_n_bit(int x, int y)
739 draw_s_to_e_bit(x,y);
743 * X X *
744 X X X *
745 X X * *
746 * * * *
748 void draw_e_to_n_bit(int x, int y)
750 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER+1, CENTER_Y+y*MULTIPLIER,
751 MODIFIER_2, MODIFIER_2);
752 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER, CENTER_Y+y*MULTIPLIER+1,
753 MODIFIER_2, MODIFIER_2);
757 * X X *
758 X X X *
759 X X * *
760 * * * *
762 void draw_s_to_w_bit(int x, int y)
764 draw_e_to_n_bit(x, y);
767 void draw_head_bit(int x, int y)
769 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER, CENTER_Y+y*MULTIPLIER,
770 MODIFIER_1, MODIFIER_1);
774 ** Draws a wall/obsticals
776 void draw_boundary ( void )
778 int x, y;
780 /*TODO: Load levels from file!*/
782 /*top and bottom line*/
783 for(x=0; x < WIDTH; x++)
785 board[x][0] = EAST;
786 board[x][HEIGHT-1] = WEST;
789 /*left and right lines*/
790 for(y=0; y < HEIGHT; y++)
792 board[0][y] = NORTH;
793 board[WIDTH-1][y] = SOUTH;
796 /*corners:*/
797 board[0][0] = NORTH_EAST;
798 board[WIDTH-1][0] = EAST_SOUTH;
799 board[0][HEIGHT-1] = SOUTH_EAST;
800 board[WIDTH-1][HEIGHT-1] = EAST_NORTH;
804 ** Redraw the entire board
806 void redraw (void)
808 int x,y;
810 #ifdef HAVE_LCD_COLOR
811 rb->lcd_set_foreground(LCD_BLACK);
812 rb->lcd_set_background(LCD_WHITE);
813 #endif
815 rb->lcd_clear_display();
817 for (x = 0; x < WIDTH; x++)
819 for (y = 0; y < HEIGHT; y++)
821 switch (board[x][y])
823 case -1:
824 draw_apple_bit(x, y);
825 break;
826 case 0:
827 break;
829 case NORTH:
830 case SOUTH:
831 draw_vertical_bit(x,y);
832 break;
834 case EAST:
835 case WEST:
836 draw_horizontal_bit(x,y);
837 break;
839 default:
840 draw_head_bit(x, y);
841 break;
846 #if LCD_WIDTH >= 160 && LCD_HEIGHT >= 128
847 draw_frame_bitmap(2);
849 rb->snprintf(strbuf, sizeof(strbuf), "%d", applecount);
850 rb->lcd_getstringsize(strbuf, &strwdt, &strhgt);
851 rb->lcd_putsxy(TOP_X3 - strwdt/2, TOP_Y2, strbuf);
853 rb->snprintf(strbuf, sizeof(strbuf), "%d", score);
854 rb->lcd_getstringsize(strbuf, &strwdt, &strhgt);
855 rb->lcd_putsxy(TOP_X4 - strwdt/2, TOP_Y2, strbuf);
856 #endif
860 ** Draws the snake bit described by nCurrentBit at position x/y
861 ** deciding whether it's a corner bit by examing the nPrevious bit
863 void draw_snake_bit(int currentbit, int previousbit, int x, int y)
865 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
866 draw_head_bit(x, y);
867 rb->lcd_set_drawmode(DRMODE_SOLID);
869 switch(currentbit)
871 case(NORTH):
872 switch(previousbit)
874 case(SOUTH):
875 case(NORTH):
876 draw_vertical_bit(x,y);
877 break;
879 case(EAST):
880 draw_e_to_n_bit(x,y);
881 break;
883 case(WEST):
884 draw_w_to_n_bit(x,y);
885 break;
887 break;
889 case(EAST):
890 switch(previousbit)
892 case(WEST):
893 case(EAST):
894 draw_horizontal_bit(x,y);
895 break;
897 case(NORTH):
898 draw_n_to_e_bit(x,y);
899 break;
901 case(SOUTH):
902 draw_s_to_e_bit(x,y);
903 break;
905 break;
907 case(SOUTH):
908 switch(previousbit)
910 case(SOUTH):
911 case(NORTH):
912 draw_vertical_bit(x,y);
913 break;
915 case(EAST):
916 draw_e_to_s_bit(x,y);
917 break;
919 case(WEST):
920 draw_w_to_s_bit(x,y);
921 break;
923 break;
925 case(WEST):
926 switch(previousbit)
928 case(EAST):
929 case(WEST):
930 draw_horizontal_bit(x,y);
931 break;
933 case(SOUTH):
934 draw_s_to_w_bit(x,y);
935 break;
937 case(NORTH):
938 draw_n_to_w_bit(x,y);
939 break;
941 break;
945 void redraw_snake(void)
947 int x = tailx, y = taily;
948 int olddir, newdir = board[x][y];
950 while (x != headx || y != heady)
952 olddir = newdir;
954 switch (olddir)
956 case(NORTH):
957 y--;
958 break;
960 case(EAST):
961 x++;
962 break;
964 case(SOUTH):
965 y++;
966 break;
968 case(WEST):
969 x--;
970 break;
973 if(x == WIDTH)
974 x = 0;
975 else if(x < 0)
976 x = WIDTH-1;
978 if(y == HEIGHT)
979 y = 0;
980 else if(y < 0)
981 y = HEIGHT-1;
983 newdir = board[x][y];
984 if(olddir != newdir)
985 draw_snake_bit(newdir, olddir, x, y);
990 ** Death 'sequence' and end game stuff.
992 void die (void)
994 int button;
995 bool done=false;
997 rb->splash(HZ*2, "Oops!");
999 rb->lcd_clear_display();
1001 applecount=0;
1003 rb->lcd_getstringsize("You died!",&strwdt,&strhgt);
1004 rb->lcd_putsxy((LCD_WIDTH - strwdt)/2,strhgt,"You died!");
1006 rb->snprintf(strbuf, sizeof(strbuf), "Your score: %d", score);
1007 rb->lcd_getstringsize(strbuf, &strwdt, &strhgt);
1008 rb->lcd_putsxy((LCD_WIDTH - strwdt)/2, strhgt * 2 + 2, strbuf);
1010 if (highscore_update(score, level_from_file, game_type==0?"Type A":"Type B",
1011 highscores, NUM_SCORES) == 0)
1013 rb->lcd_getstringsize("New high score!",&strwdt,&strhgt);
1014 rb->lcd_putsxy((LCD_WIDTH - strwdt)/2,strhgt * 4 + 2,"New high score!");
1016 else
1018 rb->snprintf(strbuf, sizeof(strbuf), "High score: %d", highscores[0].score);
1019 rb->lcd_getstringsize(strbuf, &strwdt, &strhgt);
1020 rb->lcd_putsxy((LCD_WIDTH - strwdt)/2, strhgt * 5, strbuf);
1023 rb->snprintf(strbuf, sizeof(strbuf), "Press %s...", SNAKE2_PLAYPAUSE_TEXT);
1024 rb->lcd_getstringsize(strbuf, &strwdt, &strhgt);
1025 rb->lcd_putsxy((LCD_WIDTH - strwdt)/2, strhgt * 7, strbuf);
1027 rb->lcd_update();
1029 while(!done)
1031 button=rb->button_get(true);
1032 switch(button)
1034 case SNAKE2_PLAYPAUSE:
1035 done = true;
1036 break;
1040 dead=1;
1044 ** Check for collision. TODO: Currently this
1045 ** sets of the death sequence. What we want is it to only return a true/false
1046 ** depending on whether a collision occured.
1048 void collision ( int x, int y )
1050 int bdeath=0;
1053 switch (board[x][y])
1055 case 0:
1057 break;
1058 case -1:
1059 score = score + (1 * level);
1060 apple=0;
1061 applecountdown=2;
1062 applecount++;
1064 if(game_type==1)
1066 if(num_apples_to_get == num_apples_to_got)
1068 level_from_file++;
1069 if(level_from_file >= num_levels)
1071 level_from_file = 1;
1072 /*and increase the number of apples to pick up
1073 before level changes*/
1074 num_apples_to_get+=2;
1075 game_b_level++;
1077 rb->splash(HZ, "Level Completed!");
1078 new_level(level_from_file);
1079 redraw();
1080 rb->lcd_update();
1082 else
1083 num_apples_to_got++;
1085 break;
1086 default:
1087 bdeath=1;
1088 break;
1091 if(bdeath==1)
1093 die();
1094 sillydir = dir;
1095 frames = -110;
1099 void move( void )
1101 int taildir;
1102 /*this actually sets the dir variable.*/
1103 get_direction();
1104 /*draw head*/
1105 switch (dir)
1107 case (NORTH):
1108 board[headx][heady]=NORTH;
1109 heady--;
1110 break;
1111 case (EAST):
1112 board[headx][heady]=EAST;
1113 headx++;
1114 break;
1115 case (SOUTH):
1116 board[headx][heady]=SOUTH;
1117 heady++;
1118 break;
1119 case (WEST):
1120 board[headx][heady]=WEST;
1121 headx--;
1122 break;
1125 if(headx == WIDTH)
1126 headx = 0;
1127 else if(headx < 0)
1128 headx = WIDTH-1;
1130 if(heady == HEIGHT)
1131 heady = 0;
1132 else if(heady < 0)
1133 heady = HEIGHT-1;
1135 draw_head_bit(headx, heady);
1137 /*clear tail*/
1138 if(applecountdown <= 0)
1140 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
1141 draw_head_bit(tailx, taily);
1142 rb->lcd_set_drawmode(DRMODE_SOLID);
1144 taildir = board[tailx][taily];
1145 board[tailx][taily] = 0;
1147 switch (taildir)
1149 case(NORTH):
1150 taily--;
1151 break;
1153 case(EAST):
1154 tailx++;
1155 break;
1157 case(SOUTH):
1158 taily++;
1159 break;
1161 case(WEST):
1162 tailx--;
1163 break;
1166 if(tailx == WIDTH)
1167 tailx = 0;
1168 else if(tailx < 0)
1169 tailx = WIDTH-1;
1171 if(taily == HEIGHT)
1172 taily = 0;
1173 else if(taily < 0)
1174 taily = HEIGHT-1;
1176 else
1177 applecountdown--;
1180 void frame (void)
1182 int olddir, noldx, noldy, temp;
1183 noldx = headx;
1184 noldy = heady;
1185 olddir = 0;
1186 switch(dir)
1188 case(NORTH):
1189 if(heady == HEIGHT-1)
1190 temp = 0;
1191 else
1192 temp = heady + 1;
1194 olddir = board[headx][temp];
1195 break;
1197 case(EAST):
1198 if(headx == 0)
1199 temp = WIDTH-1;
1200 else
1201 temp = headx - 1;
1203 olddir = board[temp][heady];
1204 break;
1206 case(SOUTH):
1207 if(heady == 0)
1208 temp = HEIGHT-1;
1209 else
1210 temp = heady - 1;
1212 olddir = board[headx][temp];
1213 break;
1215 case(WEST):
1216 if(headx == WIDTH-1)
1217 temp = 0;
1218 else
1219 temp = headx + 1;
1221 olddir = board[temp][heady];
1222 break;
1225 move();
1228 now redraw the bit that was
1229 the tail, to something snake-like:
1231 draw_snake_bit(dir, olddir, noldx, noldy);
1233 collision(headx, heady);
1235 rb->lcd_update();
1238 void game_pause (void)
1240 int button;
1242 rb->lcd_clear_display();
1243 rb->lcd_getstringsize("Paused",&strwdt,&strhgt);
1244 rb->lcd_putsxy((LCD_WIDTH - strwdt)/2,LCD_HEIGHT/2,"Paused");
1246 rb->lcd_update();
1247 while (1)
1249 button = rb->button_get(true);
1250 switch (button)
1252 case SNAKE2_PLAYPAUSE:
1253 redraw();
1254 redraw_snake();
1255 draw_head_bit(headx, heady);
1256 rb->lcd_update();
1257 rb->sleep(HZ/2);
1258 return;
1260 #ifdef SNAKE2_RC_QUIT
1261 case SNAKE2_RC_QUIT:
1262 #endif
1263 case SNAKE2_QUIT:
1264 dead = 1;
1265 quit = 1;
1266 return;
1268 default:
1269 if (rb->default_event_handler(button)==SYS_USB_CONNECTED) {
1270 dead = 1;
1271 quit = 2;
1272 return;
1274 break;
1279 void game (void)
1281 int button;
1283 redraw();
1284 rb->lcd_update();
1285 /*main loop:*/
1286 while (1)
1288 if(frames==5)
1290 frame();
1291 if(frames > 0) frames = 0;
1293 frames++;
1295 if(frames == 0)
1297 die();
1299 else
1301 if(frames < 0)
1303 if(sillydir != dir)
1305 /*it has, great set frames to a positive value again:*/
1306 frames = 1;
1311 if (dead) return;
1313 draw_apple();
1315 rb->sleep(HZ/speed);
1317 button = rb->button_get(false);
1319 #ifdef HAS_BUTTON_HOLD
1320 if (rb->button_hold())
1321 button = SNAKE2_PLAYPAUSE;
1322 #endif
1324 switch (button)
1326 case SNAKE2_UP:
1327 case SNAKE2_UP | BUTTON_REPEAT:
1328 if (dir != SOUTH) set_direction(NORTH);
1329 break;
1331 case SNAKE2_RIGHT:
1332 case SNAKE2_RIGHT | BUTTON_REPEAT:
1333 if (dir != WEST) set_direction(EAST);
1334 break;
1336 case SNAKE2_DOWN:
1337 case SNAKE2_DOWN | BUTTON_REPEAT:
1338 if (dir != NORTH) set_direction(SOUTH);
1339 break;
1341 case SNAKE2_LEFT:
1342 case SNAKE2_LEFT | BUTTON_REPEAT:
1343 if (dir != EAST) set_direction(WEST);
1344 break;
1346 #ifdef SNAKE2_RC_QUIT
1347 case SNAKE2_RC_QUIT:
1348 #endif
1349 case SNAKE2_QUIT:
1350 quit = 1;
1351 return;
1353 case SNAKE2_PLAYPAUSE:
1354 game_pause();
1355 break;
1357 default:
1358 if (rb->default_event_handler(button)==SYS_USB_CONNECTED) {
1359 quit = 2;
1360 return;
1362 break;
1368 void select_maze(void)
1370 int button;
1372 clear_board();
1373 load_level( level_from_file );
1374 redraw();
1375 rb->lcd_update();
1377 while (1)
1379 #if LCD_WIDTH >= 160 && LCD_HEIGHT >= 128
1380 draw_frame_bitmap(1);
1382 rb->snprintf(strbuf, sizeof(strbuf), "%d", level);
1383 rb->lcd_getstringsize(strbuf, &strwdt, &strhgt);
1384 rb->lcd_putsxy(TOP_X3 - strwdt/2, TOP_Y2, strbuf);
1386 rb->snprintf(strbuf, sizeof(strbuf), "%d", level_from_file);
1387 rb->lcd_getstringsize(strbuf, &strwdt, &strhgt);
1388 rb->lcd_putsxy(TOP_X2 - strwdt/2, TOP_Y1, strbuf);
1390 rb->strcpy(strbuf, game_type==0? "A": "B");
1391 rb->lcd_getstringsize(strbuf, &strwdt, &strhgt);
1392 rb->lcd_putsxy(TOP_X1, TOP_Y1, strbuf);
1394 rb->snprintf(strbuf, sizeof(strbuf), "%d", highscores[0].score);
1395 rb->lcd_getstringsize(strbuf, &strwdt, &strhgt);
1396 rb->lcd_putsxy(TOP_X4 - strwdt/2, TOP_Y2, strbuf);
1398 #else
1399 rb->snprintf(strbuf, sizeof(strbuf), "Maze: %d", level_from_file);
1400 rb->lcd_getstringsize(strbuf, &strwdt, &strhgt);
1401 rb->lcd_putsxy((WIDTH*MULTIPLIER - strwdt)/2,
1402 (HEIGHT*MULTIPLIER - strhgt)/2, strbuf);
1403 #endif
1405 rb->lcd_update();
1407 button = rb->button_get(true);
1408 switch (button)
1410 case SNAKE2_QUIT:
1411 case SNAKE2_PLAYPAUSE:
1412 return;
1413 break;
1414 case SNAKE2_UP:
1415 case SNAKE2_RIGHT:
1416 if(level_from_file < num_levels)
1417 level_from_file++;
1418 else
1419 level_from_file = 0;
1420 load_level( level_from_file );
1421 redraw();
1422 break;
1423 case SNAKE2_DOWN:
1424 case SNAKE2_LEFT:
1425 if(level_from_file > 0)
1426 level_from_file--;
1427 else
1428 level_from_file = num_levels;
1429 load_level( level_from_file );
1430 redraw();
1431 break;
1432 default:
1433 if (rb->default_event_handler(button)==SYS_USB_CONNECTED) {
1434 quit = 2;
1435 return;
1437 break;
1443 void game_init(void)
1445 int selection = 0;
1447 static const struct opt_items type_options[] = {
1448 { "Type A", -1 },
1449 { "Type B", -1 },
1452 MENUITEM_STRINGLIST(menu, "Snake2 Menu", NULL,
1453 "Start New Game",
1454 "Game Type", "Select Maze", "Speed",
1455 "High Scores",
1456 "Playback Control", "Quit");
1458 rb->button_clear_queue();
1460 dead = 0;
1461 apple = 0;
1462 score = 0;
1463 applecount = 0;
1465 while (1) {
1466 switch (rb->do_menu(&menu, &selection, NULL, false)) {
1467 case 0:
1468 speed = level*20;
1469 return;
1470 case 1:
1471 rb->set_option("Game Type", &game_type, INT,
1472 type_options, 2, NULL);
1473 break;
1474 case 2:
1475 select_maze();
1476 if(quit) return;
1477 break;
1478 case 3:
1479 rb->set_int("Speed", "", UNIT_INT, &level,
1480 NULL, 1, 1, 10, NULL);
1481 break;
1482 case 4:
1483 highscore_show(-1, highscores, NUM_SCORES, true);
1484 break;
1485 case 5:
1486 playback_control(NULL);
1487 break;
1488 case 6:
1489 quit = 1;
1490 return;
1491 case MENU_ATTACHED_USB:
1492 quit = 2;
1493 return;
1494 default:
1495 break;
1500 enum plugin_status plugin_start(const void* parameter)
1502 (void)(parameter);
1504 /* Lets use the default font */
1505 rb->lcd_setfont(FONT_SYSFIXED);
1506 #if LCD_DEPTH > 1
1507 rb->lcd_set_backdrop(NULL);
1508 #endif
1510 load_all_levels();
1512 if (num_levels == 0) {
1513 rb->splash(HZ*2, "Failed loading levels!");
1514 return PLUGIN_OK;
1517 highscore_load(SCORE_FILE, highscores, NUM_SCORES);
1519 while(quit==0)
1521 game_init();
1522 if(quit)
1523 break;
1525 rb->lcd_clear_display();
1526 frames=1;
1528 init_snake();
1530 /*Start Game:*/
1531 game();
1534 highscore_save(SCORE_FILE, highscores, NUM_SCORES);
1536 return (quit==1) ? PLUGIN_OK : PLUGIN_USB_CONNECTED;