A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita
audio
rust
zig
deno
mpris
rockbox
mpd
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2003 Mat Holton
11 *
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.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22/*
23Snake2!
24
25Board consists of a WIDTHxHEIGHT grid. If board element is 0 then nothing is
26there otherwise it is part of the snake or a wall.
27
28Head and Tail are stored
29
30*/
31
32#include "plugin.h"
33
34#include "lib/highscore.h"
35#include "lib/playback_control.h"
36
37
38
39#define WIDTH 28
40#define HEIGHT 16
41
42#if (LCD_WIDTH >= 160) && (LCD_HEIGHT >= 128) \
43 || (LCD_WIDTH >= 128) && (LCD_HEIGHT >= 96) && (LCD_DEPTH >= 16)
44#include "pluginbitmaps/snake2_header1.h"
45#include "pluginbitmaps/snake2_header2.h"
46#include "pluginbitmaps/snake2_left.h"
47#include "pluginbitmaps/snake2_right.h"
48#include "pluginbitmaps/snake2_bottom.h"
49#define BMPHEIGHT_snake2_header BMPHEIGHT_snake2_header1
50#define BMPWIDTH_snake2_header BMPWIDTH_snake2_header1
51#endif
52
53#if (LCD_WIDTH >= 640) && (LCD_HEIGHT >= 480)
54 #define MULTIPLIER 20 /*Modifier for porting on other screens*/
55 #define MODIFIER_1 20
56 #define MODIFIER_2 16
57 #define CENTER_X 40
58 #define CENTER_Y 110
59 #define TOP_X1 68 /* x-coord of the upperleft item (game type) */
60 #define TOP_X2 562 /* x-coord of the upperright item (maze type) */
61 #define TOP_X3 84 /* x-coord of the lowerleft item (speed) */
62 #define TOP_X4 548 /* x-coord of the lowerright item (hi-score) */
63 #define TOP_Y1 8 /* y-coord of the top row of items */
64 #define TOP_Y2 50 /* y-coord of the bottom row of items */
65#elif (LCD_WIDTH >= 360) && (LCD_HEIGHT >= 400)
66 #define MULTIPLIER 12 /*Modifier for porting on other screens*/
67 #define MODIFIER_1 12
68 #define MODIFIER_2 10
69 #define CENTER_X 12
70 #define CENTER_Y 40
71 #define TOP_X1 34 /* x-coord of the upperleft item (game type) */
72 #define TOP_X2 320 /* x-coord of the upperright item (maze type) */
73 #define TOP_X3 42 /* x-coord of the lowerleft item (speed) */
74 #define TOP_X4 314 /* x-coord of the lowerright item (hi-score) */
75 #define TOP_Y1 4 /* y-coord of the top row of items */
76 #define TOP_Y2 25 /* y-coord of the bottom row of items */
77#elif (LCD_WIDTH >= 320) && (LCD_HEIGHT >= 240)
78 #define MULTIPLIER 10 /*Modifier for porting on other screens*/
79 #define MODIFIER_1 10
80 #define MODIFIER_2 8
81 #define CENTER_X 20
82 #define CENTER_Y 55
83 #define TOP_X1 34 /* x-coord of the upperleft item (game type) */
84 #define TOP_X2 281 /* x-coord of the upperright item (maze type) */
85 #define TOP_X3 42 /* x-coord of the lowerleft item (speed) */
86 #define TOP_X4 274 /* x-coord of the lowerright item (hi-score) */
87 #define TOP_Y1 4 /* y-coord of the top row of items */
88 #define TOP_Y2 25 /* y-coord of the bottom row of items */
89#elif (LCD_WIDTH >= 240) && (LCD_HEIGHT >= 168)
90 #define MULTIPLIER 8
91 #define MODIFIER_1 8
92 #define MODIFIER_2 6
93 #define CENTER_X 8
94 #define CENTER_Y 34
95 #define TOP_X1 34
96 #define TOP_X2 201
97 #define TOP_X3 42
98 #define TOP_X4 194
99 #define TOP_Y1 4
100 #define TOP_Y2 25
101#elif (LCD_WIDTH >= 220) && (LCD_HEIGHT >= 176)
102 #define MULTIPLIER 7
103 #define MODIFIER_1 7
104 #define MODIFIER_2 5
105 #define CENTER_X 12
106 #define CENTER_Y 46
107 #define TOP_X1 34
108 #define TOP_X2 181
109 #define TOP_X3 42
110 #define TOP_X4 174
111 #define TOP_Y1 4
112 #define TOP_Y2 25
113#elif (LCD_WIDTH >= 176) && (LCD_HEIGHT >= 132)
114 #define MULTIPLIER 5
115 #define MODIFIER_1 5
116 #define MODIFIER_2 3
117 #define CENTER_X 18
118 #define CENTER_Y 40
119 #define TOP_X1 34
120 #define TOP_X2 137
121 #define TOP_X3 42
122 #define TOP_X4 130
123 #define TOP_Y1 4
124 #define TOP_Y2 25
125#elif (LCD_WIDTH >= 160) && (LCD_HEIGHT >= 128)
126 #define MULTIPLIER 5
127 #define MODIFIER_1 5
128 #define MODIFIER_2 3
129 #define CENTER_X 10
130 #define CENTER_Y 38
131 #define TOP_X1 34
132 #define TOP_X2 121
133 #define TOP_X3 42
134 #define TOP_X4 114
135 #define TOP_Y1 4
136 #define TOP_Y2 25
137#elif (LCD_WIDTH >= 128) && (LCD_HEIGHT >= 96) && (LCD_DEPTH >= 16)
138 #define MULTIPLIER 4
139 #define MODIFIER_1 4
140 #define MODIFIER_2 2
141 #define CENTER_X 8
142 #define CENTER_Y 24
143 #define TOP_X1 28
144 #define TOP_X2 96
145 #define TOP_X3 44
146 #define TOP_X4 83
147 #define TOP_Y1 2
148 #define TOP_Y2 13
149#elif (LCD_WIDTH == 96) && (LCD_HEIGHT == 96)
150 #define MULTIPLIER 3
151 #define MODIFIER_1 4
152 #define MODIFIER_2 2
153 #define CENTER_X 6
154 #define CENTER_Y 12
155#else
156 #define MULTIPLIER 4
157 #define MODIFIER_1 4
158 #define MODIFIER_2 2
159 #define CENTER_X 0
160 #define CENTER_Y 0
161
162#endif
163
164/* variable button definitions */
165#if (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
166 (CONFIG_KEYPAD == IRIVER_H300_PAD)
167#define SNAKE2_LEFT BUTTON_LEFT
168#define SNAKE2_RIGHT BUTTON_RIGHT
169#define SNAKE2_UP BUTTON_UP
170#define SNAKE2_DOWN BUTTON_DOWN
171#define SNAKE2_QUIT BUTTON_OFF
172#define SNAKE2_PLAYPAUSE BUTTON_ON
173#define SNAKE2_PLAYPAUSE_TEXT "Play"
174
175#define SNAKE2_RC_QUIT BUTTON_RC_STOP
176
177#elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \
178 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
179 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
180#define SNAKE2_LEFT BUTTON_LEFT
181#define SNAKE2_RIGHT BUTTON_RIGHT
182#define SNAKE2_UP BUTTON_MENU
183#define SNAKE2_DOWN BUTTON_PLAY
184#define SNAKE2_QUIT (BUTTON_SELECT | BUTTON_REPEAT)
185#define SNAKE2_PLAYPAUSE (BUTTON_SELECT | BUTTON_REL)
186#define SNAKE2_PLAYPAUSE_TEXT "Select"
187
188#elif (CONFIG_KEYPAD == IAUDIO_X5M5_PAD)
189#define SNAKE2_LEFT BUTTON_LEFT
190#define SNAKE2_RIGHT BUTTON_RIGHT
191#define SNAKE2_UP BUTTON_UP
192#define SNAKE2_DOWN BUTTON_DOWN
193#define SNAKE2_QUIT BUTTON_POWER
194#define SNAKE2_PLAYPAUSE BUTTON_SELECT
195#define SNAKE2_PLAYPAUSE_TEXT "Select"
196
197#elif (CONFIG_KEYPAD == GIGABEAT_PAD)
198#define SNAKE2_LEFT BUTTON_LEFT
199#define SNAKE2_RIGHT BUTTON_RIGHT
200#define SNAKE2_UP BUTTON_UP
201#define SNAKE2_DOWN BUTTON_DOWN
202#define SNAKE2_QUIT BUTTON_POWER
203#define SNAKE2_PLAYPAUSE BUTTON_SELECT
204#define SNAKE2_PLAYPAUSE_TEXT "Select"
205
206#elif (CONFIG_KEYPAD == SANSA_E200_PAD) || \
207(CONFIG_KEYPAD == SANSA_C200_PAD) || \
208(CONFIG_KEYPAD == SANSA_CONNECT_PAD) || \
209(CONFIG_KEYPAD == SANSA_CLIP_PAD) || \
210(CONFIG_KEYPAD == SANSA_M200_PAD)
211#define SNAKE2_LEFT BUTTON_LEFT
212#define SNAKE2_RIGHT BUTTON_RIGHT
213#define SNAKE2_UP BUTTON_UP
214#define SNAKE2_DOWN BUTTON_DOWN
215#define SNAKE2_QUIT BUTTON_POWER
216#define SNAKE2_PLAYPAUSE BUTTON_SELECT
217#define SNAKE2_PLAYPAUSE_TEXT "Select"
218
219#elif (CONFIG_KEYPAD == SANSA_FUZE_PAD)
220#define SNAKE2_LEFT BUTTON_LEFT
221#define SNAKE2_RIGHT BUTTON_RIGHT
222#define SNAKE2_UP BUTTON_UP
223#define SNAKE2_DOWN BUTTON_DOWN
224#define SNAKE2_QUIT (BUTTON_HOME|BUTTON_REPEAT)
225#define SNAKE2_PLAYPAUSE BUTTON_SELECT
226#define SNAKE2_PLAYPAUSE_TEXT "Select"
227
228#elif (CONFIG_KEYPAD == IRIVER_H10_PAD)
229#define SNAKE2_LEFT BUTTON_LEFT
230#define SNAKE2_RIGHT BUTTON_RIGHT
231#define SNAKE2_UP BUTTON_SCROLL_UP
232#define SNAKE2_DOWN BUTTON_SCROLL_DOWN
233#define SNAKE2_QUIT BUTTON_POWER
234#define SNAKE2_PLAYPAUSE BUTTON_FF
235#define SNAKE2_PLAYPAUSE_TEXT "FF"
236
237#elif (CONFIG_KEYPAD == GIGABEAT_S_PAD) || \
238 (CONFIG_KEYPAD == SAMSUNG_YPR0_PAD)
239#define SNAKE2_LEFT BUTTON_LEFT
240#define SNAKE2_RIGHT BUTTON_RIGHT
241#define SNAKE2_UP BUTTON_UP
242#define SNAKE2_DOWN BUTTON_DOWN
243#define SNAKE2_QUIT BUTTON_BACK
244#define SNAKE2_PLAYPAUSE BUTTON_SELECT
245#define SNAKE2_PLAYPAUSE_TEXT "Select"
246
247#elif (CONFIG_KEYPAD == MROBE100_PAD)
248#define SNAKE2_LEFT BUTTON_LEFT
249#define SNAKE2_RIGHT BUTTON_RIGHT
250#define SNAKE2_UP BUTTON_UP
251#define SNAKE2_DOWN BUTTON_DOWN
252#define SNAKE2_QUIT BUTTON_POWER
253#define SNAKE2_PLAYPAUSE BUTTON_SELECT
254#define SNAKE2_PLAYPAUSE_TEXT "Select"
255
256#elif CONFIG_KEYPAD == IAUDIO_M3_PAD
257#define SNAKE2_LEFT BUTTON_RC_REW
258#define SNAKE2_RIGHT BUTTON_RC_FF
259#define SNAKE2_UP BUTTON_RC_VOL_UP
260#define SNAKE2_DOWN BUTTON_RC_VOL_DOWN
261#define SNAKE2_QUIT BUTTON_RC_REC
262#define SNAKE2_PLAYPAUSE BUTTON_RC_PLAY
263#define SNAKE2_PLAYPAUSE_TEXT "Play"
264
265#elif (CONFIG_KEYPAD == COWON_D2_PAD)
266#define SNAKE2_QUIT BUTTON_POWER
267
268#elif CONFIG_KEYPAD == CREATIVEZVM_PAD
269#define SNAKE2_LEFT BUTTON_LEFT
270#define SNAKE2_RIGHT BUTTON_RIGHT
271#define SNAKE2_UP BUTTON_UP
272#define SNAKE2_DOWN BUTTON_DOWN
273#define SNAKE2_QUIT BUTTON_BACK
274#define SNAKE2_PLAYPAUSE BUTTON_PLAY
275#define SNAKE2_PLAYPAUSE_TEXT "Play"
276
277#elif CONFIG_KEYPAD == CREATIVE_ZENXFI3_PAD
278#define SNAKE2_LEFT BUTTON_BACK
279#define SNAKE2_RIGHT BUTTON_MENU
280#define SNAKE2_UP BUTTON_UP
281#define SNAKE2_DOWN BUTTON_DOWN
282#define SNAKE2_QUIT BUTTON_POWER
283#define SNAKE2_PLAYPAUSE (BUTTON_PLAY|BUTTON_REL)
284#define SNAKE2_PLAYPAUSE_TEXT "Play"
285
286#elif (CONFIG_KEYPAD == PHILIPS_HDD1630_PAD) || \
287 (CONFIG_KEYPAD == PHILIPS_HDD6330_PAD)
288#define SNAKE2_LEFT BUTTON_LEFT
289#define SNAKE2_RIGHT BUTTON_RIGHT
290#define SNAKE2_UP BUTTON_UP
291#define SNAKE2_DOWN BUTTON_DOWN
292#define SNAKE2_QUIT BUTTON_POWER
293#define SNAKE2_PLAYPAUSE BUTTON_VIEW
294#define SNAKE2_PLAYPAUSE_TEXT "View"
295
296#elif CONFIG_KEYPAD == PHILIPS_SA9200_PAD
297#define SNAKE2_LEFT BUTTON_PREV
298#define SNAKE2_RIGHT BUTTON_NEXT
299#define SNAKE2_UP BUTTON_UP
300#define SNAKE2_DOWN BUTTON_DOWN
301#define SNAKE2_QUIT BUTTON_POWER
302#define SNAKE2_PLAYPAUSE BUTTON_RIGHT
303#define SNAKE2_PLAYPAUSE_TEXT "Right"
304
305#elif (CONFIG_KEYPAD == ONDAVX747_PAD) || \
306(CONFIG_KEYPAD == ONDAVX777_PAD) || \
307CONFIG_KEYPAD == MROBE500_PAD
308#define SNAKE2_QUIT BUTTON_POWER
309
310#elif (CONFIG_KEYPAD == SAMSUNG_YH820_PAD) || \
311 (CONFIG_KEYPAD == SAMSUNG_YH92X_PAD)
312#define SNAKE2_LEFT BUTTON_LEFT
313#define SNAKE2_RIGHT BUTTON_RIGHT
314#define SNAKE2_UP BUTTON_UP
315#define SNAKE2_DOWN BUTTON_DOWN
316#define SNAKE2_QUIT BUTTON_REW
317#define SNAKE2_PLAYPAUSE BUTTON_PLAY
318#define SNAKE2_PLAYPAUSE_TEXT "Play"
319
320#elif CONFIG_KEYPAD == PBELL_VIBE500_PAD
321#define SNAKE2_LEFT BUTTON_PREV
322#define SNAKE2_RIGHT BUTTON_NEXT
323#define SNAKE2_UP BUTTON_UP
324#define SNAKE2_DOWN BUTTON_DOWN
325#define SNAKE2_QUIT BUTTON_REC
326#define SNAKE2_PLAYPAUSE BUTTON_PLAY
327#define SNAKE2_PLAYPAUSE_TEXT "Play"
328
329#elif CONFIG_KEYPAD == MPIO_HD200_PAD
330#define SNAKE2_LEFT BUTTON_VOL_DOWN
331#define SNAKE2_RIGHT BUTTON_VOL_UP
332#define SNAKE2_UP BUTTON_REW
333#define SNAKE2_DOWN BUTTON_FF
334#define SNAKE2_QUIT (BUTTON_REC | BUTTON_PLAY)
335#define SNAKE2_PLAYPAUSE BUTTON_PLAY
336#define SNAKE2_PLAYPAUSE_TEXT "Play"
337
338#elif CONFIG_KEYPAD == MPIO_HD300_PAD
339#define SNAKE2_LEFT BUTTON_REW
340#define SNAKE2_RIGHT BUTTON_FF
341#define SNAKE2_UP BUTTON_UP
342#define SNAKE2_DOWN BUTTON_DOWN
343#define SNAKE2_QUIT (BUTTON_MENU|BUTTON_REPEAT)
344#define SNAKE2_PLAYPAUSE BUTTON_PLAY
345#define SNAKE2_PLAYPAUSE_TEXT "Play"
346
347#elif CONFIG_KEYPAD == SANSA_FUZEPLUS_PAD
348#define SNAKE2_LEFT BUTTON_LEFT
349#define SNAKE2_RIGHT BUTTON_RIGHT
350#define SNAKE2_UP BUTTON_UP
351#define SNAKE2_DOWN BUTTON_DOWN
352#define SNAKE2_QUIT BUTTON_POWER
353#define SNAKE2_PLAYPAUSE BUTTON_PLAYPAUSE
354#define SNAKE2_PLAYPAUSE_TEXT "Play-Pause"
355
356#elif (CONFIG_KEYPAD == HM60X_PAD) || \
357 (CONFIG_KEYPAD == HM801_PAD)
358#define SNAKE2_LEFT BUTTON_LEFT
359#define SNAKE2_RIGHT BUTTON_RIGHT
360#define SNAKE2_UP BUTTON_UP
361#define SNAKE2_DOWN BUTTON_DOWN
362#define SNAKE2_QUIT BUTTON_POWER
363#define SNAKE2_PLAYPAUSE BUTTON_SELECT
364#define SNAKE2_PLAYPAUSE_TEXT "Select"
365
366#elif CONFIG_KEYPAD == SONY_NWZ_PAD
367#define SNAKE2_LEFT BUTTON_LEFT
368#define SNAKE2_RIGHT BUTTON_RIGHT
369#define SNAKE2_UP BUTTON_UP
370#define SNAKE2_DOWN BUTTON_DOWN
371#define SNAKE2_QUIT BUTTON_BACK
372#define SNAKE2_PLAYPAUSE BUTTON_PLAY
373#define SNAKE2_PLAYPAUSE_TEXT "Play"
374
375#elif CONFIG_KEYPAD == CREATIVE_ZEN_PAD
376#define SNAKE2_LEFT BUTTON_LEFT
377#define SNAKE2_RIGHT BUTTON_RIGHT
378#define SNAKE2_UP BUTTON_UP
379#define SNAKE2_DOWN BUTTON_DOWN
380#define SNAKE2_QUIT BUTTON_BACK
381#define SNAKE2_PLAYPAUSE BUTTON_PLAYPAUSE
382#define SNAKE2_PLAYPAUSE_TEXT "Play/Pause"
383
384#elif (CONFIG_KEYPAD == DX50_PAD)
385#define SNAKE2_QUIT (BUTTON_POWER|BUTTON_REL)
386#define SNAKE2_LEFT BUTTON_LEFT
387#define SNAKE2_RIGHT BUTTON_PLAY
388#define SNAKE2_UP BUTTON_VOL_UP
389#define SNAKE2_DOWN BUTTON_VOL_DOWN
390#define SNAKE2_PLAYPAUSE BUTTON_RIGHT
391#define SNAKE2_PLAYPAUSE_TEXT "Right"
392
393#elif CONFIG_KEYPAD == CREATIVE_ZENXFI2_PAD
394#define SNAKE2_QUIT BUTTON_POWER
395#define SNAKE2_PLAYPAUSE BUTTON_MENU
396#define SNAKE2_PLAYPAUSE_TEXT "Menu"
397
398#elif CONFIG_KEYPAD == AGPTEK_ROCKER_PAD
399#define SNAKE2_LEFT BUTTON_LEFT
400#define SNAKE2_RIGHT BUTTON_RIGHT
401#define SNAKE2_UP BUTTON_UP
402#define SNAKE2_DOWN BUTTON_DOWN
403#define SNAKE2_QUIT BUTTON_POWER
404#define SNAKE2_PLAYPAUSE BUTTON_SELECT
405#define SNAKE2_PLAYPAUSE_TEXT "Select"
406
407#elif (CONFIG_KEYPAD == XDUOO_X3_PAD)
408#define SNAKE2_LEFT BUTTON_PREV
409#define SNAKE2_RIGHT BUTTON_NEXT
410#define SNAKE2_UP BUTTON_HOME
411#define SNAKE2_DOWN BUTTON_OPTION
412#define SNAKE2_QUIT BUTTON_POWER
413#define SNAKE2_PLAYPAUSE BUTTON_PLAY
414#define SNAKE2_PLAYPAUSE_TEXT "PLAY"
415
416#elif (CONFIG_KEYPAD == XDUOO_X3II_PAD) || (CONFIG_KEYPAD == XDUOO_X20_PAD)
417#define SNAKE2_LEFT BUTTON_PREV
418#define SNAKE2_RIGHT BUTTON_NEXT
419#define SNAKE2_UP BUTTON_HOME
420#define SNAKE2_DOWN BUTTON_OPTION
421#define SNAKE2_QUIT BUTTON_POWER
422#define SNAKE2_PLAYPAUSE BUTTON_PLAY
423#define SNAKE2_PLAYPAUSE_TEXT "PLAY"
424
425#elif (CONFIG_KEYPAD == FIIO_M3K_LINUX_PAD)
426#define SNAKE2_LEFT BUTTON_PREV
427#define SNAKE2_RIGHT BUTTON_NEXT
428#define SNAKE2_UP BUTTON_HOME
429#define SNAKE2_DOWN BUTTON_OPTION
430#define SNAKE2_QUIT BUTTON_POWER
431#define SNAKE2_PLAYPAUSE BUTTON_PLAY
432#define SNAKE2_PLAYPAUSE_TEXT "PLAY"
433
434#elif (CONFIG_KEYPAD == IHIFI_770_PAD) || (CONFIG_KEYPAD == IHIFI_800_PAD)
435#define SNAKE2_LEFT BUTTON_HOME
436#define SNAKE2_RIGHT BUTTON_VOL_DOWN
437#define SNAKE2_UP BUTTON_PREV
438#define SNAKE2_DOWN BUTTON_NEXT
439#define SNAKE2_QUIT BUTTON_POWER
440#define SNAKE2_PLAYPAUSE BUTTON_PLAY
441#define SNAKE2_PLAYPAUSE_TEXT "PLAY"
442
443#elif (CONFIG_KEYPAD == EROSQ_PAD)
444#define SNAKE2_LEFT BUTTON_SCROLL_BACK
445#define SNAKE2_RIGHT BUTTON_SCROLL_FWD
446#define SNAKE2_UP BUTTON_PREV
447#define SNAKE2_DOWN BUTTON_NEXT
448#define SNAKE2_QUIT BUTTON_POWER
449#define SNAKE2_PLAYPAUSE BUTTON_PLAY
450#define SNAKE2_PLAYPAUSE_TEXT "PLAY"
451
452#elif CONFIG_KEYPAD == FIIO_M3K_PAD
453#define SNAKE2_LEFT BUTTON_LEFT
454#define SNAKE2_RIGHT BUTTON_RIGHT
455#define SNAKE2_UP BUTTON_UP
456#define SNAKE2_DOWN BUTTON_DOWN
457#define SNAKE2_QUIT BUTTON_POWER
458#define SNAKE2_PLAYPAUSE BUTTON_PLAY
459#define SNAKE2_PLAYPAUSE_TEXT "PLAY"
460
461#elif CONFIG_KEYPAD == SDL_PAD
462/* use touchscreen */
463
464#elif CONFIG_KEYPAD == SHANLING_Q1_PAD
465/* use touchscreen */
466
467#elif CONFIG_KEYPAD == MA_PAD
468#define SNAKE2_LEFT BUTTON_LEFT
469#define SNAKE2_RIGHT BUTTON_RIGHT
470#define SNAKE2_UP BUTTON_UP
471#define SNAKE2_DOWN BUTTON_DOWN
472#define SNAKE2_QUIT BUTTON_BACK
473#define SNAKE2_PLAYPAUSE BUTTON_PLAY
474#define SNAKE2_PLAYPAUSE_TEXT "PLAY"
475
476#elif (CONFIG_KEYPAD == RG_NANO_PAD)
477#define SNAKE2_LEFT BUTTON_LEFT
478#define SNAKE2_RIGHT BUTTON_RIGHT
479#define SNAKE2_UP BUTTON_UP
480#define SNAKE2_DOWN BUTTON_DOWN
481#define SNAKE2_QUIT BUTTON_START
482#define SNAKE2_PLAYPAUSE BUTTON_A
483#define SNAKE2_PLAYPAUSE_TEXT "A"
484
485#else
486#error No keymap defined!
487#endif
488
489#ifdef HAVE_TOUCHSCREEN
490#ifndef SNAKE2_LEFT
491#define SNAKE2_LEFT BUTTON_MIDLEFT
492#endif
493#ifndef SNAKE2_RIGHT
494#define SNAKE2_RIGHT BUTTON_MIDRIGHT
495#endif
496#ifndef SNAKE2_UP
497#define SNAKE2_UP BUTTON_TOPMIDDLE
498#endif
499#ifndef SNAKE2_DOWN
500#define SNAKE2_DOWN BUTTON_BOTTOMMIDDLE
501#endif
502#ifndef SNAKE2_QUIT
503#define SNAKE2_QUIT BUTTON_TOPLEFT
504#endif
505#ifndef SNAKE2_PLAYPAUSE
506#define SNAKE2_PLAYPAUSE BUTTON_CENTER
507#endif
508#ifndef SNAKE2_PLAYPAUSE_TEXT
509#define SNAKE2_PLAYPAUSE_TEXT "CENTER"
510#endif
511#endif
512
513static int max_levels = 0;
514static char (*level_cache)[HEIGHT][WIDTH];
515
516/*Board itself - 2D int array*/
517static int board[WIDTH][HEIGHT];
518/*
519 Buffer for sorting movement (in case user presses two movements during a
520 single frame
521*/
522static int ardirectionbuffer[2];
523static int score;
524static int applex;
525static int appley;
526static int dir;
527static int frames;
528static int apple;
529static int level = 4, speed = 5,dead = 0, quit = 0;
530static int sillydir = 0, num_levels = 0;
531static int level_from_file = 0;
532static int headx, heady, tailx, taily, applecountdown = 5;
533static int game_type = 0;
534static int num_apples_to_get=1;
535static int num_apples_to_got=0;
536static int game_b_level=0;
537static int applecount=0;
538/* used for string width, height for orientation purposes */
539static int strwdt, strhgt;
540static char strbuf[32];
541
542#define NUM_SCORES 5
543static struct highscore highscores[NUM_SCORES];
544
545#define NORTH 1
546#define EAST 2
547#define SOUTH 4
548#define WEST 8
549#define HEAD 16
550
551#define EAST_NORTH 32
552#define EAST_SOUTH 64
553#define WEST_NORTH 128
554#define WEST_SOUTH 256
555
556#define NORTH_EAST 512
557#define NORTH_WEST 1024
558#define SOUTH_EAST 2048
559#define SOUTH_WEST 4096
560
561#define LEVELS_FILE PLUGIN_GAMES_DIR "/snake2.levels"
562#define SCORE_FILE PLUGIN_GAMES_DATA_DIR "/snake2.score"
563
564static int load_all_levels(void)
565{
566 int linecnt = 0;
567 int fd;
568 size_t size;
569 char buf[64]; /* Larger than WIDTH, to allow for whitespace after the
570 lines */
571
572 /* Init the level_cache pointer and
573 calculate how many levels that will fit */
574 level_cache = rb->plugin_get_buffer(&size);
575 max_levels = size / (HEIGHT*WIDTH);
576
577 num_levels = 0;
578
579 /* open file */
580 if ((fd = rb->open(LEVELS_FILE, O_RDONLY)) < 0)
581 {
582 return -1;
583 }
584
585 while(rb->read_line(fd, buf, 64) > 0)
586 {
587 if(rb->strlen(buf) == 0) /* Separator? */
588 {
589 num_levels++;
590 if(num_levels > max_levels)
591 {
592 rb->splash(HZ, "Too many levels in file");
593 break;
594 }
595 continue;
596 }
597
598 rb->memcpy(level_cache[num_levels][linecnt], buf, WIDTH);
599 linecnt++;
600 if(linecnt == HEIGHT)
601 {
602 linecnt = 0;
603 }
604 }
605
606 rb->close(fd);
607 return 0;
608}
609
610/*
611** Completely clear the board of walls and/or snake
612*/
613
614static void clear_board( void)
615{
616 int x,y;
617
618 for (x = 0; x < WIDTH; x++)
619 {
620 for (y = 0; y < HEIGHT; y++)
621 {
622 board[x][y] = 0;
623 }
624 }
625}
626
627static int load_level( int level_number )
628{
629 int x,y;
630 clear_board();
631 for(y = 0;y < HEIGHT;y++)
632 {
633 for(x = 0;x < WIDTH;x++)
634 {
635 switch(level_cache[level_number][y][x])
636 {
637 case '|':
638 board[x][y] = NORTH;
639 break;
640
641 case '-':
642 board[x][y] = EAST;
643 break;
644
645 case '+':
646 board[x][y] = HEAD;
647 break;
648 }
649 }
650 }
651 return 1;
652}
653
654/*
655** Gets the currently chosen direction from the first place
656** in the direction buffer. If there is something in the
657** next part of the buffer then that is moved to the first place
658*/
659static void get_direction( void )
660{
661 /*if 1st place is empty*/
662 if(ardirectionbuffer[0] != -1)
663 {
664 /*return this direction*/
665 dir = ardirectionbuffer[0];
666 ardirectionbuffer[0]=-1;
667 /*now see if one needs moving:*/
668 if(ardirectionbuffer[1] != -1)
669 {
670 /*there's a move waiting to be done
671 so move it into the space:*/
672 ardirectionbuffer[0] = ardirectionbuffer[1];
673 ardirectionbuffer[1] = -1;
674 }
675 }
676}
677
678/*
679** Sets the direction
680*/
681static void set_direction(int newdir)
682{
683 if(ardirectionbuffer[0] != newdir)
684 {
685 /*if 1st place is empty*/
686 if(ardirectionbuffer[0] == -1)
687 {
688 /*use 1st space:*/
689 ardirectionbuffer[0] = newdir;
690 }
691 else
692 {
693 /*use 2nd space:*/
694 if(ardirectionbuffer[0] != newdir) ardirectionbuffer[1] = newdir;
695 }
696
697 if(frames < 0) ardirectionbuffer[0] = newdir;
698 }
699}
700
701static void new_level(int level)
702{
703 load_level(level);
704
705 ardirectionbuffer[0] = -1;
706 ardirectionbuffer[1] = -1;
707 dir = EAST;
708 headx = WIDTH/2;
709 heady = HEIGHT/2;
710 tailx = headx - 4;
711 taily = heady;
712 applecountdown = 0;
713 /*Create a small snake to start off with*/
714 board[headx][heady] = dir;
715 board[headx-1][heady] = dir;
716 board[headx-2][heady] = dir;
717 board[headx-3][heady] = dir;
718 board[headx-4][heady] = dir;
719 num_apples_to_got=0;
720}
721
722static void init_snake(void)
723{
724 num_apples_to_get=1;
725 if(game_type == 1)
726 level_from_file = 1;
727 game_b_level=1;
728 new_level(level_from_file);
729}
730
731#if (LCD_WIDTH >= 160) && (LCD_HEIGHT >= 128) \
732 || (LCD_WIDTH >= 128) && (LCD_HEIGHT >= 96) && (LCD_DEPTH >= 16)
733static void draw_frame_bitmap(int header_type)
734{
735 rb->lcd_bitmap(header_type==1? snake2_header1: snake2_header2, 0, 0,
736 BMPWIDTH_snake2_header, BMPHEIGHT_snake2_header);
737 rb->lcd_bitmap(snake2_left, 0, BMPHEIGHT_snake2_header,
738 BMPWIDTH_snake2_left, BMPHEIGHT_snake2_left);
739 rb->lcd_bitmap(snake2_right,
740 LCD_WIDTH - BMPWIDTH_snake2_right, BMPHEIGHT_snake2_header,
741 BMPWIDTH_snake2_right, BMPHEIGHT_snake2_right);
742 rb->lcd_bitmap(snake2_bottom,
743 0, BMPHEIGHT_snake2_header + BMPHEIGHT_snake2_left,
744 BMPWIDTH_snake2_bottom, BMPHEIGHT_snake2_bottom);
745}
746#endif
747
748/*
749** Draws the apple. If it doesn't exist then
750** a new one get's created.
751*/
752static void draw_apple_bit(int x, int y)
753{
754 rb->lcd_fillrect((CENTER_X+x*MULTIPLIER)+1, CENTER_Y+y*MULTIPLIER,
755 MODIFIER_2, MODIFIER_1);
756 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER, (CENTER_Y+y*MULTIPLIER)+1,
757 MODIFIER_1, MODIFIER_2);
758}
759
760static void draw_apple( void )
761{
762 int x,y;
763
764#if (LCD_WIDTH >= 160) && (LCD_HEIGHT >= 128) \
765 || (LCD_WIDTH >= 128) && (LCD_HEIGHT >= 96) && (LCD_DEPTH >= 16)
766 draw_frame_bitmap(2);
767
768 rb->snprintf(strbuf, sizeof(strbuf), "%d", applecount);
769 rb->lcd_getstringsize(strbuf, &strwdt, &strhgt);
770 rb->lcd_putsxy(TOP_X3 - strwdt/2, TOP_Y2, strbuf);
771
772 rb->snprintf(strbuf, sizeof(strbuf), "%d", score);
773 rb->lcd_getstringsize(strbuf, &strwdt, &strhgt);
774 rb->lcd_putsxy(TOP_X4 - strwdt/2, TOP_Y2, strbuf);
775#endif
776
777 if (!apple)
778 {
779 do
780 {
781 x = (rb->rand() % (WIDTH-1))+1;
782 y = (rb->rand() % (HEIGHT-1))+1;
783 } while (board[x][y]);
784 apple = 1;
785 board[x][y] = -1;
786 applex = x;appley = y;
787 }
788 draw_apple_bit(applex, appley);
789}
790
791/*
792 * x x *
793 * x x *
794 * x x *
795 * x x *
796*/
797static void draw_vertical_bit(int x, int y)
798{
799 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER+1, CENTER_Y+y*MULTIPLIER,
800 MODIFIER_2, MODIFIER_1);
801}
802
803/*
804 * * * *
805 X X X X
806 X X X X
807 * * * *
808*/
809static void draw_horizontal_bit(int x, int y)
810{
811 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER, CENTER_Y+y*MULTIPLIER+1,
812 MODIFIER_1, MODIFIER_2);
813}
814
815/*
816 * * * *
817 * * X X
818 * X X X
819 * X X *
820*/
821static void draw_n_to_e_bit(int x, int y)
822{
823 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER+1, CENTER_Y+y*MULTIPLIER+2,
824 MODIFIER_2, MODIFIER_2);
825 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER+2, CENTER_Y+y*MULTIPLIER+1,
826 MODIFIER_2, MODIFIER_2);
827}
828
829/*
830 * * * *
831 * * X X
832 * X X X
833 * X X *
834*/
835static void draw_w_to_s_bit(int x, int y)
836{
837 draw_n_to_e_bit(x,y);
838}
839
840/*
841 * * * *
842 X X * *
843 X X X *
844 * X X *
845*/
846static void draw_n_to_w_bit(int x, int y)
847{
848 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER, CENTER_Y+y*MULTIPLIER+1,
849 MODIFIER_2, MODIFIER_2);
850 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER+1, CENTER_Y+y*MULTIPLIER+2,
851 MODIFIER_2, MODIFIER_2);
852}
853
854/*
855 * * * *
856 X X * *
857 X X X *
858 * X X *
859*/
860static void draw_e_to_s_bit(int x, int y)
861{
862 draw_n_to_w_bit(x, y);
863}
864
865/*
866 * X X *
867 * X X X
868 * * X X
869 * * * *
870*/
871static void draw_s_to_e_bit(int x, int y)
872{
873 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER+1, CENTER_Y+y*MULTIPLIER,
874 MODIFIER_2, MODIFIER_2);
875 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER+2, CENTER_Y+y*MULTIPLIER+1,
876 MODIFIER_2, MODIFIER_2);
877}
878
879/*
880 * X X *
881 * X X X
882 * * X X
883 * * * *
884*/
885static void draw_w_to_n_bit(int x, int y)
886{
887 draw_s_to_e_bit(x,y);
888}
889
890/*
891 * X X *
892 X X X *
893 X X * *
894 * * * *
895*/
896static void draw_e_to_n_bit(int x, int y)
897{
898 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER+1, CENTER_Y+y*MULTIPLIER,
899 MODIFIER_2, MODIFIER_2);
900 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER, CENTER_Y+y*MULTIPLIER+1,
901 MODIFIER_2, MODIFIER_2);
902}
903
904/*
905 * X X *
906 X X X *
907 X X * *
908 * * * *
909*/
910static void draw_s_to_w_bit(int x, int y)
911{
912 draw_e_to_n_bit(x, y);
913}
914
915static void draw_head_bit(int x, int y)
916{
917 rb->lcd_fillrect(CENTER_X+x*MULTIPLIER, CENTER_Y+y*MULTIPLIER,
918 MODIFIER_1, MODIFIER_1);
919}
920
921#if 0 /* unused */
922/*
923** Draws a wall/obsticals
924*/
925static void draw_boundary ( void )
926{
927 int x, y;
928
929 /*TODO: Load levels from file!*/
930
931 /*top and bottom line*/
932 for(x=0; x < WIDTH; x++)
933 {
934 board[x][0] = EAST;
935 board[x][HEIGHT-1] = WEST;
936 }
937
938 /*left and right lines*/
939 for(y=0; y < HEIGHT; y++)
940 {
941 board[0][y] = NORTH;
942 board[WIDTH-1][y] = SOUTH;
943 }
944
945 /*corners:*/
946 board[0][0] = NORTH_EAST;
947 board[WIDTH-1][0] = EAST_SOUTH;
948 board[0][HEIGHT-1] = SOUTH_EAST;
949 board[WIDTH-1][HEIGHT-1] = EAST_NORTH;
950}
951#endif
952
953/*
954** Redraw the entire board
955*/
956static void redraw (void)
957{
958 int x,y;
959
960#ifdef HAVE_LCD_COLOR
961 rb->lcd_set_foreground(LCD_BLACK);
962 rb->lcd_set_background(LCD_WHITE);
963#endif
964
965 rb->lcd_clear_display();
966
967 for (x = 0; x < WIDTH; x++)
968 {
969 for (y = 0; y < HEIGHT; y++)
970 {
971 switch (board[x][y])
972 {
973 case -1:
974 draw_apple_bit(x, y);
975 break;
976 case 0:
977 break;
978
979 case NORTH:
980 case SOUTH:
981 draw_vertical_bit(x,y);
982 break;
983
984 case EAST:
985 case WEST:
986 draw_horizontal_bit(x,y);
987 break;
988
989 default:
990 draw_head_bit(x, y);
991 break;
992 }
993 }
994 }
995
996#if (LCD_WIDTH >= 160) && (LCD_HEIGHT >= 128) \
997 || (LCD_WIDTH >= 128) && (LCD_HEIGHT >= 96) && (LCD_DEPTH >= 16)
998 draw_frame_bitmap(2);
999
1000 rb->snprintf(strbuf, sizeof(strbuf), "%d", applecount);
1001 rb->lcd_getstringsize(strbuf, &strwdt, &strhgt);
1002 rb->lcd_putsxy(TOP_X3 - strwdt/2, TOP_Y2, strbuf);
1003
1004 rb->snprintf(strbuf, sizeof(strbuf), "%d", score);
1005 rb->lcd_getstringsize(strbuf, &strwdt, &strhgt);
1006 rb->lcd_putsxy(TOP_X4 - strwdt/2, TOP_Y2, strbuf);
1007#endif
1008}
1009
1010/*
1011** Draws the snake bit described by nCurrentBit at position x/y
1012** deciding whether it's a corner bit by examing the nPrevious bit
1013*/
1014static void draw_snake_bit(int currentbit, int previousbit, int x, int y)
1015{
1016 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
1017 draw_head_bit(x, y);
1018 rb->lcd_set_drawmode(DRMODE_SOLID);
1019
1020 switch(currentbit)
1021 {
1022 case(NORTH):
1023 switch(previousbit)
1024 {
1025 case(SOUTH):
1026 case(NORTH):
1027 draw_vertical_bit(x,y);
1028 break;
1029
1030 case(EAST):
1031 draw_e_to_n_bit(x,y);
1032 break;
1033
1034 case(WEST):
1035 draw_w_to_n_bit(x,y);
1036 break;
1037 }
1038 break;
1039
1040 case(EAST):
1041 switch(previousbit)
1042 {
1043 case(WEST):
1044 case(EAST):
1045 draw_horizontal_bit(x,y);
1046 break;
1047
1048 case(NORTH):
1049 draw_n_to_e_bit(x,y);
1050 break;
1051
1052 case(SOUTH):
1053 draw_s_to_e_bit(x,y);
1054 break;
1055 }
1056 break;
1057
1058 case(SOUTH):
1059 switch(previousbit)
1060 {
1061 case(SOUTH):
1062 case(NORTH):
1063 draw_vertical_bit(x,y);
1064 break;
1065
1066 case(EAST):
1067 draw_e_to_s_bit(x,y);
1068 break;
1069
1070 case(WEST):
1071 draw_w_to_s_bit(x,y);
1072 break;
1073 }
1074 break;
1075
1076 case(WEST):
1077 switch(previousbit)
1078 {
1079 case(EAST):
1080 case(WEST):
1081 draw_horizontal_bit(x,y);
1082 break;
1083
1084 case(SOUTH):
1085 draw_s_to_w_bit(x,y);
1086 break;
1087
1088 case(NORTH):
1089 draw_n_to_w_bit(x,y);
1090 break;
1091 }
1092 break;
1093 }
1094}
1095
1096static void redraw_snake(void)
1097{
1098 int x = tailx, y = taily;
1099 int olddir, newdir = board[x][y];
1100
1101 while (x != headx || y != heady)
1102 {
1103 olddir = newdir;
1104
1105 switch (olddir)
1106 {
1107 case(NORTH):
1108 y--;
1109 break;
1110
1111 case(EAST):
1112 x++;
1113 break;
1114
1115 case(SOUTH):
1116 y++;
1117 break;
1118
1119 case(WEST):
1120 x--;
1121 break;
1122 }
1123
1124 if(x == WIDTH)
1125 x = 0;
1126 else if(x < 0)
1127 x = WIDTH-1;
1128
1129 if(y == HEIGHT)
1130 y = 0;
1131 else if(y < 0)
1132 y = HEIGHT-1;
1133
1134 newdir = board[x][y];
1135 if(olddir != newdir)
1136 draw_snake_bit(newdir, olddir, x, y);
1137 }
1138}
1139
1140/*
1141** Death 'sequence' and end game stuff.
1142*/
1143static void die (void)
1144{
1145 int button;
1146 bool done=false;
1147
1148 rb->splash(HZ*2, "Oops!");
1149
1150 rb->lcd_clear_display();
1151
1152 applecount=0;
1153
1154 rb->lcd_getstringsize("You died!",&strwdt,&strhgt);
1155 rb->lcd_putsxy((LCD_WIDTH - strwdt)/2,strhgt,"You died!");
1156
1157 rb->snprintf(strbuf, sizeof(strbuf), "Your score: %d", score);
1158 rb->lcd_getstringsize(strbuf, &strwdt, &strhgt);
1159 rb->lcd_putsxy((LCD_WIDTH - strwdt)/2, strhgt * 2 + 2, strbuf);
1160
1161 if (highscore_update(score, level_from_file, game_type==0?"Type A":"Type B",
1162 highscores, NUM_SCORES) == 0)
1163 {
1164 rb->lcd_getstringsize("New high score!",&strwdt,&strhgt);
1165 rb->lcd_putsxy((LCD_WIDTH - strwdt)/2,strhgt * 4 + 2,"New high score!");
1166 }
1167 else
1168 {
1169 rb->snprintf(strbuf, sizeof(strbuf), "High score: %d", highscores[0].score);
1170 rb->lcd_getstringsize(strbuf, &strwdt, &strhgt);
1171 rb->lcd_putsxy((LCD_WIDTH - strwdt)/2, strhgt * 5, strbuf);
1172 }
1173
1174 rb->snprintf(strbuf, sizeof(strbuf), "Press %s...", SNAKE2_PLAYPAUSE_TEXT);
1175 rb->lcd_getstringsize(strbuf, &strwdt, &strhgt);
1176 rb->lcd_putsxy((LCD_WIDTH - strwdt)/2, strhgt * 7, strbuf);
1177
1178 rb->lcd_update();
1179
1180 while(!done)
1181 {
1182 button=rb->button_get(true);
1183 switch(button)
1184 {
1185 case SNAKE2_PLAYPAUSE:
1186 done = true;
1187 break;
1188 }
1189 }
1190
1191 dead=1;
1192}
1193
1194/*
1195** Check for collision. TODO: Currently this
1196** sets of the death sequence. What we want is it to only return a true/false
1197** depending on whether a collision occured.
1198*/
1199static void collision ( int x, int y )
1200{
1201 int bdeath=0;
1202
1203
1204 switch (board[x][y])
1205 {
1206 case 0:
1207
1208 break;
1209 case -1:
1210 score = score + (1 * level);
1211 apple=0;
1212 applecountdown=2;
1213 applecount++;
1214
1215 if(game_type==1)
1216 {
1217 if(num_apples_to_get == num_apples_to_got)
1218 {
1219 level_from_file++;
1220 if(level_from_file >= num_levels)
1221 {
1222 level_from_file = 1;
1223 /*and increase the number of apples to pick up
1224 before level changes*/
1225 num_apples_to_get+=2;
1226 game_b_level++;
1227 }
1228 rb->splash(HZ, "Level Completed!");
1229 new_level(level_from_file);
1230 redraw();
1231 rb->lcd_update();
1232 }
1233 else
1234 num_apples_to_got++;
1235 }
1236 break;
1237 default:
1238 bdeath=1;
1239 break;
1240 }
1241
1242 if(bdeath==1)
1243 {
1244 die();
1245 sillydir = dir;
1246 frames = -110;
1247 }
1248}
1249
1250static void move( void )
1251{
1252 int taildir;
1253 /*this actually sets the dir variable.*/
1254 get_direction();
1255 /*draw head*/
1256 switch (dir)
1257 {
1258 case (NORTH):
1259 board[headx][heady]=NORTH;
1260 heady--;
1261 break;
1262 case (EAST):
1263 board[headx][heady]=EAST;
1264 headx++;
1265 break;
1266 case (SOUTH):
1267 board[headx][heady]=SOUTH;
1268 heady++;
1269 break;
1270 case (WEST):
1271 board[headx][heady]=WEST;
1272 headx--;
1273 break;
1274 }
1275
1276 if(headx == WIDTH)
1277 headx = 0;
1278 else if(headx < 0)
1279 headx = WIDTH-1;
1280
1281 if(heady == HEIGHT)
1282 heady = 0;
1283 else if(heady < 0)
1284 heady = HEIGHT-1;
1285
1286 draw_head_bit(headx, heady);
1287
1288 /*clear tail*/
1289 if(applecountdown <= 0)
1290 {
1291 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
1292 draw_head_bit(tailx, taily);
1293 rb->lcd_set_drawmode(DRMODE_SOLID);
1294
1295 taildir = board[tailx][taily];
1296 board[tailx][taily] = 0;
1297
1298 switch (taildir)
1299 {
1300 case(NORTH):
1301 taily--;
1302 break;
1303
1304 case(EAST):
1305 tailx++;
1306 break;
1307
1308 case(SOUTH):
1309 taily++;
1310 break;
1311
1312 case(WEST):
1313 tailx--;
1314 break;
1315 }
1316
1317 if(tailx == WIDTH)
1318 tailx = 0;
1319 else if(tailx < 0)
1320 tailx = WIDTH-1;
1321
1322 if(taily == HEIGHT)
1323 taily = 0;
1324 else if(taily < 0)
1325 taily = HEIGHT-1;
1326 }
1327 else
1328 applecountdown--;
1329}
1330
1331static void frame (void)
1332{
1333 int olddir, noldx, noldy, temp;
1334 noldx = headx;
1335 noldy = heady;
1336 olddir = 0;
1337 switch(dir)
1338 {
1339 case(NORTH):
1340 if(heady == HEIGHT-1)
1341 temp = 0;
1342 else
1343 temp = heady + 1;
1344
1345 olddir = board[headx][temp];
1346 break;
1347
1348 case(EAST):
1349 if(headx == 0)
1350 temp = WIDTH-1;
1351 else
1352 temp = headx - 1;
1353
1354 olddir = board[temp][heady];
1355 break;
1356
1357 case(SOUTH):
1358 if(heady == 0)
1359 temp = HEIGHT-1;
1360 else
1361 temp = heady - 1;
1362
1363 olddir = board[headx][temp];
1364 break;
1365
1366 case(WEST):
1367 if(headx == WIDTH-1)
1368 temp = 0;
1369 else
1370 temp = headx + 1;
1371
1372 olddir = board[temp][heady];
1373 break;
1374 }
1375
1376 move();
1377
1378 /*
1379 now redraw the bit that was
1380 the tail, to something snake-like:
1381 */
1382 draw_snake_bit(dir, olddir, noldx, noldy);
1383
1384 collision(headx, heady);
1385
1386 rb->lcd_update();
1387}
1388
1389static void game_pause (void)
1390{
1391 int button;
1392
1393 rb->lcd_clear_display();
1394 rb->lcd_getstringsize("Paused",&strwdt,&strhgt);
1395 rb->lcd_putsxy((LCD_WIDTH - strwdt)/2,LCD_HEIGHT/2,"Paused");
1396
1397 rb->lcd_update();
1398 while (1)
1399 {
1400 button = rb->button_get(true);
1401 switch (button)
1402 {
1403 case SNAKE2_PLAYPAUSE:
1404 redraw();
1405 redraw_snake();
1406 draw_head_bit(headx, heady);
1407 rb->lcd_update();
1408 rb->sleep(HZ/2);
1409 return;
1410
1411#ifdef SNAKE2_RC_QUIT
1412 case SNAKE2_RC_QUIT:
1413#endif
1414 case SNAKE2_QUIT:
1415 dead = 1;
1416 quit = 1;
1417 return;
1418
1419 default:
1420 if (rb->default_event_handler(button)==SYS_USB_CONNECTED) {
1421 dead = 1;
1422 quit = 2;
1423 return;
1424 }
1425 break;
1426 }
1427 }
1428}
1429
1430static void game (void)
1431{
1432 int button;
1433
1434 redraw();
1435 rb->lcd_update();
1436 /*main loop:*/
1437 while (1)
1438 {
1439 if(frames==5)
1440 {
1441 frame();
1442 if(frames > 0) frames = 0;
1443 }
1444 frames++;
1445
1446 if(frames == 0)
1447 {
1448 die();
1449 }
1450 else
1451 {
1452 if(frames < 0)
1453 {
1454 if(sillydir != dir)
1455 {
1456 /*it has, great set frames to a positive value again:*/
1457 frames = 1;
1458 }
1459 }
1460 }
1461
1462 if (dead) return;
1463
1464 draw_apple();
1465
1466 rb->sleep(HZ/speed);
1467
1468 button = rb->button_get(false);
1469
1470#ifdef HAS_BUTTON_HOLD
1471 if (rb->button_hold())
1472 button = SNAKE2_PLAYPAUSE;
1473#endif
1474
1475 switch (button)
1476 {
1477 case SNAKE2_UP:
1478 case SNAKE2_UP | BUTTON_REPEAT:
1479 if (dir != SOUTH) set_direction(NORTH);
1480 break;
1481
1482 case SNAKE2_RIGHT:
1483 case SNAKE2_RIGHT | BUTTON_REPEAT:
1484 if (dir != WEST) set_direction(EAST);
1485 break;
1486
1487 case SNAKE2_DOWN:
1488 case SNAKE2_DOWN | BUTTON_REPEAT:
1489 if (dir != NORTH) set_direction(SOUTH);
1490 break;
1491
1492 case SNAKE2_LEFT:
1493 case SNAKE2_LEFT | BUTTON_REPEAT:
1494 if (dir != EAST) set_direction(WEST);
1495 break;
1496
1497#ifdef SNAKE2_RC_QUIT
1498 case SNAKE2_RC_QUIT:
1499#endif
1500 case SNAKE2_QUIT:
1501 quit = 1;
1502 return;
1503
1504 case SNAKE2_PLAYPAUSE:
1505 game_pause();
1506 break;
1507
1508 default:
1509 if (rb->default_event_handler(button)==SYS_USB_CONNECTED) {
1510 quit = 2;
1511 return;
1512 }
1513 break;
1514 }
1515 }
1516
1517}
1518
1519static void select_maze(void)
1520{
1521 int button;
1522
1523 clear_board();
1524 load_level( level_from_file );
1525 redraw();
1526 rb->lcd_update();
1527
1528 while (1)
1529 {
1530#if (LCD_WIDTH >= 160) && (LCD_HEIGHT >= 128) \
1531 || (LCD_WIDTH >= 128) && (LCD_HEIGHT >= 96) && (LCD_DEPTH >= 16)
1532 draw_frame_bitmap(1);
1533
1534 rb->snprintf(strbuf, sizeof(strbuf), "%d", level);
1535 rb->lcd_getstringsize(strbuf, &strwdt, &strhgt);
1536 rb->lcd_putsxy(TOP_X3 - strwdt/2, TOP_Y2, strbuf);
1537
1538 rb->snprintf(strbuf, sizeof(strbuf), "%d", level_from_file);
1539 rb->lcd_getstringsize(strbuf, &strwdt, &strhgt);
1540 rb->lcd_putsxy(TOP_X2 - strwdt/2, TOP_Y1, strbuf);
1541
1542 rb->strcpy(strbuf, game_type==0? "A": "B");
1543 rb->lcd_getstringsize(strbuf, &strwdt, &strhgt);
1544 rb->lcd_putsxy(TOP_X1, TOP_Y1, strbuf);
1545
1546 rb->snprintf(strbuf, sizeof(strbuf), "%d", highscores[0].score);
1547 rb->lcd_getstringsize(strbuf, &strwdt, &strhgt);
1548 rb->lcd_putsxy(TOP_X4 - strwdt/2, TOP_Y2, strbuf);
1549
1550#else
1551 rb->snprintf(strbuf, sizeof(strbuf), "Maze: %d", level_from_file);
1552 rb->lcd_getstringsize(strbuf, &strwdt, &strhgt);
1553 rb->lcd_putsxy((WIDTH*MULTIPLIER - strwdt)/2,
1554 (HEIGHT*MULTIPLIER - strhgt)/2, strbuf);
1555#endif
1556
1557 rb->lcd_update();
1558
1559 button = rb->button_get(true);
1560 switch (button)
1561 {
1562 case SNAKE2_QUIT:
1563 case SNAKE2_PLAYPAUSE:
1564 return;
1565 break;
1566 case SNAKE2_UP:
1567 case SNAKE2_RIGHT:
1568 if(level_from_file < num_levels)
1569 level_from_file++;
1570 else
1571 level_from_file = 0;
1572 load_level( level_from_file );
1573 redraw();
1574 break;
1575 case SNAKE2_DOWN:
1576 case SNAKE2_LEFT:
1577 if(level_from_file > 0)
1578 level_from_file--;
1579 else
1580 level_from_file = num_levels;
1581 load_level( level_from_file );
1582 redraw();
1583 break;
1584 default:
1585 if (rb->default_event_handler(button)==SYS_USB_CONNECTED) {
1586 quit = 2;
1587 return;
1588 }
1589 break;
1590 }
1591 }
1592
1593}
1594
1595static void game_init(void)
1596{
1597 int selection = 0;
1598
1599 static const struct opt_items type_options[] = {
1600 { "Type A", -1 },
1601 { "Type B", -1 },
1602 };
1603
1604 MENUITEM_STRINGLIST(menu, "Snake2 Menu", NULL,
1605 "Start New Game",
1606 "Game Type", "Select Maze", "Speed",
1607 "High Scores",
1608 "Playback Control", "Quit");
1609
1610 rb->button_clear_queue();
1611
1612 dead = 0;
1613 apple = 0;
1614 score = 0;
1615 applecount = 0;
1616
1617 while (1) {
1618 switch (rb->do_menu(&menu, &selection, NULL, false)) {
1619 case 0:
1620 speed = level*20;
1621 return;
1622 case 1:
1623 rb->set_option("Game Type", &game_type, RB_INT,
1624 type_options, 2, NULL);
1625 break;
1626 case 2:
1627 select_maze();
1628 if(quit) return;
1629 break;
1630 case 3:
1631 rb->set_int("Speed", "", UNIT_INT, &level,
1632 NULL, 1, 1, 10, NULL);
1633 break;
1634 case 4:
1635 highscore_show(-1, highscores, NUM_SCORES, true);
1636 break;
1637 case 5:
1638 playback_control(NULL);
1639 break;
1640 case 6:
1641 quit = 1;
1642 return;
1643 case MENU_ATTACHED_USB:
1644 quit = 2;
1645 return;
1646 default:
1647 break;
1648 }
1649 }
1650}
1651
1652enum plugin_status plugin_start(const void* parameter)
1653{
1654 (void)(parameter);
1655
1656 /* Lets use the default font */
1657 rb->lcd_setfont(FONT_SYSFIXED);
1658#if LCD_DEPTH > 1
1659 rb->lcd_set_backdrop(NULL);
1660#endif
1661
1662 load_all_levels();
1663
1664 if (num_levels == 0) {
1665 rb->splash(HZ*2, "Failed loading levels!");
1666 return PLUGIN_OK;
1667 }
1668
1669 highscore_load(SCORE_FILE, highscores, NUM_SCORES);
1670
1671 while(quit==0)
1672 {
1673 game_init();
1674 if(quit)
1675 break;
1676
1677 rb->lcd_clear_display();
1678 frames=1;
1679
1680 init_snake();
1681
1682 /*Start Game:*/
1683 game();
1684 }
1685
1686 highscore_save(SCORE_FILE, highscores, NUM_SCORES);
1687
1688 return (quit==1) ? PLUGIN_OK : PLUGIN_USB_CONNECTED;
1689}