Prepare new maemo release
[maemo-rb.git] / apps / plugins / snake.c
blob8d2a9b0011ff54ac656b6a1f7317df2824a38e89
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2002 Itai Shaked
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 Snake!
25 by Itai Shaked
27 ok, a little explanation -
28 board holds the snake and apple position - 1+ - snake body (the number
29 represents the age [1 is the snake's head]).
30 -1 is an apple, and 0 is a clear spot.
31 dir is the current direction of the snake - 0=up, 1=right, 2=down, 3=left;
35 #include "plugin.h"
37 #include "lib/configfile.h"
38 #include "lib/highscore.h"
39 #include "lib/playback_control.h"
43 /* variable button definitions */
44 #if CONFIG_KEYPAD == RECORDER_PAD
45 #define SNAKE_QUIT BUTTON_OFF
46 #define SNAKE_LEFT BUTTON_LEFT
47 #define SNAKE_RIGHT BUTTON_RIGHT
48 #define SNAKE_UP BUTTON_UP
49 #define SNAKE_DOWN BUTTON_DOWN
50 #define SNAKE_PLAYPAUSE BUTTON_PLAY
52 #elif CONFIG_KEYPAD == ARCHOS_AV300_PAD
53 #define SNAKE_QUIT BUTTON_OFF
54 #define SNAKE_LEFT BUTTON_LEFT
55 #define SNAKE_RIGHT BUTTON_RIGHT
56 #define SNAKE_UP BUTTON_UP
57 #define SNAKE_DOWN BUTTON_DOWN
58 #define SNAKE_PLAYPAUSE BUTTON_SELECT
60 #elif CONFIG_KEYPAD == ONDIO_PAD
61 #define SNAKE_QUIT BUTTON_OFF
62 #define SNAKE_LEFT BUTTON_LEFT
63 #define SNAKE_RIGHT BUTTON_RIGHT
64 #define SNAKE_UP BUTTON_UP
65 #define SNAKE_DOWN BUTTON_DOWN
66 #define SNAKE_PLAYPAUSE BUTTON_MENU
68 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
69 (CONFIG_KEYPAD == IRIVER_H300_PAD)
70 #define SNAKE_QUIT BUTTON_OFF
71 #define SNAKE_LEFT BUTTON_LEFT
72 #define SNAKE_RIGHT BUTTON_RIGHT
73 #define SNAKE_UP BUTTON_UP
74 #define SNAKE_DOWN BUTTON_DOWN
75 #define SNAKE_PLAYPAUSE BUTTON_ON
77 #define SNAKE_RC_QUIT BUTTON_RC_STOP
79 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \
80 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
81 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
82 #define SNAKE_QUIT (BUTTON_SELECT|BUTTON_MENU)
83 #define SNAKE_LEFT BUTTON_LEFT
84 #define SNAKE_RIGHT BUTTON_RIGHT
85 #define SNAKE_UP BUTTON_MENU
86 #define SNAKE_DOWN BUTTON_PLAY
87 #define SNAKE_PLAYPAUSE BUTTON_SELECT
89 #elif (CONFIG_KEYPAD == IAUDIO_X5M5_PAD)
90 #define SNAKE_QUIT BUTTON_POWER
91 #define SNAKE_LEFT BUTTON_LEFT
92 #define SNAKE_RIGHT BUTTON_RIGHT
93 #define SNAKE_UP BUTTON_UP
94 #define SNAKE_DOWN BUTTON_DOWN
95 #define SNAKE_PLAYPAUSE BUTTON_PLAY
97 #elif (CONFIG_KEYPAD == GIGABEAT_PAD)
98 #define SNAKE_QUIT BUTTON_POWER
99 #define SNAKE_LEFT BUTTON_LEFT
100 #define SNAKE_RIGHT BUTTON_RIGHT
101 #define SNAKE_UP BUTTON_UP
102 #define SNAKE_DOWN BUTTON_DOWN
103 #define SNAKE_PLAYPAUSE BUTTON_SELECT
105 #elif (CONFIG_KEYPAD == SANSA_E200_PAD) || \
106 (CONFIG_KEYPAD == SANSA_C200_PAD) || \
107 (CONFIG_KEYPAD == SANSA_CLIP_PAD) || \
108 (CONFIG_KEYPAD == SANSA_M200_PAD) || \
109 (CONFIG_KEYPAD == SANSA_CONNECT_PAD)
110 #define SNAKE_QUIT BUTTON_POWER
111 #define SNAKE_LEFT BUTTON_LEFT
112 #define SNAKE_RIGHT BUTTON_RIGHT
113 #define SNAKE_UP BUTTON_UP
114 #define SNAKE_DOWN BUTTON_DOWN
115 #define SNAKE_PLAYPAUSE BUTTON_SELECT
117 #elif (CONFIG_KEYPAD == SANSA_FUZE_PAD)
118 #define SNAKE_QUIT (BUTTON_HOME|BUTTON_REPEAT)
119 #define SNAKE_LEFT BUTTON_LEFT
120 #define SNAKE_RIGHT BUTTON_RIGHT
121 #define SNAKE_UP BUTTON_UP
122 #define SNAKE_DOWN BUTTON_DOWN
123 #define SNAKE_PLAYPAUSE BUTTON_SELECT
125 #elif (CONFIG_KEYPAD == IRIVER_H10_PAD)
126 #define SNAKE_QUIT BUTTON_POWER
127 #define SNAKE_LEFT BUTTON_LEFT
128 #define SNAKE_RIGHT BUTTON_RIGHT
129 #define SNAKE_UP BUTTON_SCROLL_UP
130 #define SNAKE_DOWN BUTTON_SCROLL_DOWN
131 #define SNAKE_PLAYPAUSE BUTTON_PLAY
133 #elif (CONFIG_KEYPAD == GIGABEAT_S_PAD) || \
134 (CONFIG_KEYPAD == SAMSUNG_YPR0_PAD)
135 #define SNAKE_QUIT BUTTON_BACK
136 #define SNAKE_LEFT BUTTON_LEFT
137 #define SNAKE_RIGHT BUTTON_RIGHT
138 #define SNAKE_UP BUTTON_UP
139 #define SNAKE_DOWN BUTTON_DOWN
140 #define SNAKE_PLAYPAUSE BUTTON_SELECT
142 #elif (CONFIG_KEYPAD == MROBE100_PAD)
143 #define SNAKE_QUIT BUTTON_POWER
144 #define SNAKE_LEFT BUTTON_LEFT
145 #define SNAKE_RIGHT BUTTON_RIGHT
146 #define SNAKE_UP BUTTON_UP
147 #define SNAKE_DOWN BUTTON_DOWN
148 #define SNAKE_PLAYPAUSE BUTTON_SELECT
150 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
151 #define SNAKE_QUIT BUTTON_RC_REC
152 #define SNAKE_LEFT BUTTON_RC_REW
153 #define SNAKE_RIGHT BUTTON_RC_FF
154 #define SNAKE_UP BUTTON_RC_VOL_UP
155 #define SNAKE_DOWN BUTTON_RC_VOL_DOWN
156 #define SNAKE_PLAYPAUSE BUTTON_RC_PLAY
158 #define SNAKE_RC_QUIT BUTTON_REC
160 #elif CONFIG_KEYPAD == CREATIVEZVM_PAD
161 #define SNAKE_QUIT BUTTON_BACK
162 #define SNAKE_LEFT BUTTON_LEFT
163 #define SNAKE_RIGHT BUTTON_RIGHT
164 #define SNAKE_UP BUTTON_UP
165 #define SNAKE_DOWN BUTTON_DOWN
166 #define SNAKE_PLAYPAUSE BUTTON_PLAY
168 #elif (CONFIG_KEYPAD == PHILIPS_HDD1630_PAD) || \
169 (CONFIG_KEYPAD == PHILIPS_HDD6330_PAD)
170 #define SNAKE_QUIT BUTTON_POWER
171 #define SNAKE_LEFT BUTTON_LEFT
172 #define SNAKE_RIGHT BUTTON_RIGHT
173 #define SNAKE_UP BUTTON_UP
174 #define SNAKE_DOWN BUTTON_DOWN
175 #define SNAKE_PLAYPAUSE BUTTON_MENU
177 #elif CONFIG_KEYPAD == PHILIPS_SA9200_PAD
178 #define SNAKE_QUIT BUTTON_POWER
179 #define SNAKE_LEFT BUTTON_PREV
180 #define SNAKE_RIGHT BUTTON_NEXT
181 #define SNAKE_UP BUTTON_UP
182 #define SNAKE_DOWN BUTTON_DOWN
183 #define SNAKE_PLAYPAUSE BUTTON_MENU
185 #elif CONFIG_KEYPAD == SAMSUNG_YH_PAD
186 #define SNAKE_QUIT BUTTON_REC
187 #define SNAKE_LEFT BUTTON_LEFT
188 #define SNAKE_RIGHT BUTTON_RIGHT
189 #define SNAKE_UP BUTTON_UP
190 #define SNAKE_DOWN BUTTON_DOWN
191 #define SNAKE_PLAYPAUSE BUTTON_PLAY
193 #elif CONFIG_KEYPAD == MROBE500_PAD
194 #define SNAKE_QUIT BUTTON_POWER
195 #define SNAKE_RC_QUIT BUTTON_RC_DOWN
197 #elif (CONFIG_KEYPAD == ONDAVX747_PAD)
198 #define SNAKE_QUIT BUTTON_POWER
200 #elif (CONFIG_KEYPAD == ONDAVX777_PAD)
201 #define SNAKE_QUIT BUTTON_POWER
203 #elif CONFIG_KEYPAD == COWON_D2_PAD
204 #define SNAKE_QUIT BUTTON_POWER
206 #elif CONFIG_KEYPAD == PBELL_VIBE500_PAD
207 #define SNAKE_QUIT BUTTON_REC
208 #define SNAKE_LEFT BUTTON_PREV
209 #define SNAKE_RIGHT BUTTON_NEXT
210 #define SNAKE_UP BUTTON_UP
211 #define SNAKE_DOWN BUTTON_DOWN
212 #define SNAKE_PLAYPAUSE BUTTON_PLAY
214 #elif CONFIG_KEYPAD == MPIO_HD200_PAD
215 #define SNAKE_QUIT (BUTTON_REC|BUTTON_PLAY)
216 #define SNAKE_LEFT BUTTON_VOL_DOWN
217 #define SNAKE_RIGHT BUTTON_VOL_UP
218 #define SNAKE_UP BUTTON_REW
219 #define SNAKE_DOWN BUTTON_FF
220 #define SNAKE_PLAYPAUSE BUTTON_PLAY
222 #elif CONFIG_KEYPAD == MPIO_HD300_PAD
223 #define SNAKE_QUIT (BUTTON_MENU|BUTTON_REPEAT)
224 #define SNAKE_LEFT BUTTON_REW
225 #define SNAKE_RIGHT BUTTON_FF
226 #define SNAKE_UP BUTTON_UP
227 #define SNAKE_DOWN BUTTON_DOWN
228 #define SNAKE_PLAYPAUSE BUTTON_PLAY
230 #elif CONFIG_KEYPAD == SANSA_FUZEPLUS_PAD
231 #define SNAKE_QUIT BUTTON_POWER
232 #define SNAKE_LEFT BUTTON_LEFT
233 #define SNAKE_RIGHT BUTTON_RIGHT
234 #define SNAKE_UP BUTTON_UP
235 #define SNAKE_DOWN BUTTON_DOWN
236 #define SNAKE_PLAYPAUSE BUTTON_PLAYPAUSE
238 #elif (CONFIG_KEYPAD == HM60X_PAD) || \
239 (CONFIG_KEYPAD == HM801_PAD)
240 #define SNAKE_QUIT BUTTON_POWER
241 #define SNAKE_LEFT BUTTON_LEFT
242 #define SNAKE_RIGHT BUTTON_RIGHT
243 #define SNAKE_UP BUTTON_UP
244 #define SNAKE_DOWN BUTTON_DOWN
245 #define SNAKE_PLAYPAUSE BUTTON_SELECT
247 #else
248 #error No keymap defined!
249 #endif
251 #ifdef HAVE_TOUCHSCREEN
252 #ifndef SNAKE_QUIT
253 #define SNAKE_QUIT BUTTON_TOPLEFT
254 #endif
255 #ifndef SNAKE_LEFT
256 #define SNAKE_LEFT BUTTON_MIDLEFT
257 #endif
258 #ifndef SNAKE_RIGHT
259 #define SNAKE_RIGHT BUTTON_MIDRIGHT
260 #endif
261 #ifndef SNAKE_UP
262 #define SNAKE_UP BUTTON_TOPMIDDLE
263 #endif
264 #ifndef SNAKE_DOWN
265 #define SNAKE_DOWN BUTTON_BOTTOMMIDDLE
266 #endif
267 #ifndef SNAKE_PLAYPAUSE
268 #define SNAKE_PLAYPAUSE BUTTON_CENTER
269 #endif
270 #endif
272 #define BOARD_WIDTH (LCD_WIDTH/4)
273 #define BOARD_HEIGHT (LCD_HEIGHT/4)
275 #define CONFIG_FILE_NAME "snake.cfg"
276 #define SCORE_FILE PLUGIN_GAMES_DATA_DIR "/snake.score"
277 #define NUM_SCORES 5
279 static int board[BOARD_WIDTH][BOARD_HEIGHT],snakelength;
280 static unsigned int score, level = 1;
281 static int dir;
282 static bool apple, dead, ingame;
283 static struct highscore highscores[NUM_SCORES];
285 static struct configdata config[] = {
286 {TYPE_INT, 1, 9, { .int_p = &level }, "level", NULL},
289 static void snake_die (void)
291 rb->lcd_clear_display();
292 rb->lcd_puts(0,0,"Oops...");
293 rb->lcd_putsf(0,1,"Your score: %d",score);
294 if (highscore_update(score, level, "", highscores, NUM_SCORES) == 0) {
295 rb->lcd_puts(0,2,"New High Score!");
297 else {
298 rb->lcd_putsf(0,2,"High Score: %d", highscores[0].score);
300 rb->lcd_update();
301 rb->sleep(3*HZ);
302 dead=true;
305 static void snake_colission (short x, short y)
307 if (x==BOARD_WIDTH || x<0 || y==BOARD_HEIGHT || y<0) {
308 snake_die();
309 return;
311 switch (board[x][y]) {
312 case 0:
313 break;
314 case -1:
315 snakelength+=2;
316 score+=level;
317 apple=false;
318 break;
319 default:
320 snake_die();
321 break;
325 static void snake_move_head (short x, short y)
327 switch (dir) {
328 case 0:
329 y-=1;
330 break;
331 case 1:
332 x+=1;
333 break;
334 case 2:
335 y+=1;
336 break;
337 case 3:
338 x-=1;
339 break;
341 snake_colission (x,y);
342 if (dead)
343 return;
344 board[x][y]=1;
345 rb->lcd_fillrect(x*4,y*4,4,4);
348 static void snake_redraw (void)
350 short x,y;
351 rb->lcd_clear_display();
352 for (x=0; x<BOARD_WIDTH; x++) {
353 for (y=0; y<BOARD_HEIGHT; y++) {
354 switch (board[x][y]) {
355 case -1:
356 rb->lcd_fillrect((x*4)+1,y*4,2,4);
357 rb->lcd_fillrect(x*4,(y*4)+1,4,2);
358 break;
359 case 0:
360 break;
361 default:
362 rb->lcd_fillrect(x*4,y*4,4,4);
363 break;
367 rb->lcd_update();
370 static void snake_frame (void)
372 short x,y,head=0;
373 for (x=0; x<BOARD_WIDTH; x++) {
374 for (y=0; y<BOARD_HEIGHT; y++) {
375 switch (board[x][y]) {
376 case 1:
377 if (!head) {
378 snake_move_head(x,y);
379 if (dead)
380 return;
381 board[x][y]++;
382 head=1;
384 break;
385 case 0:
386 break;
387 case -1:
388 break;
389 default:
390 if (board[x][y]==snakelength) {
391 board[x][y]=0;
392 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
393 rb->lcd_fillrect(x*4,y*4,4,4);
394 rb->lcd_set_drawmode(DRMODE_SOLID);
396 else
397 board[x][y]++;
398 break;
402 rb->lcd_update();
405 static void snake_game_init(void) {
406 short x,y;
407 rb->lcd_clear_display();
409 for (x=0; x<BOARD_WIDTH; x++) {
410 for (y=0; y<BOARD_HEIGHT; y++) {
411 board[x][y]=0;
414 apple=false;
415 dead=false;
416 snakelength=4;
417 score=0;
418 dir=1;
419 board[11][7]=1;
422 static int snake_menu_cb(int action, const struct menu_item_ex *this_item)
424 if(action == ACTION_REQUEST_MENUITEM
425 && !ingame && ((intptr_t)this_item)==0)
426 return ACTION_EXIT_MENUITEM;
427 return action;
430 static int snake_game_menu(void)
432 MENUITEM_STRINGLIST(main_menu,"Snake Menu",snake_menu_cb,
433 "Resume Game",
434 "Start New Game",
435 "Snake Speed",
436 "High Score",
437 "Playback Control",
438 "Quit");
439 int selected = 0;
441 rb->button_clear_queue();
443 while (true) {
444 switch (rb->do_menu(&main_menu, &selected, NULL, false)) {
445 case 0:
446 snake_redraw();
447 return 0;
448 case 1:
449 snake_game_init();
450 return 0;
451 case 2:
452 rb->set_int("Snake Speed", "", UNIT_INT, &level,
453 NULL, 1, 1, 9, NULL);
454 break;
455 case 3:
456 highscore_show(-1, highscores, NUM_SCORES, true);
457 rb->lcd_setfont(FONT_UI);
458 break;
459 case 4:
460 playback_control(NULL);
461 break;
462 case 5:
463 return 1;
464 case MENU_ATTACHED_USB:
465 return 1;
466 default:
467 break;
472 static int snake_game_loop (void) {
473 int button;
474 short x,y;
475 bool pause = false;
477 if (snake_game_menu())
478 return 1;
480 ingame = true;
481 while (true) {
482 if (!pause) {
483 snake_frame();
484 if (dead) {
485 ingame = false;
486 return 0;
488 if (!apple) {
489 do {
490 x=rb->rand() % BOARD_WIDTH;
491 y=rb->rand() % BOARD_HEIGHT;
492 } while (board[x][y]);
493 apple=true;
494 board[x][y]=-1;
495 rb->lcd_fillrect((x*4)+1,y*4,2,4);
496 rb->lcd_fillrect(x*4,(y*4)+1,4,2);
499 rb->sleep(HZ/level);
502 button=rb->button_get(false);
504 #ifdef HAS_BUTTON_HOLD
505 if (rb->button_hold() && !pause)
506 button = SNAKE_PLAYPAUSE;
507 #endif
508 switch (button) {
509 case SNAKE_UP:
510 if (dir!=2) dir=0;
511 break;
512 case SNAKE_RIGHT:
513 if (dir!=3) dir=1;
514 break;
515 case SNAKE_DOWN:
516 if (dir!=0) dir=2;
517 break;
518 case SNAKE_LEFT:
519 if (dir!=1) dir=3;
520 break;
521 case SNAKE_PLAYPAUSE:
522 pause = !pause;
523 if (pause)
524 rb->splash (HZ, "Paused");
525 else
526 snake_redraw();
527 break;
528 #ifdef SNAKE_RC_QUIT
529 case SNAKE_RC_QUIT:
530 #endif
531 case SNAKE_QUIT:
532 return 0;
533 break;
534 default:
535 if (rb->default_event_handler (button) == SYS_USB_CONNECTED)
536 return 1;
537 break;
542 enum plugin_status plugin_start(const void* parameter)
544 (void)parameter;
546 configfile_load(CONFIG_FILE_NAME, config, 1, 0);
547 highscore_load(SCORE_FILE, highscores, NUM_SCORES);
548 rb->lcd_clear_display();
549 ingame = false;
550 while(snake_game_loop() == 0)
552 configfile_save(CONFIG_FILE_NAME, config, 1, 0);
553 highscore_save(SCORE_FILE, highscores, NUM_SCORES);
554 return PLUGIN_OK;