Fix warning about missing newline at the EOF
[maemo-rb.git] / apps / plugins / blackjack.c
blobab4da37b0a74da4072f215ed5cd1e7b48e78b874
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2006 Tom Ross
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 ****************************************************************************/
22 #include "plugin.h"
23 #include "pluginbitmaps/card_deck.h"
24 #include "pluginbitmaps/card_back.h"
25 #include "lib/display_text.h"
26 #include "lib/highscore.h"
27 #include "lib/playback_control.h"
31 /* save files */
32 #define SCORE_FILE PLUGIN_GAMES_DATA_DIR "/blackjack.score"
33 #define SAVE_FILE PLUGIN_GAMES_DATA_DIR "/blackjack.save"
34 #define NUM_SCORES 5
36 /* final game return status */
37 enum {
38 BJ_LOSE,
39 BJ_QUIT_WITHOUT_SAVING,
40 BJ_QUIT,
41 BJ_USB,
42 BJ_END,
45 #if CONFIG_KEYPAD == RECORDER_PAD
46 #define BJACK_SELECT_NAME "PLAY"
47 #define BJACK_STAY_NAME "F1"
48 #define BJACK_QUIT_NAME "OFF"
49 #define BJACK_DOUBLE_NAME "F2"
50 #define BJACK_SELECT BUTTON_PLAY
51 #define BJACK_QUIT BUTTON_OFF
52 #define BJACK_MAX (BUTTON_ON|BUTTON_UP)
53 #define BJACK_MIN (BUTTON_ON|BUTTON_DOWN)
54 #define BJACK_STAY BUTTON_F1
55 #define BJACK_DOUBLEDOWN BUTTON_F2
56 #define BJACK_UP BUTTON_UP
57 #define BJACK_DOWN BUTTON_DOWN
58 #define BJACK_RIGHT BUTTON_RIGHT
59 #define BJACK_LEFT BUTTON_LEFT
61 #elif CONFIG_KEYPAD == ONDIO_PAD
62 #define BJACK_SELECT_NAME "MENU"
63 #define BJACK_STAY_NAME "RIGHT"
64 #define BJACK_QUIT_NAME "OFF"
65 #define BJACK_DOUBLE_NAME "UP"
66 #define BJACK_SELECT BUTTON_MENU
67 #define BJACK_QUIT BUTTON_OFF
68 #define BJACK_STAY BUTTON_RIGHT
69 #define BJACK_DOUBLEDOWN BUTTON_UP
70 #define BJACK_UP BUTTON_UP
71 #define BJACK_DOWN BUTTON_DOWN
72 #define BJACK_RIGHT BUTTON_RIGHT
73 #define BJACK_LEFT BUTTON_LEFT
75 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
76 #define BJACK_SELECT_NAME "PLAY"
77 #define BJACK_STAY_NAME ">>|"
78 #define BJACK_QUIT_NAME "POWER"
79 #define BJACK_DOUBLE_NAME "|<<"
80 #define BJACK_SELECT BUTTON_PLAY
81 #define BJACK_QUIT BUTTON_POWER
82 #define BJACK_STAY BUTTON_FF
83 #define BJACK_DOUBLEDOWN BUTTON_REW
84 #define BJACK_UP BUTTON_SCROLL_UP
85 #define BJACK_DOWN BUTTON_SCROLL_DOWN
86 #define BJACK_RIGHT BUTTON_RIGHT
87 #define BJACK_LEFT BUTTON_LEFT
89 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
90 (CONFIG_KEYPAD == IRIVER_H300_PAD)
91 #define BJACK_SELECT_NAME "ON"
92 #define BJACK_STAY_NAME "REC"
93 #define BJACK_QUIT_NAME "OFF"
94 #define BJACK_DOUBLE_NAME "SELECT"
95 #define BJACK_SELECT BUTTON_ON
96 #define BJACK_QUIT BUTTON_OFF
97 #define BJACK_STAY BUTTON_REC
98 #define BJACK_DOUBLEDOWN BUTTON_SELECT
99 #define BJACK_UP BUTTON_UP
100 #define BJACK_DOWN BUTTON_DOWN
101 #define BJACK_RIGHT BUTTON_RIGHT
102 #define BJACK_LEFT BUTTON_LEFT
104 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \
105 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
106 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
107 #define BJACK_SELECT_NAME "SELECT"
108 #define BJACK_STAY_NAME "RIGHT"
109 #define BJACK_RESUME_NAME "PLAY"
110 #define BJACK_QUIT_NAME "MENU"
111 #define BJACK_DOUBLE_NAME "LEFT"
112 #define BJACK_SELECT BUTTON_SELECT
113 #define BJACK_QUIT BUTTON_MENU
114 #define BJACK_STAY BUTTON_RIGHT
115 #define BJACK_DOUBLEDOWN BUTTON_LEFT
116 #define BJACK_UP BUTTON_SCROLL_FWD
117 #define BJACK_DOWN BUTTON_SCROLL_BACK
118 #define BJACK_RIGHT BUTTON_RIGHT
119 #define BJACK_LEFT BUTTON_LEFT
121 #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD
122 #define BJACK_SELECT_NAME "SELECT"
123 #define BJACK_STAY_NAME "REC"
124 #define BJACK_QUIT_NAME "POWER"
125 #define BJACK_DOUBLE_NAME "PLAY"
126 #define BJACK_SELECT BUTTON_SELECT
127 #define BJACK_QUIT BUTTON_POWER
128 #define BJACK_MAX (BUTTON_PLAY|BUTTON_UP)
129 #define BJACK_MIN (BUTTON_PLAY|BUTTON_DOWN)
130 #define BJACK_STAY BUTTON_REC
131 #define BJACK_DOUBLEDOWN BUTTON_PLAY
132 #define BJACK_UP BUTTON_UP
133 #define BJACK_DOWN BUTTON_DOWN
134 #define BJACK_RIGHT BUTTON_RIGHT
135 #define BJACK_LEFT BUTTON_LEFT
137 #elif CONFIG_KEYPAD == IRIVER_IFP7XX_PAD
138 #define BJACK_SELECT_NAME "MODE"
139 #define BJACK_STAY_NAME "MODE"
140 #define BJACK_QUIT_NAME "PLAY"
141 #define BJACK_DOUBLE_NAME "SELECT"
142 #define BJACK_SELECT BUTTON_MODE
143 #define BJACK_QUIT BUTTON_PLAY
144 #define BJACK_MAX (BUTTON_EQ|BUTTON_UP)
145 #define BJACK_MIN (BUTTON_EQ|BUTTON_DOWN)
146 #define BJACK_STAY BUTTON_MODE
147 #define BJACK_DOUBLEDOWN BUTTON_SELECT
148 #define BJACK_UP BUTTON_UP
149 #define BJACK_DOWN BUTTON_DOWN
150 #define BJACK_RIGHT BUTTON_RIGHT
151 #define BJACK_LEFT BUTTON_LEFT
153 #elif CONFIG_KEYPAD == GIGABEAT_PAD
154 #define BJACK_SELECT_NAME "SELECT"
155 #define BJACK_STAY_NAME "VOL-"
156 #define BJACK_QUIT_NAME "POWER"
157 #define BJACK_DOUBLE_NAME "A"
158 #define BJACK_SELECT BUTTON_SELECT
159 #define BJACK_QUIT BUTTON_POWER
160 #define BJACK_MAX BUTTON_VOL_UP
161 #define BJACK_MIN BUTTON_VOL_DOWN
162 #define BJACK_STAY BUTTON_VOL_DOWN
163 #define BJACK_DOUBLEDOWN BUTTON_A
164 #define BJACK_UP BUTTON_UP
165 #define BJACK_DOWN BUTTON_DOWN
166 #define BJACK_RIGHT BUTTON_RIGHT
167 #define BJACK_LEFT BUTTON_LEFT
169 #elif (CONFIG_KEYPAD == SANSA_E200_PAD) || \
170 (CONFIG_KEYPAD == SANSA_CONNECT_PAD)
171 #define BJACK_SELECT_NAME "SELECT"
172 #define BJACK_STAY_NAME "RIGHT"
173 #define BJACK_QUIT_NAME "POWER"
174 #define BJACK_DOUBLE_NAME "LEFT"
175 #define BJACK_SELECT BUTTON_SELECT
176 #define BJACK_QUIT BUTTON_POWER
177 #define BJACK_MAX BUTTON_UP
178 #define BJACK_MIN BUTTON_DOWN
179 #define BJACK_STAY BUTTON_RIGHT
180 #define BJACK_DOUBLEDOWN BUTTON_LEFT
181 #define BJACK_UP BUTTON_SCROLL_FWD
182 #define BJACK_DOWN BUTTON_SCROLL_BACK
183 #define BJACK_RIGHT BUTTON_RIGHT
184 #define BJACK_LEFT BUTTON_LEFT
186 #elif CONFIG_KEYPAD == SANSA_FUZE_PAD
187 #define BJACK_SELECT_NAME "SELECT"
188 #define BJACK_STAY_NAME "RIGHT"
189 #define BJACK_QUIT_NAME "HOME"
190 #define BJACK_DOUBLE_NAME "LEFT"
191 #define BJACK_SELECT BUTTON_SELECT
192 #define BJACK_QUIT (BUTTON_HOME|BUTTON_REPEAT)
193 #define BJACK_MAX BUTTON_UP
194 #define BJACK_MIN BUTTON_DOWN
195 #define BJACK_STAY BUTTON_RIGHT
196 #define BJACK_DOUBLEDOWN BUTTON_LEFT
197 #define BJACK_UP BUTTON_SCROLL_FWD
198 #define BJACK_DOWN BUTTON_SCROLL_BACK
199 #define BJACK_RIGHT BUTTON_RIGHT
200 #define BJACK_LEFT BUTTON_LEFT
202 #elif CONFIG_KEYPAD == SANSA_C200_PAD
203 #define BJACK_SELECT_NAME "SELECT"
204 #define BJACK_STAY_NAME "RIGHT"
205 #define BJACK_QUIT_NAME "POWER"
206 #define BJACK_DOUBLE_NAME "LEFT"
207 #define BJACK_SELECT BUTTON_SELECT
208 #define BJACK_QUIT BUTTON_POWER
209 #define BJACK_MAX BUTTON_VOL_UP
210 #define BJACK_MIN BUTTON_VOL_DOWN
211 #define BJACK_STAY BUTTON_RIGHT
212 #define BJACK_DOUBLEDOWN BUTTON_LEFT
213 #define BJACK_UP BUTTON_UP
214 #define BJACK_DOWN BUTTON_DOWN
215 #define BJACK_RIGHT BUTTON_RIGHT
216 #define BJACK_LEFT BUTTON_LEFT
218 #elif CONFIG_KEYPAD == SANSA_CLIP_PAD
219 #define BJACK_SELECT_NAME "SELECT"
220 #define BJACK_STAY_NAME "RIGHT"
221 #define BJACK_QUIT_NAME "POWER"
222 #define BJACK_DOUBLE_NAME "LEFT"
223 #define BJACK_SELECT BUTTON_SELECT
224 #define BJACK_QUIT BUTTON_POWER
225 #define BJACK_MAX BUTTON_VOL_UP
226 #define BJACK_MIN BUTTON_VOL_DOWN
227 #define BJACK_STAY BUTTON_RIGHT
228 #define BJACK_DOUBLEDOWN BUTTON_LEFT
229 #define BJACK_UP BUTTON_UP
230 #define BJACK_DOWN BUTTON_DOWN
231 #define BJACK_RIGHT BUTTON_RIGHT
232 #define BJACK_LEFT BUTTON_LEFT
234 #elif CONFIG_KEYPAD == SANSA_M200_PAD
235 #define BJACK_SELECT_NAME "SELECT"
236 #define BJACK_STAY_NAME "RIGHT"
237 #define BJACK_QUIT_NAME "POWER"
238 #define BJACK_DOUBLE_NAME "LEFT"
239 #define BJACK_SELECT (BUTTON_SELECT | BUTTON_REL)
240 #define BJACK_QUIT BUTTON_POWER
241 #define BJACK_MAX BUTTON_VOL_UP
242 #define BJACK_MIN BUTTON_VOL_DOWN
243 #define BJACK_STAY BUTTON_RIGHT
244 #define BJACK_DOUBLEDOWN BUTTON_LEFT
245 #define BJACK_UP BUTTON_UP
246 #define BJACK_DOWN BUTTON_DOWN
247 #define BJACK_RIGHT BUTTON_RIGHT
248 #define BJACK_LEFT BUTTON_LEFT
250 #elif CONFIG_KEYPAD == TATUNG_TPJ1022_PAD
251 #define BJACK_SELECT_NAME "MAIN"
252 #define BJACK_STAY_NAME "MENU"
253 #define BJACK_QUIT_NAME "POWER"
254 #define BJACK_DOUBLE_NAME "DOWN"
255 #define BJACK_SELECT BUTTON_MAIN
256 #define BJACK_QUIT BUTTON_POWER
257 #define BJACK_MAX (BUTTON_REC|BUTTON_UP)
258 #define BJACK_MIN (BUTTON_REC|BUTTON_DOWN)
259 #define BJACK_STAY BUTTON_MENU
260 #define BJACK_DOUBLEDOWN BUTTON_DOWN
261 #define BJACK_UP BUTTON_UP
262 #define BJACK_DOWN BUTTON_DOWN
263 #define BJACK_RIGHT BUTTON_RIGHT
264 #define BJACK_LEFT BUTTON_LEFT
266 #elif CONFIG_KEYPAD == GIGABEAT_S_PAD
267 #define BJACK_SELECT_NAME "PLAY"
268 #define BJACK_STAY_NAME "VOL-"
269 #define BJACK_QUIT_NAME "BACK"
270 #define BJACK_DOUBLE_NAME "SELECT"
271 #define BJACK_SELECT BUTTON_PLAY
272 #define BJACK_QUIT BUTTON_BACK
273 #define BJACK_MAX BUTTON_VOL_UP
274 #define BJACK_MIN BUTTON_VOL_DOWN
275 #define BJACK_STAY BUTTON_VOL_DOWN
276 #define BJACK_DOUBLEDOWN BUTTON_SELECT
277 #define BJACK_UP BUTTON_UP
278 #define BJACK_DOWN BUTTON_DOWN
279 #define BJACK_RIGHT BUTTON_RIGHT
280 #define BJACK_LEFT BUTTON_LEFT
282 #elif CONFIG_KEYPAD == MROBE100_PAD
283 #define BJACK_SELECT_NAME "SELECT"
284 #define BJACK_STAY_NAME "DISPLAY"
285 #define BJACK_QUIT_NAME "POWER"
286 #define BJACK_DOUBLE_NAME "DOWN"
287 #define BJACK_SELECT BUTTON_SELECT
288 #define BJACK_QUIT BUTTON_POWER
289 #define BJACK_MAX BUTTON_MENU
290 #define BJACK_MIN BUTTON_DISPLAY
291 #define BJACK_STAY BUTTON_DISPLAY
292 #define BJACK_DOUBLEDOWN BUTTON_DOWN
293 #define BJACK_UP BUTTON_UP
294 #define BJACK_DOWN BUTTON_DOWN
295 #define BJACK_RIGHT BUTTON_RIGHT
296 #define BJACK_LEFT BUTTON_LEFT
298 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
299 #define BJACK_SELECT_NAME "RC","PLAY"
300 #define BJACK_STAY_NAME "RC", ">>|"
301 #define BJACK_QUIT_NAME "RC_REC"
302 #define BJACK_DOUBLE_NAME "RC_REW"
303 #define BJACK_SELECT BUTTON_RC_PLAY
304 #define BJACK_QUIT BUTTON_RC_REC
305 #define BJACK_STAY BUTTON_RC_FF
306 #define BJACK_DOUBLEDOWN BUTTON_RC_REW
307 #define BJACK_UP BUTTON_RC_VOL_UP
308 #define BJACK_DOWN BUTTON_RC_VOL_DOWN
309 #define BJACK_RIGHT BUTTON_RC_FF
310 #define BJACK_LEFT BUTTON_RC_REW
312 #elif CONFIG_KEYPAD == COWON_D2_PAD
313 #define BJACK_QUIT_NAME "POWER"
314 #define BJACK_DOUBLE_NAME "-"
315 #define BJACK_QUIT BUTTON_POWER
316 #define BJACK_DOUBLEDOWN BUTTON_MINUS
318 #elif CONFIG_KEYPAD == CREATIVEZVM_PAD
319 #define BJACK_SELECT_NAME "SELECT"
320 #define BJACK_STAY_NAME "PLAY"
321 #define BJACK_QUIT_NAME "POWER"
322 #define BJACK_DOUBLE_NAME "CUSTOM"
323 #define BJACK_SELECT BUTTON_SELECT
324 #define BJACK_QUIT BUTTON_POWER
325 #define BJACK_STAY BUTTON_PLAY
326 #define BJACK_MAX (BUTTON_CUSTOM|BUTTON_UP)
327 #define BJACK_MIN (BUTTON_CUSTOM|BUTTON_DOWN)
328 #define BJACK_DOUBLEDOWN BUTTON_CUSTOM
329 #define BJACK_UP BUTTON_UP
330 #define BJACK_DOWN BUTTON_DOWN
331 #define BJACK_RIGHT BUTTON_RIGHT
332 #define BJACK_LEFT BUTTON_LEFT
334 #elif CONFIG_KEYPAD == PHILIPS_HDD1630_PAD
335 #define BJACK_SELECT_NAME "SELECT"
336 #define BJACK_STAY_NAME "VOL-"
337 #define BJACK_QUIT_NAME "POWER"
338 #define BJACK_DOUBLE_NAME "MENU"
339 #define BJACK_SELECT BUTTON_SELECT
340 #define BJACK_QUIT BUTTON_POWER
341 #define BJACK_MAX BUTTON_VOL_UP
342 #define BJACK_MIN BUTTON_VOL_DOWN
343 #define BJACK_STAY BUTTON_VOL_DOWN
344 #define BJACK_DOUBLEDOWN BUTTON_MENU
345 #define BJACK_UP BUTTON_UP
346 #define BJACK_DOWN BUTTON_DOWN
347 #define BJACK_RIGHT BUTTON_RIGHT
348 #define BJACK_LEFT BUTTON_LEFT
350 #elif CONFIG_KEYPAD == PHILIPS_HDD6330_PAD
351 #define BJACK_SELECT_NAME "PLAY"
352 #define BJACK_STAY_NAME "VOL-"
353 #define BJACK_QUIT_NAME "POWER"
354 #define BJACK_DOUBLE_NAME "MENU"
355 #define BJACK_SELECT BUTTON_PLAY
356 #define BJACK_QUIT BUTTON_POWER
357 #define BJACK_MAX BUTTON_VOL_UP
358 #define BJACK_MIN BUTTON_VOL_DOWN
359 #define BJACK_STAY BUTTON_VOL_DOWN
360 #define BJACK_DOUBLEDOWN BUTTON_MENU
361 #define BJACK_UP BUTTON_UP
362 #define BJACK_DOWN BUTTON_DOWN
363 #define BJACK_RIGHT BUTTON_RIGHT
364 #define BJACK_LEFT BUTTON_LEFT
366 #elif CONFIG_KEYPAD == PHILIPS_SA9200_PAD
367 #define BJACK_SELECT_NAME "MENU"
368 #define BJACK_STAY_NAME "VOL-"
369 #define BJACK_QUIT_NAME "POWER"
370 #define BJACK_DOUBLE_NAME "PLAY"
371 #define BJACK_SELECT BUTTON_MENU
372 #define BJACK_QUIT BUTTON_POWER
373 #define BJACK_MAX BUTTON_VOL_UP
374 #define BJACK_MIN BUTTON_VOL_DOWN
375 #define BJACK_STAY BUTTON_VOL_DOWN
376 #define BJACK_DOUBLEDOWN BUTTON_PLAY
377 #define BJACK_UP BUTTON_UP
378 #define BJACK_DOWN BUTTON_DOWN
379 #define BJACK_RIGHT BUTTON_NEXT
380 #define BJACK_LEFT BUTTON_PREV
382 #elif CONFIG_KEYPAD == ONDAVX747_PAD
383 #define BJACK_QUIT_NAME "POWER"
384 #define BJACK_DOUBLE_NAME "Vol-"
385 #define BJACK_QUIT BUTTON_POWER
386 #define BJACK_DOUBLEDOWN BUTTON_VOL_DOWN
388 #elif CONFIG_KEYPAD == ONDAVX777_PAD
389 #define BJACK_QUIT_NAME "POWER"
390 #define BJACK_QUIT BUTTON_POWER
392 #elif CONFIG_KEYPAD == MROBE500_PAD
393 #define BJACK_QUIT_NAME "POWER"
394 #define BJACK_QUIT BUTTON_POWER
396 #elif CONFIG_KEYPAD == SAMSUNG_YH_PAD
397 #define BJACK_SELECT_NAME "PLAY"
398 #define BJACK_STAY_NAME "RECORD"
399 #define BJACK_QUIT_NAME "REW"
400 #define BJACK_DOUBLE_NAME "FFWD"
401 #define BJACK_SELECT BUTTON_PLAY
402 #define BJACK_QUIT BUTTON_REW
403 #define BJACK_STAY BUTTON_REC
404 #define BJACK_DOUBLEDOWN BUTTON_FFWD
405 #define BJACK_UP BUTTON_UP
406 #define BJACK_DOWN BUTTON_DOWN
407 #define BJACK_RIGHT BUTTON_RIGHT
408 #define BJACK_LEFT BUTTON_LEFT
410 #elif CONFIG_KEYPAD == PBELL_VIBE500_PAD
411 #define BJACK_SELECT_NAME "OK"
412 #define BJACK_STAY_NAME "CANCEL"
413 #define BJACK_QUIT_NAME "REC"
414 #define BJACK_DOUBLE_NAME "MENU"
415 #define BJACK_SELECT BUTTON_OK
416 #define BJACK_QUIT BUTTON_REC
417 #define BJACK_STAY BUTTON_CANCEL
418 #define BJACK_DOUBLEDOWN BUTTON_MENU
419 #define BJACK_UP BUTTON_UP
420 #define BJACK_DOWN BUTTON_DOWN
421 #define BJACK_RIGHT BUTTON_NEXT
422 #define BJACK_LEFT BUTTON_PREV
424 #elif CONFIG_KEYPAD == MPIO_HD200_PAD
425 #define BJACK_SELECT_NAME "FUNC"
426 #define BJACK_STAY_NAME "VOL +"
427 #define BJACK_RESUME_NAME "PLAY"
428 #define BJACK_QUIT_NAME "REC+PLAY"
429 #define BJACK_DOUBLE_NAME "VOL -"
430 #define BJACK_SELECT BUTTON_FUNC
431 #define BJACK_QUIT (BUTTON_REC|BUTTON_PLAY)
432 #define BJACK_STAY BUTTON_VOL_UP
433 #define BJACK_DOUBLEDOWN BUTTON_VOL_DOWN
434 #define BJACK_UP BUTTON_REW
435 #define BJACK_DOWN BUTTON_FF
436 #define BJACK_RIGHT BUTTON_VOL_UP
437 #define BJACK_LEFT BUTTON_VOL_DOWN
439 #elif CONFIG_KEYPAD == MPIO_HD300_PAD
440 #define BJACK_SELECT_NAME "FUNC"
441 #define BJACK_STAY_NAME "VOL +"
442 #define BJACK_RESUME_NAME "PLAY"
443 #define BJACK_QUIT_NAME "REC+PLAY"
444 #define BJACK_DOUBLE_NAME "VOL -"
445 #define BJACK_SELECT BUTTON_ENTER
446 #define BJACK_QUIT (BUTTON_REC|BUTTON_REPEAT)
447 #define BJACK_STAY BUTTON_PLAY
448 #define BJACK_DOUBLEDOWN BUTTON_REC
449 #define BJACK_UP BUTTON_UP
450 #define BJACK_DOWN BUTTON_DOWN
451 #define BJACK_RIGHT BUTTON_FF
452 #define BJACK_LEFT BUTTON_REW
454 #elif CONFIG_KEYPAD == SANSA_FUZEPLUS_PAD
455 #define BJACK_SELECT_NAME "SELECT"
456 #define BJACK_STAY_NAME "PLAYPAUSE"
457 #define BJACK_RESUME_NAME ""
458 #define BJACK_QUIT_NAME "POWER"
459 #define BJACK_DOUBLE_NAME "BACK"
460 #define BJACK_SELECT BUTTON_SELECT
461 #define BJACK_QUIT BUTTON_POWER
462 #define BJACK_STAY BUTTON_PLAYPAUSE
463 #define BJACK_DOUBLEDOWN BUTTON_BACK
464 #define BJACK_UP BUTTON_UP
465 #define BJACK_DOWN BUTTON_DOWN
466 #define BJACK_RIGHT BUTTON_RIGHT
467 #define BJACK_LEFT BUTTON_LEFT
469 #elif CONFIG_KEYPAD == SAMSUNG_YPR0_PAD
470 #define BJACK_SELECT_NAME "SELECT"
471 #define BJACK_STAY_NAME "MENU"
472 #define BJACK_QUIT_NAME "BACK"
473 #define BJACK_DOUBLE_NAME "USER"
474 #define BJACK_SELECT BUTTON_SELECT
475 #define BJACK_QUIT BUTTON_BACK
476 #define BJACK_MAX (BUTTON_LEFT|BUTTON_UP)
477 #define BJACK_MIN (BUTTON_RIGHT|BUTTON_DOWN)
478 #define BJACK_STAY BUTTON_MENU
479 #define BJACK_DOUBLEDOWN BUTTON_USER
480 #define BJACK_UP BUTTON_UP
481 #define BJACK_DOWN BUTTON_DOWN
482 #define BJACK_RIGHT BUTTON_RIGHT
483 #define BJACK_LEFT BUTTON_LEFT
485 #else
486 #error No keymap defined!
487 #endif
489 #ifdef HAVE_TOUCHSCREEN
490 #ifndef BJACK_DOUBLEDOWN
491 #define BJACK_DOUBLEDOWN BUTTON_MIDLEFT
492 #define BJACK_DOUBLE_NAME "BUTTON_MIDLEFT"
493 #endif
494 #ifndef BJACK_SELECT
495 #define BJACK_SELECT BUTTON_CENTER
496 #define BJACK_SELECT_NAME "BUTTON_CENTER"
497 #endif
498 #ifndef BJACK_MAX
499 #define BJACK_MAX BUTTON_TOPRIGHT
500 #endif
501 #ifndef BJACK_MIN
502 #define BJACK_MIN BUTTON_TOPLEFT
503 #endif
504 #ifndef BJACK_STAY
505 #define BJACK_STAY BUTTON_BOTTOMLEFT
506 #define BJACK_STAY_NAME "BUTTON_BOTTOMLEFT"
507 #endif
508 #ifndef BJACK_UP
509 #define BJACK_UP BUTTON_TOPMIDDLE
510 #endif
511 #ifndef BJACK_DOWN
512 #define BJACK_DOWN BUTTON_BOTTOMMIDDLE
513 #endif
514 #ifndef BJACK_RIGHT
515 #define BJACK_RIGHT BUTTON_MIDRIGHT
516 #endif
517 #ifndef BJACK_LEFT
518 #define BJACK_LEFT BUTTON_MIDLEFT
519 #endif
521 #endif
523 #ifdef HAVE_LCD_COLOR
524 #define BG_COLOR LCD_RGBPACK(0,157,0)
525 #define FG_COLOR LCD_WHITE
526 #elif LCD_DEPTH > 1
527 #define BG_COLOR LCD_WHITE
528 #define FG_COLOR LCD_BLACK
529 #endif
531 #define CARD_WIDTH BMPWIDTH_card_back
532 #define CARD_HEIGHT BMPHEIGHT_card_back
534 /* This is the max amount of cards onscreen before condensing */
535 #define MAX_CARDS LCD_WIDTH/(CARD_WIDTH+4)
537 extern const fb_data card_deck[];
538 extern const fb_data card_back[];
540 #define NEXT_CARD bj->player_cards[done][bj->num_player_cards[done]]
542 /* dealer and player card positions */
543 unsigned int dealer_x, dealer_y, player_x, player_y;
545 typedef struct card {
546 unsigned int value; /* Card's value in Blackjack */
547 unsigned int num; /* Value on card face 0-12 (0=Ace, 1=2, 11=Q) */
548 unsigned int suit; /* 0:Spades, 1:Hearts, 2: Clubs; 3: Diamonds */
549 bool is_soft_ace;
550 } card;
552 typedef struct game_context {
553 struct card player_cards[2][22]; /* 22 Cards means the deal was all aces */
554 struct card dealer_cards[22]; /* That is the worst-case scenario */
555 unsigned int player_total;
556 unsigned int dealer_total;
557 signed int player_money;
558 unsigned int num_player_cards[2];
559 unsigned int num_dealer_cards;
560 unsigned int current_bet;
561 unsigned int split_status; /* 0 = split hasn't been asked, *
562 * 1 = split did not occur *
563 * 2 = split occurred *
564 * 3 = split occurred and 1st hand done */
565 bool is_blackjack;
566 bool end_hand;
567 bool asked_insurance;
568 } game_context;
570 static bool resume = false;
571 static bool resume_file = false;
572 static struct highscore highscores[NUM_SCORES];
574 /*****************************************************************************
575 * blackjack_init() initializes blackjack data structures.
576 ******************************************************************************/
577 static void blackjack_init(struct game_context* bj) {
578 /* seed the rand generator */
579 rb->srand(*rb->current_tick);
581 /* reset card positions */
582 dealer_x = 4;
583 dealer_y = LCD_HEIGHT/4 - CARD_HEIGHT/2;
584 player_x = 4;
585 player_y = LCD_HEIGHT - LCD_HEIGHT/4 - CARD_HEIGHT/2;
587 /* check for resumed game */
588 if(resume) return;
590 /* reset scoring */
591 bj->player_total = 0;
592 bj->dealer_total = 0;
593 bj->num_player_cards[0] = 2;
594 bj->num_player_cards[1] = 0;
595 bj->num_dealer_cards = 2;
596 bj->end_hand = false;
597 bj->split_status = 0;
598 bj->is_blackjack = false;
599 bj->asked_insurance = false;
602 /*****************************************************************************
603 * blackjack_drawtable() draws the table and some text.
604 ******************************************************************************/
605 static void blackjack_drawtable(struct game_context* bj) {
606 unsigned int w, h, y_loc;
607 char str[10];
609 #if LCD_HEIGHT <= 64
610 rb->lcd_getstringsize("Bet", &w, &h);
611 rb->lcd_putsxy(LCD_WIDTH - w, 2*h + 1, "Bet");
612 rb->snprintf(str, 9, "$%d", bj->current_bet);
613 rb->lcd_getstringsize(str, &w, &h);
614 rb->lcd_putsxy(LCD_WIDTH - w, 3*h + 1, str);
615 y_loc = LCD_HEIGHT/2;
616 #else
617 rb->lcd_getstringsize("Bet", &w, &h);
618 rb->lcd_putsxy(LCD_WIDTH - w, 5*h / 2, "Bet");
619 rb->snprintf(str, 9, "$%d", bj->current_bet);
620 rb->lcd_getstringsize(str, &w, &h);
621 rb->lcd_putsxy(LCD_WIDTH - w, 7*h / 2, str);
622 rb->lcd_hline(0, LCD_WIDTH, LCD_HEIGHT/2);
623 y_loc = LCD_HEIGHT/2 + h;
624 #endif
626 rb->lcd_putsxy(0,0, "Dealer");
627 rb->lcd_getstringsize("Player", &w, &h);
628 rb->lcd_putsxy(0, y_loc, "Player");
629 rb->lcd_getstringsize("Total", &w, &h);
630 rb->lcd_putsxy(LCD_WIDTH - w, y_loc, "Total");
631 rb->lcd_getstringsize("Money", &w, &h);
632 rb->lcd_putsxy(LCD_WIDTH - w, 0, "Money");
633 rb->snprintf(str, 9, "$%d", bj->player_money - bj->current_bet);
634 rb->lcd_getstringsize(str, &w, &h);
635 rb->lcd_putsxy(LCD_WIDTH - w, h + 1, str);
636 rb->snprintf(str, 3, "%d", bj->player_total);
637 rb->lcd_getstringsize(str, &w, &h);
638 rb->lcd_putsxy(LCD_WIDTH - w, y_loc + h, str);
641 /*****************************************************************************
642 * find_value() is passed a card and returns its blackjack value.
643 ******************************************************************************/
644 static unsigned int find_value(unsigned int number) {
645 unsigned int thisValue;
646 if (number == 0)
647 thisValue = 11; /* Aces get a value of 11 at first */
648 else if (number < 10)
649 thisValue = number + 1;
650 else
651 thisValue = 10; /* Anything 10 or higher gets a value of 10 */
653 return thisValue;
656 /*****************************************************************************
657 * draw_card() draws a card to the screen.
658 ******************************************************************************/
659 static void draw_card(struct card temp_card, bool shown,
660 unsigned int x, unsigned int y) {
661 if(shown)
662 rb->lcd_bitmap_part(card_deck, CARD_WIDTH*temp_card.num,
663 CARD_HEIGHT*temp_card.suit,
664 STRIDE( SCREEN_MAIN, BMPWIDTH_card_deck,
665 BMPHEIGHT_card_deck),
666 x+1, y+1, CARD_WIDTH, CARD_HEIGHT);
667 else
668 rb->lcd_bitmap(card_back, x+1, y+1,CARD_WIDTH, CARD_HEIGHT);
669 #if LCD_DEPTH > 1
670 rb->lcd_set_foreground(LCD_BLACK);
671 #endif
673 /* Print outlines */
674 #if CARD_WIDTH >= 26
675 rb->lcd_hline(x+2, x+CARD_WIDTH-1, y);
676 rb->lcd_hline(x+2, x+CARD_WIDTH-1, y+CARD_HEIGHT+1);
677 rb->lcd_vline(x, y+2, y+CARD_HEIGHT-3);
678 rb->lcd_vline(x+CARD_WIDTH+1, y+2, y+CARD_HEIGHT-1);
679 rb->lcd_drawpixel(x+1, y+1);
680 rb->lcd_drawpixel(x+1, y+CARD_HEIGHT);
681 rb->lcd_drawpixel(x+CARD_WIDTH, y+1);
682 rb->lcd_drawpixel(x+CARD_WIDTH, y+CARD_HEIGHT);
683 #else
684 rb->lcd_hline(x+1, x+CARD_WIDTH, y);
685 rb->lcd_hline(x+1, x+CARD_WIDTH, y+CARD_HEIGHT+1);
686 rb->lcd_vline(x, y+1, y+CARD_HEIGHT);
687 rb->lcd_vline(x+CARD_WIDTH+1, y+1, y+CARD_HEIGHT);
688 #endif
690 #if LCD_DEPTH > 1
691 rb->lcd_set_foreground(FG_COLOR);
692 #endif
695 /*****************************************************************************
696 * new_card() initializes a new card and gives it values.
697 ******************************************************************************/
698 static struct card new_card(void) {
699 struct card new_card;
700 new_card.suit = rb->rand()%4; /* Random number 0-3 */
701 new_card.num = rb->rand()%13; /* Random number 0-12 */
702 new_card.value = find_value(new_card.num);
703 new_card.is_soft_ace = (new_card.num == 0);
704 return new_card;
707 /*****************************************************************************
708 * deal_init_card() deals and draws to the screen the player's and dealer's
709 * initial cards.
710 ******************************************************************************/
711 static void deal_init_cards(struct game_context* bj) {
712 bj->dealer_cards[0] = new_card();
713 bj->dealer_total += bj->dealer_cards[0].value;
715 draw_card(bj->dealer_cards[0], false, dealer_x, dealer_y);
717 bj->dealer_cards[1] = new_card();
718 bj->dealer_total += bj->dealer_cards[1].value;
719 draw_card(bj->dealer_cards[1], true, dealer_x + CARD_WIDTH + 4, dealer_y);
721 bj->player_cards[0][0] = new_card();
722 bj->player_total += bj->player_cards[0][0].value;
723 draw_card(bj->player_cards[0][0], true, player_x, player_y);
724 player_x += CARD_WIDTH + 4;
726 bj->player_cards[0][1] = new_card();
727 bj->player_total += bj->player_cards[0][1].value;
728 draw_card(bj->player_cards[0][1], true, player_x, player_y);
729 player_x += CARD_WIDTH + 4;
732 /*****************************************************************************
733 * redraw_board() redraws all the cards and the board
734 ******************************************************************************/
735 static void redraw_board(struct game_context* bj) {
736 unsigned int i, n, upper_bound;
737 rb->lcd_clear_display();
739 blackjack_drawtable(bj);
740 player_x = 4;
741 dealer_x = 4;
742 upper_bound = bj->split_status > 1 ? 2 : 1;
744 for (i = 0; i < bj->num_dealer_cards; i++) {
745 if (!bj->end_hand) {
746 draw_card(bj->dealer_cards[0], false, dealer_x, dealer_y);
748 /* increment i so the dealer's first card isn't displayed */
749 i++;
750 dealer_x += CARD_WIDTH + 4;
752 draw_card(bj->dealer_cards[i], true, dealer_x, dealer_y);
754 if (bj->num_dealer_cards > MAX_CARDS-1)
755 dealer_x += 10;
756 else
757 dealer_x += CARD_WIDTH + 4;
760 for (n = 0; n < upper_bound; n++) {
761 for (i = 0; i < bj->num_player_cards[n]; i++) {
762 draw_card(bj->player_cards[n][i], true, player_x, player_y);
763 if (bj->split_status>1 || bj->num_player_cards[n]>MAX_CARDS)
764 player_x += 10;
765 else
766 player_x += CARD_WIDTH + 4;
768 if (bj->split_status > 1)
769 player_x = LCD_WIDTH/2 + 4;
773 /*****************************************************************************
774 * update_total updates the player's total
775 ******************************************************************************/
776 static void update_total(struct game_context* bj) {
777 char total[3];
778 unsigned int w, h;
779 rb->snprintf(total, 3, "%d", bj->player_total);
780 rb->lcd_getstringsize(total, &w, &h);
781 #if LCD_HEIGHT > 64
782 h *= 2;
783 #endif
784 rb->lcd_putsxy(LCD_WIDTH - w, LCD_HEIGHT/2 + h, total);
785 rb->lcd_update_rect(LCD_WIDTH - w, LCD_HEIGHT/2 + h, w, h);
789 /*****************************************************************************
790 * check_for_aces() is passed an array of cards and returns where an ace is
791 * located. Otherwise, returns -1.
792 ******************************************************************************/
793 static signed int check_for_aces(struct card temp_cards[], unsigned int size) {
794 unsigned int i;
795 for(i = 0; i < size; i++) {
796 if (temp_cards[i].is_soft_ace)
797 return i;
799 return -1;
802 /*****************************************************************************
803 * check_totals() compares player and dealer totals.
804 * 0: bust 1: loss, 2: push, 3: win, 4: blackjack, 5: something's not right...
805 ******************************************************************************/
806 static unsigned int check_totals(struct game_context* bj) {
807 unsigned int temp;
808 if (bj->player_total > 21)
809 temp = 0;
810 else if (bj->player_total == 21 && bj->is_blackjack) {
811 if (bj->dealer_total == 21 && bj->num_dealer_cards == 2)
812 temp = 2;
813 else
814 temp = 4;
816 else if (bj->player_total == bj->dealer_total)
817 temp = 2;
818 else if (bj->dealer_total > 21 && bj->player_total < 22)
819 temp = 3;
820 else if (bj->dealer_total > bj->player_total)
821 temp = 1;
822 else if (bj->player_total > bj->dealer_total)
823 temp = 3;
824 else
825 temp = 5;
827 return temp;
830 /*****************************************************************************
831 * finish_dealer() draws cards for the dealer until he has 17 or more.
832 ******************************************************************************/
833 static void finish_dealer(struct game_context* bj) {
834 signed int temp = 0;
836 if (bj->dealer_total > 16 && bj->dealer_total < 22)
837 return;
839 while (bj->dealer_total < 17) {
840 bj->dealer_cards[bj->num_dealer_cards] = new_card();
841 bj->dealer_total += bj->dealer_cards[bj->num_dealer_cards].value;
842 bj->num_dealer_cards++;
845 while (bj->dealer_total > 21) {
846 temp = check_for_aces(bj->dealer_cards, bj->num_dealer_cards);
847 if(temp != -1) {
848 bj->dealer_cards[temp].is_soft_ace = false;
849 bj->dealer_total -= 10;
851 else
852 return;
856 /*****************************************************************************
857 * finish_game() completes the game once player's turn is over.
858 ******************************************************************************/
859 static void finish_game(struct game_context* bj) {
860 unsigned int rValue, w, h;
861 char str[19];
863 do {
864 finish_dealer(bj);
865 } while (bj->dealer_total < 17);
867 redraw_board(bj);
868 rValue = check_totals(bj);
870 if (rValue == 0) {
871 rb->snprintf(str, sizeof(str), " Bust! ");
872 bj->player_money -= bj->current_bet;
874 else if (rValue == 1) {
875 rb->snprintf(str, sizeof(str), " Sorry, you lost. ");
876 bj->player_money -= bj->current_bet;
878 else if (rValue == 2) {
879 rb->snprintf(str, sizeof(str), " Push ");
881 else if (rValue == 3) {
882 rb->snprintf(str, sizeof(str), " You won! ");
883 bj->player_money+= bj->current_bet;
885 else {
886 rb->snprintf(str, sizeof(str), " Blackjack! ");
887 bj->player_money += bj->current_bet * 3 / 2;
889 rb->lcd_getstringsize(str, &w, &h);
891 #if LCD_HEIGHT <= 64
892 rb->lcd_set_drawmode(DRMODE_BG+DRMODE_INVERSEVID);
893 rb->lcd_fillrect(0, LCD_HEIGHT/2, LCD_WIDTH, LCD_HEIGHT/2);
894 rb->lcd_set_drawmode(DRMODE_SOLID);
895 rb->lcd_putsxy(LCD_WIDTH/2 - w/2, LCD_HEIGHT/2 + h, str);
896 rb->snprintf(str, 12, "You have %d", bj->player_total);
897 rb->lcd_getstringsize(str, &w, &h);
898 rb->lcd_putsxy(LCD_WIDTH/2 - w/2, LCD_HEIGHT/2, str);
899 #else
900 rb->lcd_putsxy(LCD_WIDTH/2 - w/2, LCD_HEIGHT/2 - h/2, str);
901 #endif
902 rb->lcd_update();
905 /*****************************************************************************
906 * blackjack_loadgame() loads the saved game and returns load success.
907 ******************************************************************************/
908 static bool blackjack_loadgame(struct game_context* bj) {
909 signed int fd;
910 bool loaded = false;
912 /* open game file */
913 fd = rb->open(SAVE_FILE, O_RDONLY);
914 if(fd < 0) return false;
916 /* read in saved game */
917 if(rb->read(fd, bj, sizeof(struct game_context))
918 == (long)sizeof(struct game_context))
920 loaded = true;
923 rb->close(fd);
925 return loaded;
928 /*****************************************************************************
929 * blackjack_savegame() saves the current game state.
930 ******************************************************************************/
931 static void blackjack_savegame(struct game_context* bj) {
932 int fd;
934 if(!resume)
935 return;
936 /* write out the game state to the save file */
937 fd = rb->open(SAVE_FILE, O_WRONLY|O_CREAT, 0666);
938 if(fd < 0)
939 return;
940 rb->write(fd, bj, sizeof(struct game_context));
941 rb->close(fd);
944 /*****************************************************************************
945 * blackjack_get_yes_no() gets a yes/no answer from the user
946 ******************************************************************************/
947 static unsigned int blackjack_get_yes_no(char message[20]) {
948 int button;
949 unsigned int w, h, b, choice = 0;
950 bool breakout = false;
951 char message_yes[24], message_no[24];
953 rb->strcpy(message_yes, message);
954 rb->strcpy(message_no, message);
955 rb->strcat(message_yes, " Yes");
956 rb->strcat(message_no, " No");
957 rb->lcd_getstringsize(message_yes, &w, &h);
958 const char *stg[] = {message_yes, message_no};
960 #if LCD_HEIGHT <= 64
961 b = 2*h+1;
962 #else
963 b = h-1;
964 #endif
966 #ifdef HAVE_LCD_COLOR
967 rb->lcd_fillrect(LCD_WIDTH/2 - w/2, LCD_HEIGHT/2 + b, w+1, h+3);
968 rb->lcd_set_foreground(LCD_BLACK);
969 rb->lcd_set_background(LCD_WHITE);
970 #else
971 rb->lcd_set_drawmode(DRMODE_BG+DRMODE_INVERSEVID);
972 rb->lcd_fillrect(LCD_WIDTH/2 - w/2, LCD_HEIGHT/2 + b, w+1, h+3);
973 rb->lcd_set_drawmode(DRMODE_SOLID);
974 #endif
975 rb->lcd_drawrect(LCD_WIDTH/2 - w/2 - 1, LCD_HEIGHT/2 + b - 1, w+3, h+4);
977 while(!breakout) {
978 rb->lcd_putsxy(LCD_WIDTH/2 - w/2, LCD_HEIGHT/2 + b +1, stg[choice]);
979 rb->lcd_update_rect(LCD_WIDTH/2 - w/2 - 1, LCD_HEIGHT/2 + b -1,
980 w+3, h+4);
981 button = rb->button_get(true);
983 switch(button) {
984 case BJACK_LEFT:
985 case (BJACK_LEFT|BUTTON_REPEAT):
986 case BJACK_RIGHT:
987 case (BJACK_RIGHT|BUTTON_REPEAT):
988 choice ^= 1;
989 break;
990 case BJACK_SELECT: breakout = true;
991 break;
992 case BJACK_QUIT: breakout = true;
993 choice = 1;
994 break;
998 #if LCD_DEPTH > 1
999 rb->lcd_set_foreground(FG_COLOR);
1000 rb->lcd_set_background(BG_COLOR);
1001 #endif
1002 return choice;
1005 /*****************************************************************************
1006 * blackjack_get_amount() gets an amount from the player to be used
1007 ******************************************************************************/
1008 static signed int blackjack_get_amount(char message[20], signed int lower_limit,
1009 signed int upper_limit,
1010 signed int start) {
1011 int button;
1012 bool breakout = false, changed = false;
1013 unsigned int w, h;
1014 signed int amount;
1016 rb->lcd_getstringsize("A", &w, &h); /* find the size of one character */
1018 if (start > upper_limit)
1019 amount = upper_limit;
1020 else if (start < lower_limit)
1021 amount = lower_limit;
1022 else
1023 amount = start;
1025 #if LCD_DEPTH > 1
1026 rb->lcd_set_background(LCD_WHITE);
1027 rb->lcd_set_foreground(LCD_BLACK);
1028 #endif
1030 #if LCD_HEIGHT <= 64
1031 rb->lcd_clear_display();
1032 rb->lcd_puts(0, 1, message);
1033 rb->lcd_putsf(0, 2, "$%d", amount);
1034 rb->lcd_puts(0, 3, "RIGHT: +1");
1035 rb->lcd_puts(0, 4, "LEFT: -1");
1036 rb->lcd_puts(0, 5, "UP: +10");
1037 rb->lcd_puts(0, 6, "DOWN: -10");
1038 rb->lcd_update();
1039 #else
1040 rb->lcd_set_drawmode(DRMODE_BG+DRMODE_INVERSEVID);
1041 rb->lcd_fillrect(LCD_WIDTH/2 - 9*w - 1, LCD_HEIGHT/2 - 4*h - 3,
1042 37*w / 2, 8*h -3);
1043 rb->lcd_set_drawmode(DRMODE_SOLID);
1044 rb->lcd_drawrect(LCD_WIDTH/2 - 9*w - 1, LCD_HEIGHT/2 - 4*h - 3,
1045 37*w / 2, 8*h -3);
1046 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 4*h - 1, message);
1047 rb->lcd_putsxyf(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 3*h, "$%d", amount);
1048 #if (CONFIG_KEYPAD == IPOD_4G_PAD) || \
1049 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
1050 (CONFIG_KEYPAD == IPOD_1G2G_PAD) || \
1051 (CONFIG_KEYPAD == SANSA_E200_PAD) || \
1052 (CONFIG_KEYPAD == SANSA_FUZE_PAD) || \
1053 (CONFIG_KEYPAD == SANSA_CONNECT_PAD)
1054 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - h-2, " >>|: +1");
1055 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 1, " |<<: -1");
1056 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 + h, "SCROLL+: +10");
1057 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 + 2*h + 1, "SCROLL-: -10");
1058 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
1059 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - h-2, "RIGHT: +1");
1060 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 1, "LEFT: -1");
1061 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 + h, "SCROLL+: +10");
1062 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 + 2*h + 1, "SCROLL-: -10");
1063 #else
1064 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - h-2, "RIGHT: +1");
1065 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 1, "LEFT: -1");
1066 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 + h, "UP: +10");
1067 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 + 2*h + 1, "DOWN: -10");
1068 #endif
1069 rb->lcd_update_rect(LCD_WIDTH/2 - 9*w - 1, LCD_HEIGHT/2 - 4*h - 3,
1070 37*w / 2, 8*h -3);
1071 #endif
1073 while(!breakout) {
1074 button = rb->button_get(true);
1076 switch(button) {
1077 case BJACK_UP:
1078 case (BJACK_UP|BUTTON_REPEAT):
1079 if (amount + 10 < upper_limit + 1) {
1080 amount += 10;
1081 changed = true;
1083 break;
1084 case BJACK_DOWN:
1085 case (BJACK_DOWN|BUTTON_REPEAT):
1086 if (amount - 10 > lower_limit - 1) {
1087 amount -= 10;
1088 changed = true;
1090 break;
1091 case BJACK_RIGHT:
1092 case (BJACK_RIGHT|BUTTON_REPEAT):
1093 if (amount + 1 < upper_limit + 1) {
1094 amount++;
1095 changed = true;
1097 break;
1098 case BJACK_LEFT:
1099 case (BJACK_LEFT|BUTTON_REPEAT):
1100 if (amount - 1 > lower_limit - 1) {
1101 amount--;
1102 changed = true;
1104 break;
1105 #ifdef BJACK_MAX
1106 case BJACK_MAX :
1107 amount = upper_limit;
1108 changed = true;
1109 break;
1110 #endif
1111 #ifdef BJACK_MIN
1112 case BJACK_MIN :
1113 amount = lower_limit;
1114 changed = true;
1115 break;
1116 #endif
1117 case BJACK_QUIT:
1118 breakout = true;
1119 amount = 0;
1120 break;
1121 case BJACK_SELECT:
1122 breakout = true;
1123 break;
1126 if(changed) {
1127 #if LCD_HEIGHT <= 64
1128 rb->lcd_putsf(0, 2, "$%d", amount);
1129 rb->lcd_update();
1130 #else
1131 rb->lcd_set_drawmode(DRMODE_BG+DRMODE_INVERSEVID);
1132 rb->lcd_fillrect(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 3*h, 5*w, h);
1133 rb->lcd_set_drawmode(DRMODE_SOLID);
1134 rb->lcd_putsxyf(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 3*h, "$%d", amount);
1135 rb->lcd_update_rect(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 3*h, 5*w, h);
1136 #endif
1137 changed = false;
1141 #if LCD_DEPTH > 1
1142 rb->lcd_set_foreground(FG_COLOR);
1143 rb->lcd_set_background(BG_COLOR);
1144 #endif
1145 rb->lcd_clear_display();
1146 return amount;
1149 /*****************************************************************************
1150 * blackjack_get_bet() gets the player's bet.
1151 ******************************************************************************/
1152 static void blackjack_get_bet(struct game_context* bj) {
1153 bj->current_bet = blackjack_get_amount("Please enter a bet", 10,
1154 bj->player_money, bj->current_bet);
1157 /*****************************************************************************
1158 * double_down() returns one final card then finishes the game
1159 ******************************************************************************/
1160 static void double_down(struct game_context* bj) {
1161 bj->current_bet *= 2;
1162 bj->player_cards[0][bj->num_player_cards[0]] = new_card();
1163 bj->player_total += bj->player_cards[0][bj->num_player_cards[0]].value;
1164 bj->num_player_cards[0]++;
1167 /*****************************************************************************
1168 * split() checks if the player wants to split and acts accordingly.
1169 * When bj->split_status is 1, no split occurred. 2 means the player split and 3
1170 * means a split has already occurred and the first hand is done.
1171 ******************************************************************************/
1172 static void split(struct game_context* bj) {
1173 if (blackjack_get_yes_no("Split?") != 0)
1174 bj->split_status = 1;
1175 else {
1176 bj->split_status = 2;
1177 bj->current_bet *= 2;
1178 bj->num_player_cards[0] = 1;
1179 bj->num_player_cards[1] = 1;
1180 bj->player_cards[1][0] = bj->player_cards[0][1];
1181 bj->player_total = bj->player_cards[0][0].value;
1185 /*****************************************************************************
1186 * insurance() see if the player wants to buy insurance and how much.
1187 ******************************************************************************/
1188 static unsigned int insurance(struct game_context* bj) {
1189 unsigned int insurance, max_amount;
1191 insurance = blackjack_get_yes_no("Buy Insurance?");
1192 bj->asked_insurance = true;
1193 max_amount = bj->current_bet < (unsigned int)bj->player_money ?
1194 bj->current_bet/2 : (unsigned int)bj->player_money;
1195 if (insurance != 0) return 0;
1197 insurance = blackjack_get_amount("How much?", 0, max_amount, 0);
1198 redraw_board(bj);
1199 return insurance;
1202 /*****************************************************************************
1203 * play_again() checks to see if the player wants to keep playing.
1204 ******************************************************************************/
1205 static unsigned int play_again(void) {
1206 return blackjack_get_yes_no("Play Again?");
1209 /*****************************************************************************
1210 * blackjack_help() displays help text.
1211 ******************************************************************************/
1212 static bool blackjack_help(void) {
1213 static char *help_text[] = {
1214 "Blackjack", "", "Aim", "",
1215 "Try", "to", "get", "as", "close", "to", "21", "without", "going",
1216 "over", "or", "simply", "beat", "out", "the", "dealer", "for", "the",
1217 "best", "hand.", "", "",
1218 "Controls", "",
1219 BJACK_SELECT_NAME, ":", "hit", "/", "select", "",
1220 BJACK_STAY_NAME, ":", "stay", "",
1221 BJACK_DOUBLE_NAME, ":", "double", "down", "",
1222 BJACK_QUIT_NAME, ":", "go", "to", "menu", "",
1224 static struct style_text formation[]={
1225 { 0, TEXT_CENTER|TEXT_UNDERLINE },
1226 { 2, C_RED },
1227 { 26, C_RED },
1228 LAST_STYLE_ITEM
1231 rb->lcd_setfont(FONT_UI);
1232 #ifdef HAVE_LCD_COLOR
1233 rb->lcd_set_background(LCD_BLACK);
1234 rb->lcd_set_foreground(LCD_WHITE);
1235 #endif
1236 if (display_text(ARRAYLEN(help_text), help_text, formation, NULL, true))
1237 return true;
1238 rb->lcd_setfont(FONT_SYSFIXED);
1240 return false;
1243 static int blackjack_menu_cb(int action, const struct menu_item_ex *this_item)
1245 int i = ((intptr_t)this_item);
1246 if(action == ACTION_REQUEST_MENUITEM
1247 && !resume && (i==0 || i==5))
1248 return ACTION_EXIT_MENUITEM;
1249 return action;
1252 /*****************************************************************************
1253 * blackjack_menu() is the initial menu at the start of the game.
1254 ******************************************************************************/
1255 static unsigned int blackjack_menu(void) {
1256 int selection = 0;
1257 bool breakout = false;
1259 MENUITEM_STRINGLIST(menu, "BlackJack Menu", blackjack_menu_cb,
1260 "Resume Game", "Start New Game",
1261 "High Scores", "Help",
1262 "Playback Control",
1263 "Quit without Saving", "Quit");
1265 while(!breakout) {
1266 switch(rb->do_menu(&menu, &selection, NULL, false)) {
1267 case 0:
1268 breakout = true;
1269 if(resume_file)
1270 rb->remove(SAVE_FILE);
1271 resume_file = false;
1272 break;
1273 case 1:
1274 breakout = true;
1275 resume = false;
1276 break;
1277 case 2:
1278 highscore_show(-1, highscores, NUM_SCORES, false);
1279 break;
1280 case 3:
1281 if(blackjack_help())
1282 return BJ_USB;
1283 break;
1284 case 4:
1285 if (playback_control(NULL))
1286 return BJ_USB;
1287 break;
1288 case 5:
1289 return BJ_QUIT_WITHOUT_SAVING;
1290 case 6:
1291 if (resume)
1292 return BJ_QUIT;
1293 else
1294 return BJ_QUIT_WITHOUT_SAVING;
1296 case MENU_ATTACHED_USB:
1297 return BJ_USB;
1299 default:
1300 break;
1304 return 0;
1307 /*****************************************************************************
1308 * blackjack() is the main game subroutine, it returns the final game status.
1309 ******************************************************************************/
1310 static int blackjack(struct game_context* bj) {
1311 int button;
1312 unsigned int w, h, temp_var, done = 0, todo = 1;
1313 signed int temp;
1314 bool breakout = false;
1315 bool dbl_down = false;
1317 /********************
1318 * menu *
1319 ********************/
1320 temp_var = blackjack_menu();
1321 if (temp_var != 0)
1322 return temp_var;
1324 #if LCD_DEPTH > 1
1325 rb->lcd_set_background(BG_COLOR);
1326 rb->lcd_set_foreground(FG_COLOR);
1327 #endif
1329 /********************
1330 * init *
1331 ********************/
1332 blackjack_init(bj);
1334 /********************
1335 * play *
1336 ********************/
1338 resume_file = false;
1339 /* check for resumed game */
1340 if(resume) {
1341 resume = false;
1342 redraw_board(bj);
1343 if (bj->split_status == 2) {
1344 todo=2;
1345 player_x = bj->num_player_cards[0] * 10 + 4;
1347 else if (bj->split_status == 3) {
1348 player_x = bj->num_player_cards[1] * 10 + LCD_WIDTH/2 + 4;
1349 todo=2;
1350 done=1;
1353 else {
1354 bj->player_money = 1000;
1355 bj->current_bet = 10;
1356 blackjack_get_bet(bj);
1357 if (bj->current_bet == 0)
1358 return -1;
1359 rb->lcd_clear_display();
1360 deal_init_cards(bj);
1361 blackjack_drawtable(bj);
1364 rb->lcd_update();
1366 breakout = false;
1368 while(true){
1369 if(bj->player_total == 21 && bj->num_player_cards[0] == 2) {
1370 bj->is_blackjack = true;
1371 bj->end_hand = true;
1372 finish_game(bj);
1374 else if(bj->dealer_cards[1].is_soft_ace && !breakout &&
1375 !bj->asked_insurance) {
1376 temp_var = insurance(bj);
1377 if (bj->dealer_total == 21) {
1378 rb->splash(HZ, "Dealer has blackjack");
1379 bj->player_money += temp_var;
1380 bj->end_hand = true;
1381 breakout = true;
1382 redraw_board(bj);
1383 finish_game(bj);
1385 else {
1386 rb->splash(HZ, "Dealer does not have blackjack");
1387 bj->player_money -= temp_var;
1388 breakout = true;
1389 redraw_board(bj);
1390 rb->lcd_update();
1393 if(!bj->end_hand && bj->split_status == 0 &&
1394 bj->player_cards[0][0].num == bj->player_cards[0][1].num) {
1395 split(bj);
1396 redraw_board(bj);
1397 rb->lcd_update_rect(0, LCD_HEIGHT/2, LCD_WIDTH, LCD_HEIGHT/2);
1398 if (bj->split_status == 2) {
1399 todo++;
1400 player_x = bj->num_player_cards[0] * 10 + 4;
1404 while(!bj->end_hand && done < todo) {
1405 button = rb->button_get(true);
1407 switch(button) {
1408 case BJACK_SELECT:
1409 NEXT_CARD = new_card();
1410 bj->player_total += NEXT_CARD.value;
1411 draw_card(NEXT_CARD, true, player_x, player_y);
1412 bj->num_player_cards[done]++;
1413 if (bj->num_player_cards[done] == MAX_CARDS + 1) {
1414 redraw_board(bj);
1415 rb->lcd_update_rect(0, LCD_HEIGHT/2, LCD_WIDTH,
1416 LCD_HEIGHT/2);
1418 else if (bj->num_player_cards[done]>MAX_CARDS || todo > 1) {
1419 rb->lcd_update_rect(player_x, player_y, CARD_WIDTH+2,
1420 CARD_HEIGHT+2);
1421 player_x += 10;
1423 else {
1424 rb->lcd_update_rect(player_x, player_y, CARD_WIDTH+2,
1425 CARD_HEIGHT+2);
1426 player_x += CARD_WIDTH + 4;
1428 update_total(bj);
1430 break;
1431 case BJACK_STAY:
1432 bj->end_hand = true;
1433 break;
1434 case BJACK_DOUBLEDOWN:
1435 if ((signed int)bj->current_bet * 2 <
1436 bj->player_money + 1 &&
1437 bj->num_player_cards[0]==2 && todo==1) {
1438 double_down(bj);
1439 dbl_down = true;
1440 if (bj->player_total < 22) {
1441 bj->end_hand = true;
1442 finish_game(bj);
1445 else if((signed int)bj->current_bet * 2 >
1446 bj->player_money){
1447 rb->splash(HZ, "Not enough money to double down.");
1448 redraw_board(bj);
1449 rb->lcd_update();
1451 break;
1453 case BJACK_QUIT:
1454 resume = true;
1455 return BJ_END;
1458 while (bj->player_total > 21 && !bj->end_hand) {
1459 temp = check_for_aces(bj->player_cards[done],
1460 bj->num_player_cards[done]);
1461 if(temp != -1) {
1462 bj->player_cards[done][temp].is_soft_ace = false;
1463 bj->player_total -= 10;
1464 update_total(bj);
1465 if (dbl_down) {
1466 bj->end_hand = true;
1467 finish_game(bj);
1470 else
1471 bj->end_hand = true;
1474 if (bj->end_hand) {
1475 done++;
1476 if(todo > 1) {
1477 if (done == 2) {
1478 temp = bj->player_total;
1479 bj->player_total = temp_var;
1480 temp_var = temp;
1481 finish_game(bj);
1482 rb->lcd_getstringsize(" Split 1 ", &w, &h);
1483 rb->lcd_putsxy(LCD_WIDTH/2-w/2, LCD_HEIGHT/2-3*h/2,
1484 " Split 1 ");
1485 rb->lcd_update_rect(LCD_WIDTH/2-w/2, LCD_HEIGHT/2-3*h/2,
1486 w,h);
1487 bj->current_bet /= 2;
1488 rb->lcd_update_rect(LCD_WIDTH/2-w/2, LCD_HEIGHT/2-3*h/2,
1489 w,h);
1490 rb->sleep(HZ*2);
1491 bj->player_total = temp_var;
1492 finish_game(bj);
1493 rb->lcd_getstringsize(" Split 2 ", &w, &h);
1494 rb->lcd_putsxy(LCD_WIDTH/2-w/2, LCD_HEIGHT/2-3*h/2,
1495 " Split 2 ");
1496 rb->lcd_update_rect(LCD_WIDTH/2-w/2, LCD_HEIGHT/2-3*h/2,
1497 w,h);
1498 rb->sleep(HZ*2);
1500 else {
1501 bj->end_hand = false;
1502 bj->split_status = 3;
1503 temp_var = bj->player_total;
1504 bj->player_total = bj->player_cards[1][0].value;
1505 update_total(bj);
1506 redraw_board(bj);
1507 player_x += 10;
1508 rb->lcd_update();
1511 else
1512 finish_game(bj);
1516 if (bj->player_money < 10) {
1517 rb->sleep(HZ);
1518 return BJ_LOSE;
1521 if (bj->end_hand) { /* If hand is over */
1522 if (play_again() != 0) /* User wants to quit */
1523 return BJ_END;
1524 else { /* User keeps playing */
1525 breakout = false;
1526 temp = bj->current_bet;
1527 bj->current_bet = 0;
1528 redraw_board(bj);
1529 rb->lcd_update();
1530 bj->current_bet = temp;
1531 if(dbl_down) {
1532 bj->current_bet /= 2;
1533 dbl_down = false;
1535 done = 0;
1536 todo = 1;
1537 blackjack_init(bj);
1538 blackjack_get_bet(bj);
1539 if (bj->current_bet == 0)
1540 return BJ_END;
1541 deal_init_cards(bj);
1542 blackjack_drawtable(bj);
1543 rb->lcd_update();
1547 /* Never reached */
1548 return PLUGIN_OK;
1551 /*****************************************************************************
1552 * plugin entry point.
1553 ******************************************************************************/
1554 enum plugin_status plugin_start(const void* parameter)
1556 struct game_context bj;
1557 bool exit = false;
1559 (void)parameter;
1561 #if LCD_DEPTH > 1
1562 rb->lcd_set_backdrop(NULL);
1563 #endif
1565 /* load high scores */
1566 highscore_load(SCORE_FILE, highscores, NUM_SCORES);
1567 resume = blackjack_loadgame(&bj);
1568 resume_file = resume;
1570 rb->lcd_setfont(FONT_SYSFIXED);
1572 while(!exit) {
1573 switch(blackjack(&bj)){
1574 case BJ_LOSE:
1575 rb->splash(HZ, "Not enough money to continue");
1576 /* fall through to BJ_END */
1578 case BJ_END:
1579 if(!resume && bj.player_money > 10) {
1580 /* There is no level, so store -1 to blank column */
1581 int position = highscore_update(bj.player_money, -1, "",
1582 highscores, NUM_SCORES);
1583 if (position != -1)
1585 if (position==0)
1586 rb->splash(HZ*2, "New High Score");
1587 highscore_show(position, highscores, NUM_SCORES, false);
1590 break;
1592 case BJ_USB:
1593 highscore_save(SCORE_FILE, highscores, NUM_SCORES);
1594 return PLUGIN_USB_CONNECTED;
1596 case BJ_QUIT:
1597 rb->splash(HZ*1, "Saving game...");
1598 blackjack_savegame(&bj);
1599 /* fall through */
1601 case BJ_QUIT_WITHOUT_SAVING:
1602 exit = true;
1603 break;
1605 default:
1606 break;
1609 highscore_save(SCORE_FILE, highscores, NUM_SCORES);
1610 return PLUGIN_OK;