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) 2004-2006 Antoine Cellerier <dionoea -at- videolan -dot- org>
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#include "plugin.h"
23
24#include "lib/playback_control.h"
25
26/* what the minesweeper() function can return */
27enum minesweeper_status {
28 MINESWEEPER_WIN,
29 MINESWEEPER_LOSE,
30 MINESWEEPER_QUIT,
31 MINESWEEPER_USB
32};
33
34/* variable button definitions */
35#if (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
36 (CONFIG_KEYPAD == IRIVER_H300_PAD)
37# define MINESWP_LEFT BUTTON_LEFT
38# define MINESWP_RIGHT BUTTON_RIGHT
39# define MINESWP_UP BUTTON_UP
40# define MINESWP_DOWN BUTTON_DOWN
41# define MINESWP_QUIT BUTTON_OFF
42# define MINESWP_TOGGLE BUTTON_ON
43# define MINESWP_TOGGLE2 BUTTON_REC
44# define MINESWP_DISCOVER BUTTON_SELECT
45# define MINESWP_INFO BUTTON_MODE
46
47# define MINESWP_RC_QUIT BUTTON_RC_STOP
48
49#elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \
50 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
51 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
52# define MINESWP_SCROLLWHEEL
53# define MINESWP_LEFT BUTTON_LEFT
54# define MINESWP_RIGHT BUTTON_RIGHT
55# define MINESWP_UP BUTTON_MENU
56# define MINESWP_DOWN BUTTON_PLAY
57# define MINESWP_NEXT BUTTON_SCROLL_FWD
58# define MINESWP_PREV BUTTON_SCROLL_BACK
59# define MINESWP_QUIT (BUTTON_SELECT | BUTTON_MENU)
60# define MINESWP_TOGGLE_PRE BUTTON_SELECT
61# define MINESWP_TOGGLE (BUTTON_SELECT | BUTTON_REL)
62# define MINESWP_DISCOVER (BUTTON_SELECT | BUTTON_REPEAT)
63# define MINESWP_INFO (BUTTON_SELECT | BUTTON_PLAY)
64
65#elif (CONFIG_KEYPAD == IAUDIO_X5M5_PAD)
66# define MINESWP_LEFT BUTTON_LEFT
67# define MINESWP_RIGHT BUTTON_RIGHT
68# define MINESWP_UP BUTTON_UP
69# define MINESWP_DOWN BUTTON_DOWN
70# define MINESWP_QUIT BUTTON_POWER
71# define MINESWP_TOGGLE BUTTON_PLAY
72# define MINESWP_DISCOVER BUTTON_SELECT
73# define MINESWP_INFO BUTTON_REC
74
75#elif (CONFIG_KEYPAD == GIGABEAT_PAD)
76# define MINESWP_LEFT BUTTON_LEFT
77# define MINESWP_RIGHT BUTTON_RIGHT
78# define MINESWP_UP BUTTON_UP
79# define MINESWP_DOWN BUTTON_DOWN
80# define MINESWP_QUIT BUTTON_POWER
81# define MINESWP_TOGGLE BUTTON_A
82# define MINESWP_DISCOVER BUTTON_SELECT
83# define MINESWP_INFO BUTTON_MENU
84
85#elif (CONFIG_KEYPAD == SANSA_E200_PAD)
86
87# define MINESWP_SCROLLWHEEL
88# define MINESWP_LEFT BUTTON_LEFT
89# define MINESWP_RIGHT BUTTON_RIGHT
90# define MINESWP_UP BUTTON_UP
91# define MINESWP_DOWN BUTTON_DOWN
92# define MINESWP_QUIT BUTTON_POWER
93# define MINESWP_NEXT BUTTON_SCROLL_FWD
94# define MINESWP_PREV BUTTON_SCROLL_BACK
95# define MINESWP_TOGGLE BUTTON_REC
96# define MINESWP_DISCOVER BUTTON_SELECT
97# define MINESWP_INFO (BUTTON_REC|BUTTON_REPEAT)
98
99#elif (CONFIG_KEYPAD == SANSA_FUZE_PAD)
100
101# define MINESWP_LEFT BUTTON_LEFT
102# define MINESWP_RIGHT BUTTON_RIGHT
103# define MINESWP_UP BUTTON_UP
104# define MINESWP_DOWN BUTTON_DOWN
105# define MINESWP_QUIT (BUTTON_HOME|BUTTON_REPEAT)
106# define MINESWP_TOGGLE BUTTON_SCROLL_FWD
107# define MINESWP_DISCOVER BUTTON_SELECT
108# define MINESWP_INFO BUTTON_SCROLL_BACK
109
110#elif (CONFIG_KEYPAD == SANSA_C200_PAD) || \
111(CONFIG_KEYPAD == SANSA_CLIP_PAD) || \
112(CONFIG_KEYPAD == SANSA_M200_PAD)
113# define MINESWP_LEFT BUTTON_LEFT
114# define MINESWP_RIGHT BUTTON_RIGHT
115# define MINESWP_UP BUTTON_UP
116# define MINESWP_DOWN BUTTON_DOWN
117# define MINESWP_QUIT BUTTON_POWER
118# define MINESWP_TOGGLE_PRE BUTTON_SELECT
119# define MINESWP_TOGGLE (BUTTON_SELECT | BUTTON_REL)
120# define MINESWP_TOGGLE2 BUTTON_VOL_DOWN
121# define MINESWP_DISCOVER (BUTTON_SELECT | BUTTON_REPEAT)
122# define MINESWP_DISCOVER2 BUTTON_VOL_UP
123# define MINESWP_INFO (BUTTON_SELECT | BUTTON_UP)
124
125#elif (CONFIG_KEYPAD == IRIVER_H10_PAD)
126# define MINESWP_LEFT BUTTON_LEFT
127# define MINESWP_RIGHT BUTTON_RIGHT
128# define MINESWP_UP BUTTON_SCROLL_UP
129# define MINESWP_DOWN BUTTON_SCROLL_DOWN
130# define MINESWP_QUIT BUTTON_POWER
131# define MINESWP_TOGGLE BUTTON_PLAY
132# define MINESWP_DISCOVER BUTTON_REW
133# define MINESWP_INFO (BUTTON_REW | BUTTON_PLAY)
134
135#elif (CONFIG_KEYPAD == GIGABEAT_S_PAD)
136# define MINESWP_LEFT BUTTON_LEFT
137# define MINESWP_RIGHT BUTTON_RIGHT
138# define MINESWP_UP BUTTON_UP
139# define MINESWP_DOWN BUTTON_DOWN
140# define MINESWP_QUIT BUTTON_BACK
141# define MINESWP_TOGGLE BUTTON_PLAY
142# define MINESWP_DISCOVER BUTTON_SELECT
143# define MINESWP_INFO BUTTON_MENU
144
145#elif (CONFIG_KEYPAD == MROBE100_PAD)
146# define MINESWP_LEFT BUTTON_LEFT
147# define MINESWP_RIGHT BUTTON_RIGHT
148# define MINESWP_UP BUTTON_UP
149# define MINESWP_DOWN BUTTON_DOWN
150# define MINESWP_QUIT BUTTON_POWER
151# define MINESWP_TOGGLE BUTTON_DISPLAY
152# define MINESWP_DISCOVER BUTTON_SELECT
153# define MINESWP_INFO BUTTON_MENU
154
155#elif CONFIG_KEYPAD == IAUDIO_M3_PAD
156# define MINESWP_LEFT BUTTON_RC_REW
157# define MINESWP_RIGHT BUTTON_RC_FF
158# define MINESWP_UP BUTTON_RC_VOL_UP
159# define MINESWP_DOWN BUTTON_RC_VOL_DOWN
160# define MINESWP_QUIT BUTTON_RC_REC
161# define MINESWP_TOGGLE BUTTON_RC_MODE
162# define MINESWP_DISCOVER BUTTON_RC_PLAY
163# define MINESWP_INFO BUTTON_RC_MENU
164
165#elif (CONFIG_KEYPAD == COWON_D2_PAD)
166# define MINESWP_QUIT BUTTON_POWER
167
168#elif CONFIG_KEYPAD == CREATIVEZVM_PAD
169# define MINESWP_LEFT BUTTON_LEFT
170# define MINESWP_RIGHT BUTTON_RIGHT
171# define MINESWP_UP BUTTON_UP
172# define MINESWP_DOWN BUTTON_DOWN
173# define MINESWP_QUIT BUTTON_BACK
174# define MINESWP_TOGGLE BUTTON_SELECT
175# define MINESWP_DISCOVER BUTTON_PLAY
176# define MINESWP_INFO BUTTON_MENU
177
178#elif CONFIG_KEYPAD == PHILIPS_HDD1630_PAD
179# define MINESWP_LEFT BUTTON_LEFT
180# define MINESWP_RIGHT BUTTON_RIGHT
181# define MINESWP_UP BUTTON_UP
182# define MINESWP_DOWN BUTTON_DOWN
183# define MINESWP_QUIT BUTTON_POWER
184# define MINESWP_TOGGLE BUTTON_VIEW
185# define MINESWP_DISCOVER BUTTON_SELECT
186# define MINESWP_INFO BUTTON_MENU
187
188#elif CONFIG_KEYPAD == PHILIPS_HDD6330_PAD
189# define MINESWP_LEFT BUTTON_LEFT
190# define MINESWP_RIGHT BUTTON_RIGHT
191# define MINESWP_UP BUTTON_UP
192# define MINESWP_DOWN BUTTON_DOWN
193# define MINESWP_QUIT BUTTON_POWER
194# define MINESWP_TOGGLE BUTTON_NEXT
195# define MINESWP_DISCOVER BUTTON_PLAY
196# define MINESWP_INFO BUTTON_MENU
197
198#elif CONFIG_KEYPAD == PHILIPS_SA9200_PAD
199# define MINESWP_LEFT BUTTON_PREV
200# define MINESWP_RIGHT BUTTON_NEXT
201# define MINESWP_UP BUTTON_UP
202# define MINESWP_DOWN BUTTON_DOWN
203# define MINESWP_QUIT BUTTON_POWER
204# define MINESWP_TOGGLE BUTTON_RIGHT
205# define MINESWP_DISCOVER BUTTON_PLAY
206# define MINESWP_INFO BUTTON_MENU
207
208#elif (CONFIG_KEYPAD == ONDAVX747_PAD) || \
209CONFIG_KEYPAD == ONDAVX777_PAD || \
210CONFIG_KEYPAD == MROBE500_PAD
211# define MINESWP_QUIT BUTTON_POWER
212
213#elif (CONFIG_KEYPAD == SAMSUNG_YH820_PAD)
214# define MINESWP_LEFT BUTTON_LEFT
215# define MINESWP_RIGHT BUTTON_RIGHT
216# define MINESWP_UP BUTTON_UP
217# define MINESWP_DOWN BUTTON_DOWN
218# define MINESWP_QUIT (BUTTON_REW|BUTTON_REPEAT)
219# define MINESWP_TOGGLE BUTTON_PLAY
220# define MINESWP_DISCOVER BUTTON_FFWD
221# define MINESWP_INFO BUTTON_REC
222
223#elif (CONFIG_KEYPAD == SAMSUNG_YH92X_PAD)
224# define MINESWP_LEFT BUTTON_LEFT
225# define MINESWP_RIGHT BUTTON_RIGHT
226# define MINESWP_UP BUTTON_UP
227# define MINESWP_DOWN BUTTON_DOWN
228# define MINESWP_QUIT (BUTTON_REW|BUTTON_REPEAT)
229# define MINESWP_TOGGLE (BUTTON_PLAY|BUTTON_REL)
230# define MINESWP_TOGGLE_PRE BUTTON_PLAY
231# define MINESWP_DISCOVER BUTTON_FFWD
232# define MINESWP_INFO (BUTTON_PLAY|BUTTON_REPEAT)
233# define MINESWP_INFO_PRE BUTTON_PLAY
234
235#elif (CONFIG_KEYPAD == PBELL_VIBE500_PAD)
236# define MINESWP_LEFT BUTTON_PREV
237# define MINESWP_RIGHT BUTTON_NEXT
238# define MINESWP_UP BUTTON_UP
239# define MINESWP_DOWN BUTTON_DOWN
240# define MINESWP_QUIT BUTTON_REC
241# define MINESWP_TOGGLE BUTTON_PLAY
242# define MINESWP_DISCOVER BUTTON_OK
243# define MINESWP_INFO BUTTON_MENU
244
245#elif CONFIG_KEYPAD == MPIO_HD200_PAD
246# define MINESWP_LEFT BUTTON_VOL_DOWN
247# define MINESWP_RIGHT BUTTON_VOL_UP
248# define MINESWP_UP BUTTON_REW
249# define MINESWP_DOWN BUTTON_FF
250# define MINESWP_QUIT (BUTTON_REC|BUTTON_PLAY)
251# define MINESWP_TOGGLE BUTTON_PLAY
252# define MINESWP_DISCOVER BUTTON_FUNC
253# define MINESWP_INFO BUTTON_REC
254
255#elif CONFIG_KEYPAD == MPIO_HD300_PAD
256# define MINESWP_LEFT BUTTON_REW
257# define MINESWP_RIGHT BUTTON_FF
258# define MINESWP_UP BUTTON_UP
259# define MINESWP_DOWN BUTTON_DOWN
260# define MINESWP_QUIT (BUTTON_MENU|BUTTON_REPEAT)
261# define MINESWP_TOGGLE BUTTON_ENTER
262# define MINESWP_DISCOVER BUTTON_PLAY
263# define MINESWP_INFO (BUTTON_MENU|BUTTON_REL)
264
265#elif CONFIG_KEYPAD == SANSA_FUZEPLUS_PAD
266# define MINESWP_LEFT BUTTON_LEFT
267# define MINESWP_RIGHT BUTTON_RIGHT
268# define MINESWP_UP BUTTON_UP
269# define MINESWP_DOWN BUTTON_DOWN
270# define MINESWP_QUIT BUTTON_POWER
271# define MINESWP_TOGGLE BUTTON_SELECT
272# define MINESWP_DISCOVER BUTTON_PLAYPAUSE
273# define MINESWP_NEXT BUTTON_BOTTOMRIGHT
274# define MINESWP_PREV BUTTON_BOTTOMLEFT
275# define MINESWP_INFO BUTTON_BACK
276
277
278#elif (CONFIG_KEYPAD == SANSA_CONNECT_PAD)
279# define MINESWP_SCROLLWHEEL
280# define MINESWP_LEFT BUTTON_LEFT
281# define MINESWP_RIGHT BUTTON_RIGHT
282# define MINESWP_UP BUTTON_UP
283# define MINESWP_DOWN BUTTON_DOWN
284# define MINESWP_QUIT BUTTON_POWER
285# define MINESWP_NEXT BUTTON_SCROLL_FWD
286# define MINESWP_PREV BUTTON_SCROLL_BACK
287# define MINESWP_TOGGLE BUTTON_NEXT
288# define MINESWP_DISCOVER BUTTON_SELECT
289# define MINESWP_INFO BUTTON_PREV
290
291#elif (CONFIG_KEYPAD == SAMSUNG_YPR0_PAD)
292# define MINESWP_LEFT BUTTON_LEFT
293# define MINESWP_RIGHT BUTTON_RIGHT
294# define MINESWP_UP BUTTON_UP
295# define MINESWP_DOWN BUTTON_DOWN
296# define MINESWP_QUIT BUTTON_BACK
297# define MINESWP_TOGGLE BUTTON_USER
298# define MINESWP_DISCOVER BUTTON_SELECT
299# define MINESWP_INFO BUTTON_MENU
300
301#elif (CONFIG_KEYPAD == HM60X_PAD)
302
303# define MINESWP_LEFT BUTTON_LEFT
304# define MINESWP_RIGHT BUTTON_RIGHT
305# define MINESWP_UP BUTTON_UP
306# define MINESWP_DOWN BUTTON_DOWN
307# define MINESWP_QUIT BUTTON_POWER
308# define MINESWP_TOGGLE (BUTTON_LEFT|BUTTON_POWER)
309# define MINESWP_DISCOVER BUTTON_SELECT
310# define MINESWP_INFO (BUTTON_UP|BUTTON_POWER)
311
312#elif (CONFIG_KEYPAD == HM801_PAD)
313
314# define MINESWP_LEFT BUTTON_LEFT
315# define MINESWP_RIGHT BUTTON_RIGHT
316# define MINESWP_UP BUTTON_UP
317# define MINESWP_DOWN BUTTON_DOWN
318# define MINESWP_QUIT BUTTON_POWER
319# define MINESWP_TOGGLE BUTTON_PLAY
320# define MINESWP_DISCOVER BUTTON_SELECT
321# define MINESWP_INFO BUTTON_PREV
322
323#elif (CONFIG_KEYPAD == CREATIVE_ZENXFI3_PAD)
324
325# define MINESWP_LEFT BUTTON_BACK
326# define MINESWP_RIGHT BUTTON_MENU
327# define MINESWP_UP BUTTON_UP
328# define MINESWP_DOWN BUTTON_DOWN
329# define MINESWP_QUIT BUTTON_POWER
330# define MINESWP_TOGGLE BUTTON_VOL_UP
331# define MINESWP_DISCOVER BUTTON_PLAY
332# define MINESWP_INFO BUTTON_VOL_DOWN
333
334#elif CONFIG_KEYPAD == SONY_NWZ_PAD
335#define MINESWP_LEFT BUTTON_LEFT
336#define MINESWP_RIGHT BUTTON_RIGHT
337#define MINESWP_UP BUTTON_UP
338#define MINESWP_DOWN BUTTON_DOWN
339#define MINESWP_QUIT BUTTON_BACK
340#define MINESWP_TOGGLE BUTTON_PLAY
341#define MINESWP_DISCOVER (BUTTON_PLAY|BUTTON_REPEAT)
342#define MINESWP_INFO BUTTON_POWER
343
344#elif CONFIG_KEYPAD == CREATIVE_ZEN_PAD
345#define MINESWP_LEFT BUTTON_LEFT
346#define MINESWP_RIGHT BUTTON_RIGHT
347#define MINESWP_UP BUTTON_UP
348#define MINESWP_DOWN BUTTON_DOWN
349#define MINESWP_QUIT BUTTON_BACK
350#define MINESWP_TOGGLE BUTTON_PLAYPAUSE
351#define MINESWP_DISCOVER BUTTON_SELECT
352#define MINESWP_INFO BUTTON_MENU
353
354#elif CONFIG_KEYPAD == AGPTEK_ROCKER_PAD
355#define MINESWP_LEFT BUTTON_LEFT
356#define MINESWP_RIGHT BUTTON_RIGHT
357#define MINESWP_UP BUTTON_UP
358#define MINESWP_DOWN BUTTON_DOWN
359#define MINESWP_QUIT BUTTON_POWER
360#define MINESWP_TOGGLE BUTTON_VOLUP
361#define MINESWP_DISCOVER BUTTON_SELECT
362#define MINESWP_INFO BUTTON_VOLDOWN
363
364#elif (CONFIG_KEYPAD == DX50_PAD)
365# define MINESWP_QUIT (BUTTON_POWER|BUTTON_REL)
366
367#elif CONFIG_KEYPAD == CREATIVE_ZENXFI2_PAD
368# define MINESWP_QUIT BUTTON_POWER
369
370#elif (CONFIG_KEYPAD == XDUOO_X3_PAD)
371# define MINESWP_LEFT BUTTON_PREV
372# define MINESWP_RIGHT BUTTON_NEXT
373# define MINESWP_UP BUTTON_HOME
374# define MINESWP_DOWN BUTTON_OPTION
375# define MINESWP_QUIT BUTTON_POWER
376# define MINESWP_TOGGLE_PRE BUTTON_PLAY
377# define MINESWP_TOGGLE (BUTTON_PLAY | BUTTON_REL)
378# define MINESWP_TOGGLE2 BUTTON_VOL_DOWN
379# define MINESWP_DISCOVER (BUTTON_PLAY | BUTTON_REPEAT)
380# define MINESWP_DISCOVER2 BUTTON_VOL_UP
381# define MINESWP_INFO (BUTTON_PLAY | BUTTON_OPTION)
382
383#elif (CONFIG_KEYPAD == XDUOO_X3II_PAD) || (CONFIG_KEYPAD == XDUOO_X20_PAD)
384# define MINESWP_LEFT BUTTON_PREV
385# define MINESWP_RIGHT BUTTON_NEXT
386# define MINESWP_UP BUTTON_HOME
387# define MINESWP_DOWN BUTTON_OPTION
388# define MINESWP_QUIT BUTTON_POWER
389# define MINESWP_TOGGLE_PRE BUTTON_PLAY
390# define MINESWP_TOGGLE (BUTTON_PLAY | BUTTON_REL)
391# define MINESWP_TOGGLE2 BUTTON_VOL_DOWN
392# define MINESWP_DISCOVER (BUTTON_PLAY | BUTTON_REPEAT)
393# define MINESWP_DISCOVER2 BUTTON_VOL_UP
394# define MINESWP_INFO (BUTTON_PLAY | BUTTON_OPTION)
395
396#elif (CONFIG_KEYPAD == FIIO_M3K_LINUX_PAD)
397# define MINESWP_LEFT BUTTON_PREV
398# define MINESWP_RIGHT BUTTON_NEXT
399# define MINESWP_UP BUTTON_HOME
400# define MINESWP_DOWN BUTTON_OPTION
401# define MINESWP_QUIT BUTTON_POWER
402# define MINESWP_TOGGLE_PRE BUTTON_PLAY
403# define MINESWP_TOGGLE (BUTTON_PLAY | BUTTON_REL)
404# define MINESWP_TOGGLE2 BUTTON_VOL_DOWN
405# define MINESWP_DISCOVER (BUTTON_PLAY | BUTTON_REPEAT)
406# define MINESWP_DISCOVER2 BUTTON_VOL_UP
407# define MINESWP_INFO (BUTTON_PLAY | BUTTON_OPTION)
408
409#elif (CONFIG_KEYPAD == IHIFI_770_PAD) || (CONFIG_KEYPAD == IHIFI_800_PAD)
410# define MINESWP_LEFT BUTTON_HOME
411# define MINESWP_RIGHT BUTTON_VOL_DOWN
412# define MINESWP_UP BUTTON_PREV
413# define MINESWP_DOWN BUTTON_NEXT
414# define MINESWP_QUIT BUTTON_POWER
415# define MINESWP_TOGGLE_PRE BUTTON_PLAY
416# define MINESWP_TOGGLE (BUTTON_POWER | BUTTON_PREV)
417# define MINESWP_TOGGLE2 (BUTTON_POWER | BUTTON_NEXT)
418# define MINESWP_DISCOVER (BUTTON_POWER | BUTTON_VOL_UP)
419# define MINESWP_DISCOVER2 (BUTTON_POWER | BUTTON_VOL_DOWN)
420# define MINESWP_INFO (BUTTON_POWER | BUTTON_HOME)
421
422#elif (CONFIG_KEYPAD == EROSQ_PAD)
423# define MINESWP_LEFT BUTTON_SCROLL_BACK
424# define MINESWP_RIGHT BUTTON_SCROLL_FWD
425# define MINESWP_UP BUTTON_PREV
426# define MINESWP_DOWN BUTTON_NEXT
427# define MINESWP_QUIT BUTTON_POWER
428# define MINESWP_TOGGLE_PRE BUTTON_PLAY
429# define MINESWP_TOGGLE (BUTTON_PLAY | BUTTON_REL)
430# define MINESWP_DISCOVER (BUTTON_PLAY | BUTTON_REPEAT)
431# define MINESWP_INFO BUTTON_VOL_UP
432
433#elif CONFIG_KEYPAD == FIIO_M3K_PAD
434# define MINESWP_LEFT BUTTON_LEFT
435# define MINESWP_RIGHT BUTTON_RIGHT
436# define MINESWP_UP BUTTON_UP
437# define MINESWP_DOWN BUTTON_DOWN
438# define MINESWP_QUIT BUTTON_POWER
439# define MINESWP_TOGGLE_PRE BUTTON_SELECT
440# define MINESWP_TOGGLE (BUTTON_SELECT|BUTTON_REL)
441# define MINESWP_DISCOVER (BUTTON_SELECT|BUTTON_REPEAT)
442# define MINESWP_INFO BUTTON_MENU
443
444#elif CONFIG_KEYPAD == MA_PAD
445# define MINESWP_LEFT BUTTON_LEFT
446# define MINESWP_RIGHT BUTTON_RIGHT
447# define MINESWP_UP BUTTON_UP
448# define MINESWP_DOWN BUTTON_DOWN
449# define MINESWP_QUIT BUTTON_BACK
450# define MINESWP_TOGGLE_PRE BUTTON_PLAY
451# define MINESWP_TOGGLE (BUTTON_PLAY|BUTTON_REL)
452# define MINESWP_DISCOVER (BUTTON_MENU|BUTTON_REPEAT)
453# define MINESWP_INFO BUTTON_MENU
454
455#elif CONFIG_KEYPAD == SHANLING_Q1_PAD
456/* use touchscreen */
457
458#elif CONFIG_KEYPAD == SDL_PAD
459/* use touchscreen */
460#elif CONFIG_KEYPAD == RG_NANO_PAD
461# define MINESWP_LEFT BUTTON_LEFT
462# define MINESWP_RIGHT BUTTON_RIGHT
463# define MINESWP_UP BUTTON_UP
464# define MINESWP_DOWN BUTTON_DOWN
465# define MINESWP_QUIT BUTTON_START
466# define MINESWP_TOGGLE BUTTON_X
467# define MINESWP_DISCOVER BUTTON_A
468# define MINESWP_INFO BUTTON_Y
469
470#else
471#error No keymap defined!
472#endif
473
474#ifdef HAVE_TOUCHSCREEN
475#ifndef MINESWP_QUIT
476# define MINESWP_QUIT BUTTON_TOPLEFT
477#endif
478#ifndef MINESWP_LEFT
479# define MINESWP_LEFT BUTTON_MIDLEFT
480#endif
481#ifndef MINESWP_RIGHT
482# define MINESWP_RIGHT BUTTON_MIDRIGHT
483#endif
484#ifndef MINESWP_UP
485# define MINESWP_UP BUTTON_TOPMIDDLE
486#endif
487#ifndef MINESWP_DOWN
488# define MINESWP_DOWN BUTTON_BOTTOMMIDDLE
489#endif
490#ifndef MINESWP_TOGGLE
491# define MINESWP_TOGGLE BUTTON_CENTER
492#endif
493#ifndef MINESWP_DISCOVER
494# define MINESWP_DISCOVER BUTTON_BOTTOMLEFT
495#endif
496#ifndef MINESWP_INFO
497# define MINESWP_INFO BUTTON_BOTTOMRIGHT
498#endif
499#endif
500
501extern const fb_data minesweeper_tiles[];
502
503#ifdef HAVE_LCD_COLOR
504# if ( LCD_HEIGHT * LCD_WIDTH ) / ( 16 * 16 ) >= 130
505 /* We want to have at least 130 tiles on the screen */
506# define TileSize 16
507# elif ( LCD_HEIGHT * LCD_WIDTH ) / ( 12 * 12 ) >= 130
508# define TileSize 12
509# else
510# define TileSize 10
511# endif
512# define BackgroundColor LCD_RGBPACK( 128, 128, 128 )
513#elif LCD_DEPTH > 1
514# define TileSize 12
515#else
516# define TileSize 8
517#endif
518
519#define Mine 9
520#define Flag 10
521#define Unknown 11
522#define ExplodedMine 12
523#define WrongFlag 13
524#define CorrectFlag 14
525
526#define draw_tile( num, x, y ) \
527 rb->lcd_bitmap_part( minesweeper_tiles, 0, num * TileSize, \
528 TileSize, left+x*TileSize, top+y*TileSize, \
529 TileSize, TileSize )
530
531#define invert_tile( x, y ) \
532 rb->lcd_set_drawmode(DRMODE_COMPLEMENT); \
533 rb->lcd_fillrect( left+x*TileSize, top+y*TileSize, TileSize, TileSize ); \
534 rb->lcd_set_drawmode(DRMODE_SOLID);
535
536
537/* the tile struct
538 * if there is a mine, mine is true
539 * if tile is known by player, known is true
540 * if tile has a flag, flag is true
541 * neighbors is the total number of mines arround tile
542 */
543typedef struct tile
544{
545 unsigned char mine : 1;
546 unsigned char known : 1;
547 unsigned char flag : 1;
548 unsigned char neighbors : 4;
549} tile;
550
551/* the height and width of the field */
552#define MAX_HEIGHT (LCD_HEIGHT/TileSize)
553#define MAX_WIDTH (LCD_WIDTH/TileSize)
554static int height = MAX_HEIGHT;
555static int width = MAX_WIDTH;
556static int top;
557static int left;
558
559/* The Minefield. Caution it is defined as Y, X! Not the opposite. */
560static tile minefield[MAX_HEIGHT][MAX_WIDTH];
561
562/* total number of mines on the game */
563static int mine_num = 0;
564
565/* percentage of mines on minefield used during generation */
566static int percent = 16;
567
568/* number of tiles left on the game */
569static int tiles_left;
570
571/* Because mines are set after the first move... */
572static bool no_mines = true;
573
574/* We need a stack (created on discover()) for the cascade algorithm. */
575static int stack_pos = 0;
576
577#ifdef HAVE_TOUCHSCREEN
578
579#include "lib/pluginlib_touchscreen.h"
580static struct ts_raster mine_raster = { 0, 0, MAX_WIDTH, MAX_HEIGHT, TileSize, TileSize };
581#endif
582
583
584static void push( int *stack, int y, int x )
585{
586 if( stack_pos <= height*width )
587 {
588 stack[++stack_pos] = y;
589 stack[++stack_pos] = x;
590 }
591}
592
593/* Unveil tiles and push them to stack if they are empty. */
594static void unveil( int *stack, int y, int x )
595{
596 if( x < 0 || y < 0 || x > width - 1 || y > height - 1
597 || minefield[y][x].known
598 || minefield[y][x].mine || minefield[y][x].flag ) return;
599
600 minefield[y][x].known = 1;
601
602 if( minefield[y][x].neighbors == 0 )
603 push( stack, y, x );
604}
605
606static int is_flagged( int y, int x )
607{
608 if( x >= 0 && y >= 0 && x < width && y < height && minefield[y][x].flag )
609 return 1;
610 return 0;
611}
612
613static int neighbors_flagged( int y, int x )
614{
615 return is_flagged( y-1, x-1 ) +
616 is_flagged( y-1, x ) +
617 is_flagged( y-1, x+1 ) +
618 is_flagged( y, x-1 ) +
619 is_flagged( y, x ) +
620 is_flagged( y, x+1 ) +
621 is_flagged( y+1, x-1 ) +
622 is_flagged( y+1, x ) +
623 is_flagged( y+1, x+1 );
624}
625
626static bool discover( int y, int x, bool explore_neighbors )
627{
628 /* Selected tile. */
629 if( x < 0 || y < 0 || x > width - 1 || y > height - 1)
630 return false;
631
632 if( minefield[y][x].known || minefield[y][x].mine || minefield[y][x].flag )
633 {
634 if( !minefield[y][x].flag && minefield[y][x].mine )
635 return true;
636
637 if( explore_neighbors && minefield[y][x].known &&
638 minefield[y][x].neighbors == neighbors_flagged( y, x ) )
639 {
640 return discover( y-1, x-1, false ) ||
641 discover( y-1, x, false ) ||
642 discover( y-1, x+1, false ) ||
643 discover( y, x-1, false ) ||
644 discover( y, x, false ) ||
645 discover( y, x+1, false ) ||
646 discover( y+1, x-1, false ) ||
647 discover( y+1, x, false ) ||
648 discover( y+1, x+1, false );
649 }
650
651 return false;
652 }
653
654 minefield[y][x].known = 1;
655 /* Exit if the tile is not empty. (no mines nearby) */
656 if( minefield[y][x].neighbors ) return false;
657
658 int stack[height*width];
659
660 push( stack, y, x );
661
662 /* Scan all nearby tiles. If we meet a tile with a number we just unveil
663 * it. If we meet an empty tile, we push the location in stack. For each
664 * location in stack we do the same thing. (scan again all nearby tiles)
665 */
666 while( stack_pos )
667 {
668 /* Pop x, y from stack. */
669 x = stack[stack_pos--];
670 y = stack[stack_pos--];
671
672 unveil( stack, y-1, x-1 );
673 unveil( stack, y-1, x );
674 unveil( stack, y-1, x+1 );
675 unveil( stack, y, x+1 );
676 unveil( stack, y+1, x+1 );
677 unveil( stack, y+1, x );
678 unveil( stack, y+1, x-1 );
679 unveil( stack, y, x-1 );
680 }
681
682 return false;
683}
684
685/* Reset the whole board for a new game. */
686static void minesweeper_init( void )
687{
688 rb->memset(minefield, 0, sizeof(minefield));
689 no_mines = true;
690 tiles_left = width*height;
691}
692
693
694/* put mines on the mine field */
695/* there is p% chance that a tile is a mine */
696/* if the tile has coordinates (x,y), or is adjacent to those,
697 * then it can't be a mine because that would reduce the game
698 * from a logic game to a guessing game. */
699static void minesweeper_putmines( int p, int x, int y )
700{
701 int i,j;
702
703 mine_num = 0;
704 for( i = 0; i < height; i++ )
705 {
706 for( j = 0; j < width; j++ )
707 {
708 if( rb->rand()%100 < p
709 && !( i>=y-1 && i<=y+1 && j>=x-1 && j<=x+1 ) )
710 {
711 minefield[i][j].mine = 1;
712 mine_num++;
713 }
714 else
715 {
716 minefield[i][j].mine = 0;
717 }
718 minefield[i][j].neighbors = 0;
719 }
720 }
721
722 /* we need to compute the neighbor element for each tile */
723 for( i = 0; i < height; i++ )
724 {
725 for( j = 0; j < width; j++ )
726 {
727 if( i > 0 )
728 {
729 if( j > 0 )
730 minefield[i][j].neighbors += minefield[i-1][j-1].mine;
731 minefield[i][j].neighbors += minefield[i-1][j].mine;
732 if( j < width - 1 )
733 minefield[i][j].neighbors += minefield[i-1][j+1].mine;
734 }
735 if( j > 0 )
736 minefield[i][j].neighbors += minefield[i][j-1].mine;
737 if( j < width - 1 )
738 minefield[i][j].neighbors += minefield[i][j+1].mine;
739 if( i < height - 1 )
740 {
741 if( j > 0 )
742 minefield[i][j].neighbors += minefield[i+1][j-1].mine;
743 minefield[i][j].neighbors += minefield[i+1][j].mine;
744 if( j < width - 1 )
745 minefield[i][j].neighbors += minefield[i+1][j+1].mine;
746 }
747 }
748 }
749
750 no_mines = false;
751
752 /* In case the user is lucky and there are no mines positioned. */
753 if( !mine_num && height*width != 1 )
754 {
755 minesweeper_putmines(p, x, y);
756 }
757}
758
759/* A function that will uncover all the board, when the user wins or loses.
760 can easily be expanded, (just a call assigned to a button) as a solver. */
761static void mine_show( void )
762{
763 int i, j, button;
764
765 for( i = 0; i < height; i++ )
766 {
767 for( j = 0; j < width; j++ )
768 {
769 if( minefield[i][j].mine )
770 {
771 if( minefield[i][j].known )
772 draw_tile( ExplodedMine, j, i );
773 else if( minefield[i][j].flag )
774 draw_tile( CorrectFlag, j, i );
775 else
776 draw_tile( Mine, j, i );
777 }
778 else
779 {
780 if( minefield[i][j].flag )
781 draw_tile( WrongFlag, j, i );
782 else
783 draw_tile( minefield[i][j].neighbors, j, i );
784 }
785 }
786 }
787 rb->lcd_update();
788
789 do
790 button = rb->button_get(true);
791 while( ( button == BUTTON_NONE )
792 || ( button & (BUTTON_REL|BUTTON_REPEAT) ) );
793#ifdef HAVE_TOUCHSCREEN
794 button = BUTTON_NONE;
795#endif
796}
797
798static int count_tiles_left( void )
799{
800 int tiles = 0;
801 int i, j;
802 for( i = 0; i < height; i++ )
803 for( j = 0; j < width; j++ )
804 if( minefield[i][j].known == 0 )
805 tiles++;
806 return tiles;
807}
808
809static int count_flags( void )
810{
811 int flags = 0;
812 int i, j;
813 for( i = 0; i < height; i++ )
814 for( j = 0; j < width; j++ )
815 if( minefield[i][j].flag == 1 )
816 flags++;
817 return flags;
818}
819
820/* welcome screen where player can chose mine percentage */
821static enum minesweeper_status menu( void )
822{
823 int selection = 0, result = MINESWEEPER_QUIT;
824 bool menu_quit = false;
825
826 MENUITEM_STRINGLIST( menu, "Minesweeper Menu", NULL, "Play Minesweeper",
827 "Mine Percentage", "Number of Rows",
828 "Number of Columns", "Playback Control", "Quit" );
829
830#ifdef HAVE_LCD_COLOR
831 rb->lcd_set_foreground( rb->global_settings->fg_color );
832 rb->lcd_set_background( rb->global_settings->bg_color );
833#endif
834
835 while( !menu_quit )
836 {
837 switch( rb->do_menu( &menu, &selection, NULL, false ) )
838 {
839 case 0:
840 result = MINESWEEPER_WIN; /* start playing */
841 menu_quit = true;
842 break;
843
844 case 1:
845 rb->set_int( "Mine Percentage", "%", UNIT_INT, &percent, NULL,
846 1, 2, 98, NULL );
847 break;
848
849 case 2:
850 rb->set_int( "Number of Rows", "", UNIT_INT, &height, NULL,
851 1, 1, MAX_HEIGHT, NULL );
852 break;
853
854 case 3:
855 rb->set_int( "Number of Columns", "", UNIT_INT, &width, NULL,
856 1, 1, MAX_WIDTH, NULL );
857 break;
858
859 case 4:
860 playback_control( NULL );
861 break;
862
863 default:
864 result = MINESWEEPER_QUIT; /* quit program */
865 menu_quit = true;
866 break;
867 }
868 }
869
870 return result;
871}
872
873/* the big and ugly game function */
874static enum minesweeper_status minesweeper( void )
875{
876 int i, j;
877 int button;
878#if defined(HAVE_TOUCHSCREEN) || defined(MINESWP_TOGGLE_PRE) || defined(MINESWP_INFO_PRE)
879 int lastbutton = BUTTON_NONE;
880#endif
881
882 /* the cursor coordinates */
883 int x=0, y=0;
884
885 /**
886 * Show the menu
887 */
888 if( ( i = menu() ) != MINESWEEPER_WIN ) return i;
889
890 /**
891 * Init game
892 */
893 top = (LCD_HEIGHT-height*TileSize)/2;
894 left = (LCD_WIDTH-width*TileSize)/2;
895
896#ifdef HAVE_TOUCHSCREEN
897 mine_raster.tl_x = left;
898 mine_raster.tl_y = top;
899 mine_raster.width = width*TileSize;
900 mine_raster.height = height*TileSize;
901#endif
902
903 rb->srand( *rb->current_tick );
904 minesweeper_init();
905 x = 0;
906 y = 0;
907
908 /**
909 * Play
910 */
911 while( true )
912 {
913
914 /* clear the screen buffer */
915#ifdef HAVE_LCD_COLOR
916 rb->lcd_set_background( BackgroundColor );
917#endif
918 rb->lcd_clear_display();
919
920 /* display the mine field */
921 for( i = 0; i < height; i++ )
922 {
923 for( j = 0; j < width; j++ )
924 {
925 if( minefield[i][j].known )
926 {
927 draw_tile( minefield[i][j].neighbors, j, i );
928 }
929 else if(minefield[i][j].flag)
930 {
931 draw_tile( Flag, j, i );
932 }
933 else
934 {
935 draw_tile( Unknown, j, i );
936 }
937 }
938 }
939
940 /* display the cursor */
941 invert_tile( x, y );
942
943 /* update the screen */
944 rb->lcd_update();
945
946 button = rb->button_get(true);
947#ifdef HAVE_TOUCHSCREEN
948 if(button & BUTTON_TOUCHSCREEN)
949 {
950 struct ts_raster_result res;
951 if(touchscreen_map_raster(&mine_raster, rb->button_get_data() >> 16, rb->button_get_data() & 0xffff, &res) == 1)
952 {
953 button &= ~BUTTON_TOUCHSCREEN;
954 lastbutton &= ~BUTTON_TOUCHSCREEN;
955
956 if(button & BUTTON_REPEAT && lastbutton != MINESWP_TOGGLE && lastbutton ^ BUTTON_REPEAT)
957 button = MINESWP_TOGGLE;
958 else if(button == BUTTON_REL && lastbutton ^ BUTTON_REPEAT)
959 button = MINESWP_DISCOVER;
960 else
961 button |= BUTTON_TOUCHSCREEN;
962
963 x = res.x;
964 y = res.y;
965 }
966 }
967#endif
968 switch(button)
969 {
970 /* quit minesweeper (you really shouldn't use this button ...) */
971#ifdef MINESWP_RC_QUIT
972 case MINESWP_RC_QUIT:
973#endif
974 case MINESWP_QUIT:
975 return MINESWEEPER_QUIT;
976
977 /* move cursor left */
978 case MINESWP_LEFT:
979 case MINESWP_LEFT|BUTTON_REPEAT:
980 if( --x < 0)
981 x += width;
982 break;
983
984 /* move cursor right */
985 case MINESWP_RIGHT:
986 case MINESWP_RIGHT|BUTTON_REPEAT:
987 if( ++x >= width )
988 x -= width;
989 break;
990
991 /* move cursor down */
992 case MINESWP_DOWN:
993 case MINESWP_DOWN|BUTTON_REPEAT:
994 if( ++y >= height )
995 y -= height;
996 break;
997
998 /* move cursor up */
999 case MINESWP_UP:
1000 case MINESWP_UP|BUTTON_REPEAT:
1001 if( --y < 0 )
1002 y += height;
1003 break;
1004
1005 /*move cursor though the entire field*/
1006#ifdef MINESWP_SCROLLWHEEL
1007 case MINESWP_NEXT:
1008 case MINESWP_NEXT|BUTTON_REPEAT:
1009 if (x == width -1 ) {
1010 if( ++y >= height )
1011 y -= height;
1012 }
1013 if( ++x >= width )
1014 x -= width;
1015 break;
1016
1017 case MINESWP_PREV:
1018 case MINESWP_PREV|BUTTON_REPEAT:
1019 if (x == 0) {
1020 if( --y < 0 )
1021 y += height;
1022 }
1023 if( --x < 0 )
1024 x += width;
1025 break;
1026#endif
1027 /* discover a tile (and it's neighbors if .neighbors == 0) */
1028 case MINESWP_DISCOVER:
1029#ifdef MINESWP_DISCOVER2
1030 case MINESWP_DISCOVER2:
1031#endif
1032 if( minefield[y][x].flag ) break;
1033 /* we put the mines on the first "click" so that you don't
1034 * lose on the first "click" */
1035 if( tiles_left == width*height && no_mines )
1036 minesweeper_putmines(percent,x,y);
1037
1038 if( discover( y, x, true ) )
1039 {
1040 minefield[y][x].known = 1;
1041 return MINESWEEPER_LOSE;
1042 }
1043
1044 tiles_left = count_tiles_left();
1045 if( tiles_left == mine_num )
1046 {
1047 return MINESWEEPER_WIN;
1048 }
1049 break;
1050
1051 /* toggle flag under cursor */
1052 case MINESWP_TOGGLE:
1053#ifdef MINESWP_TOGGLE_PRE
1054 if( lastbutton != MINESWP_TOGGLE_PRE )
1055 break;
1056#endif
1057#ifdef MINESWP_TOGGLE2
1058 case MINESWP_TOGGLE2:
1059#endif
1060 if( !minefield[y][x].known )
1061 minefield[y][x].flag = !minefield[y][x].flag;
1062 break;
1063
1064 /* show how many mines you think you have found and how many
1065 * there really are on the game */
1066 case MINESWP_INFO:
1067#ifdef MINESWP_INFO_PRE
1068 if( lastbutton != MINESWP_INFO_PRE )
1069 break;
1070#endif
1071 if( no_mines )
1072 break;
1073 int flags_used = count_flags();
1074 if (flags_used == 1) {
1075 rb->splashf( HZ*2, "You marked 1 field. There are %d mines.",
1076 mine_num );
1077 }
1078 else
1079 {
1080 rb->splashf( HZ*2, "You marked %d fields. There are %d mines.",
1081 flags_used, mine_num );
1082 }
1083 break;
1084
1085 default:
1086 if( rb->default_event_handler( button ) == SYS_USB_CONNECTED )
1087 return MINESWEEPER_USB;
1088 break;
1089 }
1090#if defined(HAVE_TOUCHSCREEN) || defined(MINESWP_TOGGLE_PRE) || defined(MINESWP_INFO_PRE)
1091 if( button != BUTTON_NONE )
1092 lastbutton = button;
1093#endif
1094 }
1095
1096}
1097
1098/* plugin entry point */
1099enum plugin_status plugin_start(const void* parameter)
1100{
1101 bool exit = false;
1102
1103 (void)parameter;
1104#if LCD_DEPTH > 1
1105 rb->lcd_set_backdrop(NULL);
1106#endif
1107
1108 while( !exit )
1109 {
1110 switch( minesweeper() )
1111 {
1112 case MINESWEEPER_WIN:
1113 rb->splash( HZ, "You Win!" );
1114 rb->lcd_clear_display();
1115 mine_show();
1116 break;
1117
1118 case MINESWEEPER_LOSE:
1119 rb->splash( HZ, "You Lose!" );
1120 rb->lcd_clear_display();
1121 mine_show();
1122 break;
1123
1124 case MINESWEEPER_USB:
1125 return PLUGIN_USB_CONNECTED;
1126
1127 case MINESWEEPER_QUIT:
1128 exit = true;
1129 break;
1130
1131 default:
1132 break;
1133 }
1134 }
1135
1136 return PLUGIN_OK;
1137}