make sure plugin reset backlight setting before exit. do code polish.
[kugel-rb.git] / apps / plugins / blackjack.c
blob315f21f27b13fb3c924fe8d6f3edee85f1de16b4
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"
29 PLUGIN_HEADER
31 /* save files */
32 #define HIGH_SCORE PLUGIN_GAMES_DIR "/blackjack.score"
33 #define SAVE_FILE PLUGIN_GAMES_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_RESUME_NAME "F3"
49 #define BJACK_QUIT_NAME "OFF"
50 #define BJACK_DOUBLE_NAME "F2"
51 #define BJACK_SELECT BUTTON_PLAY
52 #define BJACK_QUIT BUTTON_OFF
53 #define BJACK_MAX (BUTTON_ON|BUTTON_UP)
54 #define BJACK_MIN (BUTTON_ON|BUTTON_DOWN)
55 #define BJACK_STAY BUTTON_F1
56 #define BJACK_DOUBLEDOWN BUTTON_F2
57 #define BJACK_RESUME BUTTON_F3
58 #define BJACK_UP BUTTON_UP
59 #define BJACK_DOWN BUTTON_DOWN
60 #define BJACK_RIGHT BUTTON_RIGHT
61 #define BJACK_LEFT BUTTON_LEFT
63 #elif CONFIG_KEYPAD == ONDIO_PAD
64 #define BJACK_SELECT_NAME "MENU"
65 #define BJACK_STAY_NAME "RIGHT"
66 #define BJACK_RESUME_NAME "DOWN"
67 #define BJACK_QUIT_NAME "OFF"
68 #define BJACK_DOUBLE_NAME "UP"
69 #define BJACK_SELECT BUTTON_MENU
70 #define BJACK_QUIT BUTTON_OFF
71 #define BJACK_MAX (BUTTON_MENU|BUTTON_UP)
72 #define BJACK_MIN (BUTTON_MENU|BUTTON_DOWN)
73 #define BJACK_STAY BUTTON_RIGHT
74 #define BJACK_DOUBLEDOWN BUTTON_UP
75 #define BJACK_RESUME BUTTON_DOWN
76 #define BJACK_UP BUTTON_UP
77 #define BJACK_DOWN BUTTON_DOWN
78 #define BJACK_RIGHT BUTTON_RIGHT
79 #define BJACK_LEFT BUTTON_LEFT
81 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
82 #define BJACK_SELECT_NAME "PLAY"
83 #define BJACK_STAY_NAME ">>|"
84 #define BJACK_RESUME_NAME "RIGHT"
85 #define BJACK_QUIT_NAME "POWER"
86 #define BJACK_DOUBLE_NAME "|<<"
87 #define BJACK_SELECT BUTTON_PLAY
88 #define BJACK_QUIT BUTTON_POWER
89 #define BJACK_MAX (BUTTON_PLAY|BUTTON_SCROLL_UP)
90 #define BJACK_MIN (BUTTON_PLAY|BUTTON_SCROLL_DOWN)
91 #define BJACK_STAY BUTTON_FF
92 #define BJACK_DOUBLEDOWN BUTTON_REW
93 #define BJACK_RESUME BUTTON_RIGHT
94 #define BJACK_UP BUTTON_SCROLL_UP
95 #define BJACK_DOWN BUTTON_SCROLL_DOWN
96 #define BJACK_RIGHT BUTTON_RIGHT
97 #define BJACK_LEFT BUTTON_LEFT
99 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
100 (CONFIG_KEYPAD == IRIVER_H300_PAD)
101 #define BJACK_SELECT_NAME "ON"
102 #define BJACK_STAY_NAME "REC"
103 #define BJACK_RESUME_NAME "MODE"
104 #define BJACK_QUIT_NAME "OFF"
105 #define BJACK_DOUBLE_NAME "SELECT"
106 #define BJACK_SELECT BUTTON_ON
107 #define BJACK_QUIT BUTTON_OFF
108 #define BJACK_MAX (BUTTON_ON|BUTTON_UP)
109 #define BJACK_MIN (BUTTON_ON|BUTTON_DOWN)
110 #define BJACK_STAY BUTTON_REC
111 #define BJACK_DOUBLEDOWN BUTTON_SELECT
112 #define BJACK_RESUME BUTTON_MODE
113 #define BJACK_UP BUTTON_UP
114 #define BJACK_DOWN BUTTON_DOWN
115 #define BJACK_RIGHT BUTTON_RIGHT
116 #define BJACK_LEFT BUTTON_LEFT
118 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \
119 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
120 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
121 #define BJACK_SELECT_NAME "SELECT"
122 #define BJACK_STAY_NAME "RIGHT"
123 #define BJACK_RESUME_NAME "PLAY"
124 #define BJACK_QUIT_NAME "MENU"
125 #define BJACK_DOUBLE_NAME "LEFT"
126 #define BJACK_SELECT BUTTON_SELECT
127 #define BJACK_QUIT BUTTON_MENU
128 #define BJACK_MAX (BUTTON_SELECT|BUTTON_SCROLL_FWD)
129 #define BJACK_MIN (BUTTON_SELECT|BUTTON_SCROLL_BACK)
130 #define BJACK_STAY BUTTON_RIGHT
131 #define BJACK_DOUBLEDOWN BUTTON_LEFT
132 #define BJACK_RESUME BUTTON_PLAY
133 #define BJACK_UP BUTTON_SCROLL_FWD
134 #define BJACK_DOWN BUTTON_SCROLL_BACK
135 #define BJACK_RIGHT BUTTON_RIGHT
136 #define BJACK_LEFT BUTTON_LEFT
138 #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD
139 #define BJACK_SELECT_NAME "SELECT"
140 #define BJACK_STAY_NAME "REC"
141 #define BJACK_RESUME_NAME "DOWN"
142 #define BJACK_QUIT_NAME "POWER"
143 #define BJACK_DOUBLE_NAME "PLAY"
144 #define BJACK_SELECT BUTTON_SELECT
145 #define BJACK_QUIT BUTTON_POWER
146 #define BJACK_MAX (BUTTON_PLAY|BUTTON_UP)
147 #define BJACK_MIN (BUTTON_PLAY|BUTTON_DOWN)
148 #define BJACK_STAY BUTTON_REC
149 #define BJACK_DOUBLEDOWN BUTTON_PLAY
150 #define BJACK_RESUME BUTTON_DOWN
151 #define BJACK_UP BUTTON_UP
152 #define BJACK_DOWN BUTTON_DOWN
153 #define BJACK_RIGHT BUTTON_RIGHT
154 #define BJACK_LEFT BUTTON_LEFT
156 #elif CONFIG_KEYPAD == IRIVER_IFP7XX_PAD
157 #define BJACK_SELECT_NAME "MODE"
158 #define BJACK_STAY_NAME "MODE"
159 #define BJACK_RESUME_NAME "EQ+MODE"
160 #define BJACK_QUIT_NAME "PLAY"
161 #define BJACK_DOUBLE_NAME "SELECT"
162 #define BJACK_SELECT BUTTON_MODE
163 #define BJACK_QUIT BUTTON_PLAY
164 #define BJACK_MAX (BUTTON_EQ|BUTTON_UP)
165 #define BJACK_MIN (BUTTON_EQ|BUTTON_DOWN)
166 #define BJACK_STAY BUTTON_MODE
167 #define BJACK_DOUBLEDOWN BUTTON_SELECT
168 #define BJACK_RESUME (BUTTON_EQ|BUTTON_MODE)
169 #define BJACK_UP BUTTON_UP
170 #define BJACK_DOWN BUTTON_DOWN
171 #define BJACK_RIGHT BUTTON_RIGHT
172 #define BJACK_LEFT BUTTON_LEFT
174 #elif CONFIG_KEYPAD == GIGABEAT_PAD
175 #define BJACK_SELECT_NAME "SELECT"
176 #define BJACK_STAY_NAME "VOL-"
177 #define BJACK_RESUME_NAME "MENU"
178 #define BJACK_QUIT_NAME "POWER"
179 #define BJACK_DOUBLE_NAME "A"
180 #define BJACK_SELECT BUTTON_SELECT
181 #define BJACK_QUIT BUTTON_POWER
182 #define BJACK_MAX BUTTON_VOL_UP
183 #define BJACK_MIN BUTTON_VOL_DOWN
184 #define BJACK_STAY BUTTON_VOL_DOWN
185 #define BJACK_DOUBLEDOWN BUTTON_A
186 #define BJACK_RESUME BUTTON_MENU
187 #define BJACK_UP BUTTON_UP
188 #define BJACK_DOWN BUTTON_DOWN
189 #define BJACK_RIGHT BUTTON_RIGHT
190 #define BJACK_LEFT BUTTON_LEFT
192 #elif CONFIG_KEYPAD == SANSA_E200_PAD
193 #define BJACK_SELECT_NAME "SELECT"
194 #define BJACK_STAY_NAME "RIGHT"
195 #define BJACK_RESUME_NAME "DOWN"
196 #define BJACK_QUIT_NAME "POWER"
197 #define BJACK_DOUBLE_NAME "LEFT"
198 #define BJACK_SELECT BUTTON_SELECT
199 #define BJACK_QUIT BUTTON_POWER
200 #define BJACK_MAX (BUTTON_REC|BUTTON_UP)
201 #define BJACK_MIN (BUTTON_REC|BUTTON_DOWN)
202 #define BJACK_STAY BUTTON_RIGHT
203 #define BJACK_DOUBLEDOWN BUTTON_LEFT
204 #define BJACK_RESUME BUTTON_DOWN
205 #define BJACK_UP BUTTON_SCROLL_FWD
206 #define BJACK_DOWN BUTTON_SCROLL_BACK
207 #define BJACK_RIGHT BUTTON_RIGHT
208 #define BJACK_LEFT BUTTON_LEFT
210 #elif CONFIG_KEYPAD == SANSA_FUZE_PAD
211 #define BJACK_SELECT_NAME "SELECT"
212 #define BJACK_STAY_NAME "RIGHT"
213 #define BJACK_RESUME_NAME "UP"
214 #define BJACK_QUIT_NAME "HOME"
215 #define BJACK_DOUBLE_NAME "LEFT"
216 #define BJACK_SELECT BUTTON_SELECT
217 #define BJACK_QUIT (BUTTON_HOME|BUTTON_REPEAT)
218 #define BJACK_MAX (BUTTON_SELECT|BUTTON_UP)
219 #define BJACK_MIN (BUTTON_SELECT|BUTTON_DOWN)
220 #define BJACK_STAY BUTTON_RIGHT
221 #define BJACK_DOUBLEDOWN BUTTON_LEFT
222 #define BJACK_RESUME BUTTON_UP
223 #define BJACK_UP BUTTON_SCROLL_FWD
224 #define BJACK_DOWN BUTTON_SCROLL_BACK
225 #define BJACK_RIGHT BUTTON_RIGHT
226 #define BJACK_LEFT BUTTON_LEFT
228 #elif CONFIG_KEYPAD == SANSA_C200_PAD
229 #define BJACK_SELECT_NAME "SELECT"
230 #define BJACK_STAY_NAME "RIGHT"
231 #define BJACK_RESUME_NAME "DOWN"
232 #define BJACK_QUIT_NAME "POWER"
233 #define BJACK_DOUBLE_NAME "LEFT"
234 #define BJACK_SELECT BUTTON_SELECT
235 #define BJACK_QUIT BUTTON_POWER
236 #define BJACK_MAX BUTTON_VOL_UP
237 #define BJACK_MIN BUTTON_VOL_DOWN
238 #define BJACK_STAY BUTTON_RIGHT
239 #define BJACK_DOUBLEDOWN BUTTON_LEFT
240 #define BJACK_RESUME BUTTON_DOWN
241 #define BJACK_UP BUTTON_UP
242 #define BJACK_DOWN BUTTON_DOWN
243 #define BJACK_RIGHT BUTTON_RIGHT
244 #define BJACK_LEFT BUTTON_LEFT
246 #elif CONFIG_KEYPAD == SANSA_CLIP_PAD
247 #define BJACK_SELECT_NAME "SELECT"
248 #define BJACK_STAY_NAME "RIGHT"
249 #define BJACK_RESUME_NAME "DOWN"
250 #define BJACK_QUIT_NAME "POWER"
251 #define BJACK_DOUBLE_NAME "LEFT"
252 #define BJACK_SELECT BUTTON_SELECT
253 #define BJACK_QUIT BUTTON_POWER
254 #define BJACK_MAX BUTTON_VOL_UP
255 #define BJACK_MIN BUTTON_VOL_DOWN
256 #define BJACK_STAY BUTTON_RIGHT
257 #define BJACK_DOUBLEDOWN BUTTON_LEFT
258 #define BJACK_RESUME BUTTON_DOWN
259 #define BJACK_UP BUTTON_UP
260 #define BJACK_DOWN BUTTON_DOWN
261 #define BJACK_RIGHT BUTTON_RIGHT
262 #define BJACK_LEFT BUTTON_LEFT
264 #elif CONFIG_KEYPAD == SANSA_M200_PAD
265 #define BJACK_SELECT_NAME "SELECT"
266 #define BJACK_STAY_NAME "RIGHT"
267 #define BJACK_RESUME_NAME "DOWN"
268 #define BJACK_QUIT_NAME "POWER"
269 #define BJACK_DOUBLE_NAME "LEFT"
270 #define BJACK_SELECT (BUTTON_SELECT | BUTTON_REL)
271 #define BJACK_QUIT BUTTON_POWER
272 #define BJACK_MAX BUTTON_VOL_UP
273 #define BJACK_MIN BUTTON_VOL_DOWN
274 #define BJACK_STAY BUTTON_RIGHT
275 #define BJACK_DOUBLEDOWN BUTTON_LEFT
276 #define BJACK_RESUME BUTTON_DOWN
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 == TATUNG_TPJ1022_PAD
283 #define BJACK_SELECT_NAME "MAIN"
284 #define BJACK_STAY_NAME "MENU"
285 #define BJACK_RESUME_NAME ">>|"
286 #define BJACK_QUIT_NAME "POWER"
287 #define BJACK_DOUBLE_NAME "DOWN"
288 #define BJACK_SELECT BUTTON_MAIN
289 #define BJACK_QUIT BUTTON_POWER
290 #define BJACK_MAX (BUTTON_REC|BUTTON_UP)
291 #define BJACK_MIN (BUTTON_REC|BUTTON_DOWN)
292 #define BJACK_STAY BUTTON_MENU
293 #define BJACK_DOUBLEDOWN BUTTON_DOWN
294 #define BJACK_RESUME BUTTON_FF
295 #define BJACK_UP BUTTON_UP
296 #define BJACK_DOWN BUTTON_DOWN
297 #define BJACK_RIGHT BUTTON_RIGHT
298 #define BJACK_LEFT BUTTON_LEFT
300 #elif CONFIG_KEYPAD == GIGABEAT_S_PAD
301 #define BJACK_SELECT_NAME "PLAY"
302 #define BJACK_STAY_NAME "VOL-"
303 #define BJACK_RESUME_NAME "MENU"
304 #define BJACK_QUIT_NAME "BACK"
305 #define BJACK_DOUBLE_NAME "SELECT"
306 #define BJACK_SELECT BUTTON_PLAY
307 #define BJACK_QUIT BUTTON_BACK
308 #define BJACK_MAX BUTTON_VOL_UP
309 #define BJACK_MIN BUTTON_VOL_DOWN
310 #define BJACK_STAY BUTTON_VOL_DOWN
311 #define BJACK_DOUBLEDOWN BUTTON_SELECT
312 #define BJACK_RESUME BUTTON_MENU
313 #define BJACK_UP BUTTON_UP
314 #define BJACK_DOWN BUTTON_DOWN
315 #define BJACK_RIGHT BUTTON_RIGHT
316 #define BJACK_LEFT BUTTON_LEFT
318 #elif CONFIG_KEYPAD == MROBE100_PAD
319 #define BJACK_SELECT_NAME "SELECT"
320 #define BJACK_STAY_NAME "DISPLAY"
321 #define BJACK_RESUME_NAME "PLAY"
322 #define BJACK_QUIT_NAME "POWER"
323 #define BJACK_DOUBLE_NAME "DOWN"
324 #define BJACK_SELECT BUTTON_SELECT
325 #define BJACK_QUIT BUTTON_POWER
326 #define BJACK_MAX BUTTON_MENU
327 #define BJACK_MIN BUTTON_DISPLAY
328 #define BJACK_STAY BUTTON_DISPLAY
329 #define BJACK_DOUBLEDOWN BUTTON_DOWN
330 #define BJACK_RESUME BUTTON_PLAY
331 #define BJACK_UP BUTTON_UP
332 #define BJACK_DOWN BUTTON_DOWN
333 #define BJACK_RIGHT BUTTON_RIGHT
334 #define BJACK_LEFT BUTTON_LEFT
336 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
337 #define BJACK_SELECT_NAME "RC","PLAY"
338 #define BJACK_STAY_NAME "RC", ">>|"
339 #define BJACK_RESUME_NAME "RC_MODE"
340 #define BJACK_QUIT_NAME "RC_REC"
341 #define BJACK_DOUBLE_NAME "RC_REW"
342 #define BJACK_SELECT BUTTON_RC_PLAY
343 #define BJACK_QUIT BUTTON_RC_REC
344 #define BJACK_MAX (BUTTON_RC_PLAY|BUTTON_RC_VOL_UP)
345 #define BJACK_MIN (BUTTON_RC_PLAY|BUTTON_RC_VOL_DOWN)
346 #define BJACK_STAY BUTTON_RC_FF
347 #define BJACK_DOUBLEDOWN BUTTON_RC_REW
348 #define BJACK_RESUME BUTTON_RC_MODE
349 #define BJACK_UP BUTTON_RC_VOL_UP
350 #define BJACK_DOWN BUTTON_RC_VOL_DOWN
351 #define BJACK_RIGHT BUTTON_RC_FF
352 #define BJACK_LEFT BUTTON_RC_REW
354 #elif CONFIG_KEYPAD == COWON_D2_PAD
355 #define BJACK_QUIT_NAME "POWER"
356 #define BJACK_DOUBLE_NAME "-"
357 #define BJACK_QUIT BUTTON_POWER
358 #define BJACK_DOUBLEDOWN BUTTON_MINUS
360 #elif CONFIG_KEYPAD == CREATIVEZVM_PAD
361 #define BJACK_SELECT_NAME "SELECT"
362 #define BJACK_STAY_NAME "PLAY"
363 #define BJACK_RESUME_NAME "MENU"
364 #define BJACK_QUIT_NAME "POWER"
365 #define BJACK_DOUBLE_NAME "CUSTOM"
366 #define BJACK_SELECT BUTTON_SELECT
367 #define BJACK_QUIT BUTTON_POWER
368 #define BJACK_STAY BUTTON_PLAY
369 #define BJACK_MAX (BUTTON_CUSTOM|BUTTON_UP)
370 #define BJACK_MIN (BUTTON_CUSTOM|BUTTON_DOWN)
371 #define BJACK_DOUBLEDOWN BUTTON_CUSTOM
372 #define BJACK_RESUME BUTTON_MENU
373 #define BJACK_UP BUTTON_UP
374 #define BJACK_DOWN BUTTON_DOWN
375 #define BJACK_RIGHT BUTTON_RIGHT
376 #define BJACK_LEFT BUTTON_LEFT
378 #elif CONFIG_KEYPAD == PHILIPS_HDD1630_PAD
379 #define BJACK_SELECT_NAME "MENU"
380 #define BJACK_STAY_NAME "VOL-"
381 #define BJACK_RESUME_NAME "VIEW"
382 #define BJACK_QUIT_NAME "POWER"
383 #define BJACK_DOUBLE_NAME "SELECT"
384 #define BJACK_SELECT BUTTON_MENU
385 #define BJACK_QUIT BUTTON_POWER
386 #define BJACK_MAX BUTTON_VOL_UP
387 #define BJACK_MIN BUTTON_VOL_DOWN
388 #define BJACK_STAY BUTTON_VOL_DOWN
389 #define BJACK_DOUBLEDOWN BUTTON_SELECT
390 #define BJACK_RESUME BUTTON_VIEW
391 #define BJACK_UP BUTTON_UP
392 #define BJACK_DOWN BUTTON_DOWN
393 #define BJACK_RIGHT BUTTON_RIGHT
394 #define BJACK_LEFT BUTTON_LEFT
396 #elif CONFIG_KEYPAD == PHILIPS_SA9200_PAD
397 #define BJACK_SELECT_NAME "MENU"
398 #define BJACK_STAY_NAME "VOL-"
399 #define BJACK_RESUME_NAME "Right"
400 #define BJACK_QUIT_NAME "POWER"
401 #define BJACK_DOUBLE_NAME "PLAY"
402 #define BJACK_SELECT BUTTON_MENU
403 #define BJACK_QUIT BUTTON_POWER
404 #define BJACK_MAX BUTTON_VOL_UP
405 #define BJACK_MIN BUTTON_VOL_DOWN
406 #define BJACK_STAY BUTTON_VOL_DOWN
407 #define BJACK_DOUBLEDOWN BUTTON_PLAY
408 #define BJACK_RESUME BUTTON_RIGHT
409 #define BJACK_UP BUTTON_UP
410 #define BJACK_DOWN BUTTON_DOWN
411 #define BJACK_RIGHT BUTTON_NEXT
412 #define BJACK_LEFT BUTTON_PREV
414 #elif CONFIG_KEYPAD == ONDAVX747_PAD
415 #define BJACK_QUIT_NAME "POWER"
416 #define BJACK_DOUBLE_NAME "Vol-"
417 #define BJACK_QUIT BUTTON_POWER
418 #define BJACK_DOUBLEDOWN BUTTON_VOL_DOWN
420 #elif CONFIG_KEYPAD == ONDAVX777_PAD
421 #define BJACK_QUIT_NAME "POWER"
422 #define BJACK_QUIT BUTTON_POWER
424 #elif CONFIG_KEYPAD == MROBE500_PAD
425 #define BJACK_QUIT_NAME "POWER"
426 #define BJACK_QUIT BUTTON_POWER
428 #elif CONFIG_KEYPAD == SAMSUNG_YH_PAD
429 #define BJACK_SELECT_NAME ""
430 #define BJACK_STAY_NAME "RECORD"
431 #define BJACK_RESUME_NAME "PREVIOUS"
432 #define BJACK_QUIT_NAME "PLAY+LEFT"
433 #define BJACK_DOUBLE_NAME "FFWD"
434 #define BJACK_SELECT BUTTON_PLAY
435 #define BJACK_QUIT (BUTTON_PLAY|BUTTON_LEFT)
436 #define BJACK_MAX (BUTTON_PLAY|BUTTON_UP)
437 #define BJACK_MIN (BUTTON_PLAY|BUTTON_DOWN)
438 #define BJACK_STAY BUTTON_REC
439 #define BJACK_DOUBLEDOWN BUTTON_FFWD
440 #define BJACK_RESUME BUTTON_REW
441 #define BJACK_UP BUTTON_UP
442 #define BJACK_DOWN BUTTON_DOWN
443 #define BJACK_RIGHT BUTTON_RIGHT
444 #define BJACK_LEFT BUTTON_LEFT
446 #else
447 #error No keymap defined!
448 #endif
450 #ifdef HAVE_TOUCHSCREEN
451 #ifndef BJACK_DOUBLEDOWN
452 #define BJACK_DOUBLEDOWN BUTTON_MIDLEFT
453 #define BJACK_DOUBLE_NAME "BUTTON_MIDLEFT"
454 #endif
455 #ifndef BJACK_SELECT
456 #define BJACK_SELECT BUTTON_CENTER
457 #define BJACK_SELECT_NAME "BUTTON_CENTER"
458 #endif
459 #ifndef BJACK_MAX
460 #define BJACK_MAX BUTTON_TOPRIGHT
461 #endif
462 #ifndef BJACK_MIN
463 #define BJACK_MIN BUTTON_TOPLEFT
464 #endif
465 #ifndef BJACK_RESUME
466 #define BJACK_RESUME BUTTON_BOTTOMRIGHT
467 #define BJACK_RESUME_NAME "BUTTON_BOTTOMRIGHT"
468 #endif
469 #ifndef BJACK_STAY
470 #define BJACK_STAY BUTTON_BOTTOMLEFT
471 #define BJACK_STAY_NAME "BUTTON_BOTTOMLEFT"
472 #endif
473 #ifndef BJACK_UP
474 #define BJACK_UP BUTTON_TOPMIDDLE
475 #endif
476 #ifndef BJACK_DOWN
477 #define BJACK_DOWN BUTTON_BOTTOMMIDDLE
478 #endif
479 #ifndef BJACK_RIGHT
480 #define BJACK_RIGHT BUTTON_MIDRIGHT
481 #endif
482 #ifndef BJACK_LEFT
483 #define BJACK_LEFT BUTTON_MIDLEFT
484 #endif
486 #endif
488 #ifdef HAVE_LCD_COLOR
489 #define BG_COLOR LCD_RGBPACK(0,157,0)
490 #define FG_COLOR LCD_WHITE
491 #elif LCD_DEPTH > 1
492 #define BG_COLOR LCD_WHITE
493 #define FG_COLOR LCD_BLACK
494 #endif
496 #define CARD_WIDTH BMPWIDTH_card_back
497 #define CARD_HEIGHT BMPHEIGHT_card_back
499 /* This is the max amount of cards onscreen before condensing */
500 #define MAX_CARDS LCD_WIDTH/(CARD_WIDTH+4)
502 extern const fb_data card_deck[];
503 extern const fb_data card_back[];
505 #define NEXT_CARD bj->player_cards[done][bj->num_player_cards[done]]
507 /* dealer and player card positions */
508 unsigned int dealer_x, dealer_y, player_x, player_y;
510 typedef struct card {
511 unsigned int value; /* Card's value in Blackjack */
512 unsigned int num; /* Value on card face 0-12 (0=Ace, 1=2, 11=Q) */
513 unsigned int suit; /* 0:Spades, 1:Hearts, 2: Clubs; 3: Diamonds */
514 bool is_soft_ace;
515 } card;
517 typedef struct game_context {
518 struct card player_cards[2][22]; /* 22 Cards means the deal was all aces */
519 struct card dealer_cards[22]; /* That is the worst-case scenario */
520 unsigned int player_total;
521 unsigned int dealer_total;
522 signed int player_money;
523 unsigned int num_player_cards[2];
524 unsigned int num_dealer_cards;
525 unsigned int current_bet;
526 unsigned int split_status; /* 0 = split hasn't been asked, *
527 * 1 = split did not occur *
528 * 2 = split occurred *
529 * 3 = split occurred and 1st hand done */
530 bool is_blackjack;
531 bool end_hand;
532 bool asked_insurance;
533 } game_context;
535 static bool resume = false;
536 static bool resume_file = false;
537 static struct highscore highest[NUM_SCORES];
539 /*****************************************************************************
540 * blackjack_init() initializes blackjack data structures.
541 ******************************************************************************/
542 static void blackjack_init(struct game_context* bj) {
543 /* seed the rand generator */
544 rb->srand(*rb->current_tick);
546 /* reset card positions */
547 dealer_x = 4;
548 dealer_y = LCD_HEIGHT/4 - CARD_HEIGHT/2;
549 player_x = 4;
550 player_y = LCD_HEIGHT - LCD_HEIGHT/4 - CARD_HEIGHT/2;
552 /* check for resumed game */
553 if(resume) return;
555 /* reset scoring */
556 bj->player_total = 0;
557 bj->dealer_total = 0;
558 bj->num_player_cards[0] = 2;
559 bj->num_player_cards[1] = 0;
560 bj->num_dealer_cards = 2;
561 bj->end_hand = false;
562 bj->split_status = 0;
563 bj->is_blackjack = false;
564 bj->asked_insurance = false;
567 /*****************************************************************************
568 * blackjack_drawtable() draws the table and some text.
569 ******************************************************************************/
570 static void blackjack_drawtable(struct game_context* bj) {
571 unsigned int w, h, y_loc;
572 char str[10];
574 #if LCD_HEIGHT <= 64
575 rb->lcd_getstringsize("Bet", &w, &h);
576 rb->lcd_putsxy(LCD_WIDTH - w, 2*h + 1, "Bet");
577 rb->snprintf(str, 9, "$%d", bj->current_bet);
578 rb->lcd_getstringsize(str, &w, &h);
579 rb->lcd_putsxy(LCD_WIDTH - w, 3*h + 1, str);
580 y_loc = LCD_HEIGHT/2;
581 #else
582 rb->lcd_getstringsize("Bet", &w, &h);
583 rb->lcd_putsxy(LCD_WIDTH - w, 5*h / 2, "Bet");
584 rb->snprintf(str, 9, "$%d", bj->current_bet);
585 rb->lcd_getstringsize(str, &w, &h);
586 rb->lcd_putsxy(LCD_WIDTH - w, 7*h / 2, str);
587 rb->lcd_hline(0, LCD_WIDTH, LCD_HEIGHT/2);
588 y_loc = LCD_HEIGHT/2 + h;
589 #endif
591 rb->lcd_putsxy(0,0, "Dealer");
592 rb->lcd_getstringsize("Player", &w, &h);
593 rb->lcd_putsxy(0, y_loc, "Player");
594 rb->lcd_getstringsize("Total", &w, &h);
595 rb->lcd_putsxy(LCD_WIDTH - w, y_loc, "Total");
596 rb->lcd_getstringsize("Money", &w, &h);
597 rb->lcd_putsxy(LCD_WIDTH - w, 0, "Money");
598 rb->snprintf(str, 9, "$%d", bj->player_money - bj->current_bet);
599 rb->lcd_getstringsize(str, &w, &h);
600 rb->lcd_putsxy(LCD_WIDTH - w, h + 1, str);
601 rb->snprintf(str, 3, "%d", bj->player_total);
602 rb->lcd_getstringsize(str, &w, &h);
603 rb->lcd_putsxy(LCD_WIDTH - w, y_loc + h, str);
606 /*****************************************************************************
607 * find_value() is passed a card and returns its blackjack value.
608 ******************************************************************************/
609 static unsigned int find_value(unsigned int number) {
610 unsigned int thisValue;
611 if (number == 0)
612 thisValue = 11; /* Aces get a value of 11 at first */
613 else if (number < 10)
614 thisValue = number + 1;
615 else
616 thisValue = 10; /* Anything 10 or higher gets a value of 10 */
618 return thisValue;
621 /*****************************************************************************
622 * draw_card() draws a card to the screen.
623 ******************************************************************************/
624 static void draw_card(struct card temp_card, bool shown,
625 unsigned int x, unsigned int y) {
626 if(shown)
627 rb->lcd_bitmap_part(card_deck, CARD_WIDTH*temp_card.num,
628 CARD_HEIGHT*temp_card.suit,
629 STRIDE( SCREEN_MAIN, BMPWIDTH_card_deck,
630 BMPHEIGHT_card_deck),
631 x+1, y+1, CARD_WIDTH, CARD_HEIGHT);
632 else
633 rb->lcd_bitmap(card_back, x+1, y+1,CARD_WIDTH, CARD_HEIGHT);
634 #if LCD_DEPTH > 1
635 rb->lcd_set_foreground(LCD_BLACK);
636 #endif
638 /* Print outlines */
639 #if CARD_WIDTH >= 26
640 rb->lcd_hline(x+2, x+CARD_WIDTH-1, y);
641 rb->lcd_hline(x+2, x+CARD_WIDTH-1, y+CARD_HEIGHT+1);
642 rb->lcd_vline(x, y+2, y+CARD_HEIGHT-3);
643 rb->lcd_vline(x+CARD_WIDTH+1, y+2, y+CARD_HEIGHT-1);
644 rb->lcd_drawpixel(x+1, y+1);
645 rb->lcd_drawpixel(x+1, y+CARD_HEIGHT);
646 rb->lcd_drawpixel(x+CARD_WIDTH, y+1);
647 rb->lcd_drawpixel(x+CARD_WIDTH, y+CARD_HEIGHT);
648 #else
649 rb->lcd_hline(x+1, x+CARD_WIDTH, y);
650 rb->lcd_hline(x+1, x+CARD_WIDTH, y+CARD_HEIGHT+1);
651 rb->lcd_vline(x, y+1, y+CARD_HEIGHT);
652 rb->lcd_vline(x+CARD_WIDTH+1, y+1, y+CARD_HEIGHT);
653 #endif
655 #if LCD_DEPTH > 1
656 rb->lcd_set_foreground(FG_COLOR);
657 #endif
660 /*****************************************************************************
661 * new_card() initializes a new card and gives it values.
662 ******************************************************************************/
663 static struct card new_card(void) {
664 struct card new_card;
665 new_card.suit = rb->rand()%4; /* Random number 0-3 */
666 new_card.num = rb->rand()%13; /* Random number 0-12 */
667 new_card.value = find_value(new_card.num);
668 new_card.is_soft_ace = new_card.num == 0 ? true : false;
669 return new_card;
672 /*****************************************************************************
673 * deal_init_card() deals and draws to the screen the player's and dealer's
674 * initial cards.
675 ******************************************************************************/
676 static void deal_init_cards(struct game_context* bj) {
677 bj->dealer_cards[0] = new_card();
678 bj->dealer_total += bj->dealer_cards[0].value;
680 draw_card(bj->dealer_cards[0], false, dealer_x, dealer_y);
682 bj->dealer_cards[1] = new_card();
683 bj->dealer_total += bj->dealer_cards[1].value;
684 draw_card(bj->dealer_cards[1], true, dealer_x + CARD_WIDTH + 4, dealer_y);
686 bj->player_cards[0][0] = new_card();
687 bj->player_total += bj->player_cards[0][0].value;
688 draw_card(bj->player_cards[0][0], true, player_x, player_y);
689 player_x += CARD_WIDTH + 4;
691 bj->player_cards[0][1] = new_card();
692 bj->player_total += bj->player_cards[0][1].value;
693 draw_card(bj->player_cards[0][1], true, player_x, player_y);
694 player_x += CARD_WIDTH + 4;
697 /*****************************************************************************
698 * redraw_board() redraws all the cards and the board
699 ******************************************************************************/
700 static void redraw_board(struct game_context* bj) {
701 unsigned int i, n, upper_bound;
702 rb->lcd_clear_display();
704 blackjack_drawtable(bj);
705 player_x = 4;
706 dealer_x = 4;
707 upper_bound = bj->split_status > 1 ? 2 : 1;
709 for (i = 0; i < bj->num_dealer_cards; i++) {
710 if (!bj->end_hand) {
711 draw_card(bj->dealer_cards[0], false, dealer_x, dealer_y);
713 /* increment i so the dealer's first card isn't displayed */
714 i++;
715 dealer_x += CARD_WIDTH + 4;
717 draw_card(bj->dealer_cards[i], true, dealer_x, dealer_y);
719 if (bj->num_dealer_cards > MAX_CARDS-1)
720 dealer_x += 10;
721 else
722 dealer_x += CARD_WIDTH + 4;
725 for (n = 0; n < upper_bound; n++) {
726 for (i = 0; i < bj->num_player_cards[n]; i++) {
727 draw_card(bj->player_cards[n][i], true, player_x, player_y);
728 if (bj->split_status>1 || bj->num_player_cards[n]>MAX_CARDS)
729 player_x += 10;
730 else
731 player_x += CARD_WIDTH + 4;
733 if (bj->split_status > 1)
734 player_x = LCD_WIDTH/2 + 4;
738 /*****************************************************************************
739 * update_total updates the player's total
740 ******************************************************************************/
741 static void update_total(struct game_context* bj) {
742 char total[3];
743 unsigned int w, h;
744 rb->snprintf(total, 3, "%d", bj->player_total);
745 rb->lcd_getstringsize(total, &w, &h);
746 #if LCD_HEIGHT > 64
747 h *= 2;
748 #endif
749 rb->lcd_putsxy(LCD_WIDTH - w, LCD_HEIGHT/2 + h, total);
750 rb->lcd_update_rect(LCD_WIDTH - w, LCD_HEIGHT/2 + h, w, h);
754 /*****************************************************************************
755 * check_for_aces() is passed an array of cards and returns where an ace is
756 * located. Otherwise, returns -1.
757 ******************************************************************************/
758 static signed int check_for_aces(struct card temp_cards[], unsigned int size) {
759 unsigned int i;
760 for(i = 0; i < size; i++) {
761 if (temp_cards[i].is_soft_ace == true)
762 return i;
764 return -1;
767 /*****************************************************************************
768 * check_totals() compares player and dealer totals.
769 * 0: bust 1: loss, 2: push, 3: win, 4: blackjack, 5: something's not right...
770 ******************************************************************************/
771 static unsigned int check_totals(struct game_context* bj) {
772 unsigned int temp;
773 if (bj->player_total > 21)
774 temp = 0;
775 else if (bj->player_total == 21 && bj->is_blackjack) {
776 if (bj->dealer_total == 21 && bj->num_dealer_cards == 2)
777 temp = 2;
778 else
779 temp = 4;
781 else if (bj->player_total == bj->dealer_total)
782 temp = 2;
783 else if (bj->dealer_total > 21 && bj->player_total < 22)
784 temp = 3;
785 else if (bj->dealer_total > bj->player_total)
786 temp = 1;
787 else if (bj->player_total > bj->dealer_total)
788 temp = 3;
789 else
790 temp = 5;
792 return temp;
795 /*****************************************************************************
796 * finish_dealer() draws cards for the dealer until he has 17 or more.
797 ******************************************************************************/
798 static void finish_dealer(struct game_context* bj) {
799 signed int temp = 0;
801 if (bj->dealer_total > 16 && bj->dealer_total < 22)
802 return;
804 while (bj->dealer_total < 17) {
805 bj->dealer_cards[bj->num_dealer_cards] = new_card();
806 bj->dealer_total += bj->dealer_cards[bj->num_dealer_cards].value;
807 bj->num_dealer_cards++;
810 while (bj->dealer_total > 21) {
811 temp = check_for_aces(bj->dealer_cards, bj->num_dealer_cards);
812 if(temp != -1) {
813 bj->dealer_cards[temp].is_soft_ace = false;
814 bj->dealer_total -= 10;
816 else
817 return;
821 /*****************************************************************************
822 * finish_game() completes the game once player's turn is over.
823 ******************************************************************************/
824 static void finish_game(struct game_context* bj) {
825 unsigned int rValue, w, h;
826 char str[19];
828 do {
829 finish_dealer(bj);
830 } while (bj->dealer_total < 17);
832 redraw_board(bj);
833 rValue = check_totals(bj);
835 if (rValue == 0) {
836 rb->snprintf(str, sizeof(str), " Bust! ");
837 bj->player_money -= bj->current_bet;
839 else if (rValue == 1) {
840 rb->snprintf(str, sizeof(str), " Sorry, you lost. ");
841 bj->player_money -= bj->current_bet;
843 else if (rValue == 2) {
844 rb->snprintf(str, sizeof(str), " Push ");
846 else if (rValue == 3) {
847 rb->snprintf(str, sizeof(str), " You won! ");
848 bj->player_money+= bj->current_bet;
850 else {
851 rb->snprintf(str, sizeof(str), " Blackjack! ");
852 bj->player_money += bj->current_bet * 3 / 2;
854 rb->lcd_getstringsize(str, &w, &h);
856 #if LCD_HEIGHT <= 64
857 rb->lcd_set_drawmode(DRMODE_BG+DRMODE_INVERSEVID);
858 rb->lcd_fillrect(0, LCD_HEIGHT/2, LCD_WIDTH, LCD_HEIGHT/2);
859 rb->lcd_set_drawmode(DRMODE_SOLID);
860 rb->lcd_putsxy(LCD_WIDTH/2 - w/2, LCD_HEIGHT/2 + h, str);
861 rb->snprintf(str, 12, "You have %d", bj->player_total);
862 rb->lcd_getstringsize(str, &w, &h);
863 rb->lcd_putsxy(LCD_WIDTH/2 - w/2, LCD_HEIGHT/2, str);
864 #else
865 rb->lcd_putsxy(LCD_WIDTH/2 - w/2, LCD_HEIGHT/2 - h/2, str);
866 #endif
867 rb->lcd_update();
870 /*****************************************************************************
871 * blackjack_loadgame() loads the saved game and returns load success.
872 ******************************************************************************/
873 static bool blackjack_loadgame(struct game_context* bj) {
874 signed int fd;
875 bool loaded = false;
877 /* open game file */
878 fd = rb->open(SAVE_FILE, O_RDONLY);
879 if(fd < 0) return false;
881 /* read in saved game */
882 if(rb->read(fd, bj, sizeof(struct game_context))
883 == (long)sizeof(struct game_context))
885 loaded = true;
888 rb->close(fd);
890 return loaded;
893 /*****************************************************************************
894 * blackjack_savegame() saves the current game state.
895 ******************************************************************************/
896 static void blackjack_savegame(struct game_context* bj) {
897 int fd;
899 if(!resume)
900 return;
901 /* write out the game state to the save file */
902 fd = rb->open(SAVE_FILE, O_WRONLY|O_CREAT);
903 if(fd < 0)
904 return;
905 rb->write(fd, bj, sizeof(struct game_context));
906 rb->close(fd);
909 /*****************************************************************************
910 * blackjack_get_yes_no() gets a yes/no answer from the user
911 ******************************************************************************/
912 static unsigned int blackjack_get_yes_no(char message[20]) {
913 int button;
914 unsigned int w, h, b, choice = 0;
915 bool breakout = false;
916 char message_yes[24], message_no[24];
918 rb->strcpy(message_yes, message);
919 rb->strcpy(message_no, message);
920 rb->strcat(message_yes, " Yes");
921 rb->strcat(message_no, " No");
922 rb->lcd_getstringsize(message_yes, &w, &h);
923 const char *stg[] = {message_yes, message_no};
925 #if LCD_HEIGHT <= 64
926 b = 2*h+1;
927 #else
928 b = h-1;
929 #endif
931 #ifdef HAVE_LCD_COLOR
932 rb->lcd_fillrect(LCD_WIDTH/2 - w/2, LCD_HEIGHT/2 + b, w+1, h+3);
933 rb->lcd_set_foreground(LCD_BLACK);
934 rb->lcd_set_background(LCD_WHITE);
935 #else
936 rb->lcd_set_drawmode(DRMODE_BG+DRMODE_INVERSEVID);
937 rb->lcd_fillrect(LCD_WIDTH/2 - w/2, LCD_HEIGHT/2 + b, w+1, h+3);
938 rb->lcd_set_drawmode(DRMODE_SOLID);
939 #endif
940 rb->lcd_drawrect(LCD_WIDTH/2 - w/2 - 1, LCD_HEIGHT/2 + b - 1, w+3, h+4);
942 while(!breakout) {
943 rb->lcd_putsxy(LCD_WIDTH/2 - w/2, LCD_HEIGHT/2 + b +1, stg[choice]);
944 rb->lcd_update_rect(LCD_WIDTH/2 - w/2 - 1, LCD_HEIGHT/2 + b -1,
945 w+3, h+4);
946 button = rb->button_get(true);
948 switch(button) {
949 case BJACK_LEFT:
950 case (BJACK_LEFT|BUTTON_REPEAT):
951 case BJACK_RIGHT:
952 case (BJACK_RIGHT|BUTTON_REPEAT):
953 choice ^= 1;
954 break;
955 case BJACK_SELECT: breakout = true;
956 break;
957 case BJACK_QUIT: breakout = true;
958 choice = 1;
959 break;
963 #if LCD_DEPTH > 1
964 rb->lcd_set_foreground(FG_COLOR);
965 rb->lcd_set_background(BG_COLOR);
966 #endif
967 return choice;
970 /*****************************************************************************
971 * blackjack_get_amount() gets an amount from the player to be used
972 ******************************************************************************/
973 static signed int blackjack_get_amount(char message[20], signed int lower_limit,
974 signed int upper_limit,
975 signed int start) {
976 int button;
977 char str[9];
978 bool breakout = false, changed = false;
979 unsigned int w, h;
980 signed int amount;
982 rb->lcd_getstringsize("A", &w, &h); /* find the size of one character */
984 if (start > upper_limit)
985 amount = upper_limit;
986 else if (start < lower_limit)
987 amount = lower_limit;
988 else
989 amount = start;
991 #if LCD_DEPTH > 1
992 rb->lcd_set_background(LCD_WHITE);
993 rb->lcd_set_foreground(LCD_BLACK);
994 #endif
996 #if LCD_HEIGHT <= 64
997 rb->lcd_clear_display();
998 rb->lcd_puts(0, 1, message);
999 rb->snprintf(str, 9, "$%d", amount);
1000 rb->lcd_puts(0, 2, str);
1001 rb->lcd_puts(0, 3, "RIGHT: +1");
1002 rb->lcd_puts(0, 4, "LEFT: -1");
1003 rb->lcd_puts(0, 5, "UP: +10");
1004 rb->lcd_puts(0, 6, "DOWN: -10");
1005 rb->lcd_update();
1006 #else
1007 rb->lcd_set_drawmode(DRMODE_BG+DRMODE_INVERSEVID);
1008 rb->lcd_fillrect(LCD_WIDTH/2 - 9*w - 1, LCD_HEIGHT/2 - 4*h - 3,
1009 37*w / 2, 8*h -3);
1010 rb->lcd_set_drawmode(DRMODE_SOLID);
1011 rb->lcd_drawrect(LCD_WIDTH/2 - 9*w - 1, LCD_HEIGHT/2 - 4*h - 3,
1012 37*w / 2, 8*h -3);
1013 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 4*h - 1, message);
1014 rb->snprintf(str, 9, "$%d", amount);
1015 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 3*h, str);
1016 #if (CONFIG_KEYPAD == IPOD_4G_PAD) || \
1017 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
1018 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
1019 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - h-2, " >>|: +1");
1020 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 1, " |<<: -1");
1021 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 + h, "SCROLL+: +10");
1022 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 + 2*h + 1, "SCROLL-: -10");
1023 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
1024 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - h-2, "RIGHT: +1");
1025 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 1, "LEFT: -1");
1026 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 + h, "SCROLL+: +10");
1027 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 + 2*h + 1, "SCROLL-: -10");
1028 #else
1029 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - h-2, "RIGHT: +1");
1030 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 1, "LEFT: -1");
1031 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 + h, "UP: +10");
1032 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 + 2*h + 1, "DOWN: -10");
1033 #endif
1034 rb->lcd_update_rect(LCD_WIDTH/2 - 9*w - 1, LCD_HEIGHT/2 - 4*h - 3,
1035 37*w / 2, 8*h -3);
1036 #endif
1038 while(!breakout) {
1039 button = rb->button_get(true);
1041 switch(button) {
1042 case BJACK_UP:
1043 case (BJACK_UP|BUTTON_REPEAT):
1044 if (amount + 10 < upper_limit + 1) {
1045 amount += 10;
1046 changed = true;
1048 break;
1049 case BJACK_DOWN:
1050 case (BJACK_DOWN|BUTTON_REPEAT):
1051 if (amount - 10 > lower_limit - 1) {
1052 amount -= 10;
1053 changed = true;
1055 break;
1056 case BJACK_RIGHT:
1057 case (BJACK_RIGHT|BUTTON_REPEAT):
1058 if (amount + 1 < upper_limit + 1) {
1059 amount++;
1060 changed = true;
1062 break;
1063 case BJACK_LEFT:
1064 case (BJACK_LEFT|BUTTON_REPEAT):
1065 if (amount - 1 > lower_limit - 1) {
1066 amount--;
1067 changed = true;
1069 break;
1070 case BJACK_MAX :
1071 amount = upper_limit;
1072 changed = true;
1073 break;
1074 case BJACK_MIN :
1075 amount = lower_limit;
1076 changed = true;
1077 break;
1078 case BJACK_QUIT:
1079 breakout = true;
1080 amount = 0;
1081 break;
1082 case BJACK_SELECT:
1083 breakout = true;
1084 break;
1087 if(changed) {
1088 rb->snprintf(str, 9, "$%d", amount);
1089 #if LCD_HEIGHT <= 64
1090 rb->lcd_puts(0, 2, str);
1091 rb->lcd_update();
1092 #else
1093 rb->lcd_set_drawmode(DRMODE_BG+DRMODE_INVERSEVID);
1094 rb->lcd_fillrect(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 3*h, 5*w, h);
1095 rb->lcd_set_drawmode(DRMODE_SOLID);
1096 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 3*h, str);
1097 rb->lcd_update_rect(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 3*h, 5*w, h);
1098 #endif
1099 changed = false;
1103 #if LCD_DEPTH > 1
1104 rb->lcd_set_foreground(FG_COLOR);
1105 rb->lcd_set_background(BG_COLOR);
1106 #endif
1107 rb->lcd_clear_display();
1108 return amount;
1111 /*****************************************************************************
1112 * blackjack_get_bet() gets the player's bet.
1113 ******************************************************************************/
1114 static void blackjack_get_bet(struct game_context* bj) {
1115 bj->current_bet = blackjack_get_amount("Please enter a bet", 10,
1116 bj->player_money, bj->current_bet);
1119 /*****************************************************************************
1120 * double_down() returns one final card then finishes the game
1121 ******************************************************************************/
1122 static void double_down(struct game_context* bj) {
1123 bj->current_bet *= 2;
1124 bj->player_cards[0][bj->num_player_cards[0]] = new_card();
1125 bj->player_total += bj->player_cards[0][bj->num_player_cards[0]].value;
1126 bj->num_player_cards[0]++;
1129 /*****************************************************************************
1130 * split() checks if the player wants to split and acts accordingly.
1131 * When bj->split_status is 1, no split occurred. 2 means the player split and 3
1132 * means a split has already occurred and the first hand is done.
1133 ******************************************************************************/
1134 static void split(struct game_context* bj) {
1135 if (blackjack_get_yes_no("Split?") != 0)
1136 bj->split_status = 1;
1137 else {
1138 bj->split_status = 2;
1139 bj->current_bet *= 2;
1140 bj->num_player_cards[0] = 1;
1141 bj->num_player_cards[1] = 1;
1142 bj->player_cards[1][0] = bj->player_cards[0][1];
1143 bj->player_total = bj->player_cards[0][0].value;
1147 /*****************************************************************************
1148 * insurance() see if the player wants to buy insurance and how much.
1149 ******************************************************************************/
1150 static unsigned int insurance(struct game_context* bj) {
1151 unsigned int insurance, max_amount;
1153 insurance = blackjack_get_yes_no("Buy Insurance?");
1154 bj->asked_insurance = true;
1155 max_amount = bj->current_bet < (unsigned int)bj->player_money ?
1156 bj->current_bet/2 : (unsigned int)bj->player_money;
1157 if (insurance != 0) return 0;
1159 insurance = blackjack_get_amount("How much?", 0, max_amount, 0);
1160 redraw_board(bj);
1161 return insurance;
1164 /*****************************************************************************
1165 * play_again() checks to see if the player wants to keep playing.
1166 ******************************************************************************/
1167 static unsigned int play_again(void) {
1168 return blackjack_get_yes_no("Play Again?");
1171 /*****************************************************************************
1172 * blackjack_help() displays help text.
1173 ******************************************************************************/
1174 static bool blackjack_help(void) {
1175 #define WORDS (sizeof help_text / sizeof (char*))
1176 static char *help_text[] = {
1177 "Blackjack", "",
1178 "The", "goal", "is", "to", "get", "21.", "", "",
1179 "Controls", "",
1180 BJACK_SELECT_NAME, ":", "hit", "/", "select", "",
1181 BJACK_STAY_NAME, ":", "stay", "",
1182 BJACK_DOUBLE_NAME, ":", "double", "down", "",
1183 BJACK_QUIT_NAME, ":", "End", "game", "and", "go", "to", "menu", "",
1184 BJACK_RESUME_NAME, ":", "Go", "to", "menu", "without", "end", "game",
1186 static struct style_text formation[]={
1187 { 0, TEXT_CENTER|TEXT_UNDERLINE },
1188 { 12, C_RED }, /* Hit/Select */
1189 { 18, C_RED }, /* Stay */
1190 { 22, C_RED }, /* Double Down */
1191 { 27, C_RED }, /* Quit */
1192 { 36, C_RED }, /* Menu */
1193 { -1, 0 }
1195 int button;
1197 rb->lcd_setfont(FONT_UI);
1198 #ifdef HAVE_LCD_COLOR
1199 rb->lcd_set_background(LCD_BLACK);
1200 rb->lcd_set_foreground(LCD_WHITE);
1201 #endif
1203 if (display_text(WORDS, help_text, formation, NULL))
1204 return true;
1205 do {
1206 button = rb->button_get(true);
1207 if (rb->default_event_handler(button) == SYS_USB_CONNECTED) {
1208 return true;
1210 } while( ( button == BUTTON_NONE )
1211 || ( button & (BUTTON_REL|BUTTON_REPEAT) ) );
1212 rb->lcd_setfont(FONT_SYSFIXED);
1213 return false;
1216 /*****************************************************************************
1217 * blackjack_menu() is the initial menu at the start of the game.
1218 ******************************************************************************/
1219 static unsigned int blackjack_menu(struct game_context* bj) {
1220 int selection = resume?0:1;
1221 bool breakout = false;
1222 (void)bj;
1224 MENUITEM_STRINGLIST(menu, "BlackJack Menu", NULL,
1225 "Resume Game", "Start New Game",
1226 "High Scores", "Help",
1227 "Playback Control",
1228 "Quit without Saving", "Quit");
1230 while(!breakout) {
1231 switch(rb->do_menu(&menu, &selection, NULL, false)) {
1232 case 0:
1233 if(!resume) {
1234 rb->splash(HZ*2, "Nothing to resume");
1235 } else {
1236 breakout = true;
1237 if(resume_file)
1238 rb->remove(SAVE_FILE);
1240 break;
1241 case 1:
1242 breakout = true;
1243 resume = false;
1244 break;
1245 case 2:
1246 highscore_show(NUM_SCORES, highest, NUM_SCORES, false);
1247 break;
1248 case 3:
1249 if(blackjack_help())
1250 return BJ_USB;
1251 break;
1252 case 4:
1253 if (playback_control(NULL))
1254 return BJ_USB;
1255 break;
1256 case 5:
1257 return BJ_QUIT_WITHOUT_SAVING;
1258 case 6:
1259 return BJ_QUIT;
1261 case MENU_ATTACHED_USB:
1262 return BJ_USB;
1264 default:
1265 break;
1269 return 0;
1272 /*****************************************************************************
1273 * blackjack() is the main game subroutine, it returns the final game status.
1274 ******************************************************************************/
1275 static int blackjack(struct game_context* bj) {
1276 int button;
1277 unsigned int w, h, temp_var, done = 0, todo = 1;
1278 signed int temp;
1279 bool breakout = false;
1280 bool dbl_down = false;
1282 #if LCD_DEPTH > 1
1283 rb->lcd_set_background(BG_COLOR);
1284 rb->lcd_set_foreground(FG_COLOR);
1285 #endif
1287 /********************
1288 * menu *
1289 ********************/
1290 temp_var = blackjack_menu(bj);
1291 if (temp_var != 0)
1292 return temp_var;
1295 /********************
1296 * init *
1297 ********************/
1298 blackjack_init(bj);
1300 /********************
1301 * play *
1302 ********************/
1304 resume_file = false;
1305 /* check for resumed game */
1306 if(resume) {
1307 resume = false;
1308 redraw_board(bj);
1309 if (bj->split_status == 2) {
1310 todo=2;
1311 player_x = bj->num_player_cards[0] * 10 + 4;
1313 else if (bj->split_status == 3) {
1314 player_x = bj->num_player_cards[1] * 10 + LCD_WIDTH/2 + 4;
1315 todo=2;
1316 done=1;
1319 else {
1320 bj->player_money = 1000;
1321 bj->current_bet = 10;
1322 blackjack_get_bet(bj);
1323 if (bj->current_bet == 0)
1324 return -1;
1325 rb->lcd_clear_display();
1326 deal_init_cards(bj);
1327 blackjack_drawtable(bj);
1330 rb->lcd_update();
1332 breakout = false;
1334 while(true){
1335 if(bj->player_total == 21 && bj->num_player_cards[0] == 2) {
1336 bj->is_blackjack = true;
1337 bj->end_hand = true;
1338 finish_game(bj);
1340 else if(bj->dealer_cards[1].is_soft_ace && !breakout &&
1341 !bj->asked_insurance) {
1342 temp_var = insurance(bj);
1343 if (bj->dealer_total == 21) {
1344 rb->splash(HZ, "Dealer has blackjack");
1345 bj->player_money += temp_var;
1346 bj->end_hand = true;
1347 breakout = true;
1348 redraw_board(bj);
1349 finish_game(bj);
1351 else {
1352 rb->splash(HZ, "Dealer does not have blackjack");
1353 bj->player_money -= temp_var;
1354 breakout = true;
1355 redraw_board(bj);
1356 rb->lcd_update();
1359 if(!bj->end_hand && bj->split_status == 0 &&
1360 bj->player_cards[0][0].num == bj->player_cards[0][1].num) {
1361 split(bj);
1362 redraw_board(bj);
1363 rb->lcd_update_rect(0, LCD_HEIGHT/2, LCD_WIDTH, LCD_HEIGHT/2);
1364 if (bj->split_status == 2) {
1365 todo++;
1366 player_x = bj->num_player_cards[0] * 10 + 4;
1370 while(!bj->end_hand && done < todo) {
1371 button = rb->button_get(true);
1373 switch(button) {
1374 case BJACK_SELECT:
1375 NEXT_CARD = new_card();
1376 bj->player_total += NEXT_CARD.value;
1377 draw_card(NEXT_CARD, true, player_x, player_y);
1378 bj->num_player_cards[done]++;
1379 if (bj->num_player_cards[done] == MAX_CARDS + 1) {
1380 redraw_board(bj);
1381 rb->lcd_update_rect(0, LCD_HEIGHT/2, LCD_WIDTH,
1382 LCD_HEIGHT/2);
1384 else if (bj->num_player_cards[done]>MAX_CARDS || todo > 1) {
1385 rb->lcd_update_rect(player_x, player_y, CARD_WIDTH+2,
1386 CARD_HEIGHT+2);
1387 player_x += 10;
1389 else {
1390 rb->lcd_update_rect(player_x, player_y, CARD_WIDTH+2,
1391 CARD_HEIGHT+2);
1392 player_x += CARD_WIDTH + 4;
1394 update_total(bj);
1396 break;
1397 case BJACK_STAY:
1398 bj->end_hand = true;
1399 break;
1400 case BJACK_DOUBLEDOWN:
1401 if ((signed int)bj->current_bet * 2 <
1402 bj->player_money + 1 &&
1403 bj->num_player_cards[0]==2 && todo==1) {
1404 double_down(bj);
1405 dbl_down = true;
1406 if (bj->player_total < 22) {
1407 bj->end_hand = true;
1408 finish_game(bj);
1411 else if((signed int)bj->current_bet * 2 >
1412 bj->player_money){
1413 rb->splash(HZ, "Not enough money to double down.");
1414 redraw_board(bj);
1415 rb->lcd_update();
1417 break;
1418 case BJACK_RESUME: /* save and end game */
1419 resume = true;
1420 return BJ_END;
1422 case BJACK_QUIT:
1423 return BJ_END;
1426 while (bj->player_total > 21 && !bj->end_hand) {
1427 temp = check_for_aces(bj->player_cards[done],
1428 bj->num_player_cards[done]);
1429 if(temp != -1) {
1430 bj->player_cards[done][temp].is_soft_ace = false;
1431 bj->player_total -= 10;
1432 update_total(bj);
1433 if (dbl_down) {
1434 bj->end_hand = true;
1435 finish_game(bj);
1438 else
1439 bj->end_hand = true;
1442 if (bj->end_hand) {
1443 done++;
1444 if(todo > 1) {
1445 if (done == 2) {
1446 temp = bj->player_total;
1447 bj->player_total = temp_var;
1448 temp_var = temp;
1449 finish_game(bj);
1450 rb->lcd_getstringsize(" Split 1 ", &w, &h);
1451 rb->lcd_putsxy(LCD_WIDTH/2-w/2, LCD_HEIGHT/2-3*h/2,
1452 " Split 1 ");
1453 rb->lcd_update_rect(LCD_WIDTH/2-w/2, LCD_HEIGHT/2-3*h/2,
1454 w,h);
1455 bj->current_bet /= 2;
1456 rb->lcd_update_rect(LCD_WIDTH/2-w/2, LCD_HEIGHT/2-3*h/2,
1457 w,h);
1458 rb->sleep(HZ*2);
1459 bj->player_total = temp_var;
1460 finish_game(bj);
1461 rb->lcd_getstringsize(" Split 2 ", &w, &h);
1462 rb->lcd_putsxy(LCD_WIDTH/2-w/2, LCD_HEIGHT/2-3*h/2,
1463 " Split 2 ");
1464 rb->lcd_update_rect(LCD_WIDTH/2-w/2, LCD_HEIGHT/2-3*h/2,
1465 w,h);
1466 rb->sleep(HZ*2);
1468 else {
1469 bj->end_hand = false;
1470 bj->split_status = 3;
1471 temp_var = bj->player_total;
1472 bj->player_total = bj->player_cards[1][0].value;
1473 update_total(bj);
1474 redraw_board(bj);
1475 player_x += 10;
1476 rb->lcd_update();
1479 else
1480 finish_game(bj);
1484 if (bj->player_money < 10) {
1485 rb->sleep(HZ);
1486 return BJ_LOSE;
1489 if (bj->end_hand) { /* If hand is over */
1490 if (play_again() != 0) /* User wants to quit */
1491 return BJ_END;
1492 else { /* User keeps playing */
1493 breakout = false;
1494 temp = bj->current_bet;
1495 bj->current_bet = 0;
1496 redraw_board(bj);
1497 rb->lcd_update();
1498 bj->current_bet = temp;
1499 if(dbl_down) {
1500 bj->current_bet /= 2;
1501 dbl_down = false;
1503 done = 0;
1504 todo = 1;
1505 blackjack_init(bj);
1506 blackjack_get_bet(bj);
1507 if (bj->current_bet == 0)
1508 return BJ_END;
1509 deal_init_cards(bj);
1510 blackjack_drawtable(bj);
1511 rb->lcd_update();
1515 /* Never reached */
1516 return PLUGIN_OK;
1519 /*****************************************************************************
1520 * plugin entry point.
1521 ******************************************************************************/
1522 enum plugin_status plugin_start(const void* parameter)
1524 struct game_context bj;
1525 bool exit = false;
1527 (void)parameter;
1529 #if LCD_DEPTH > 1
1530 rb->lcd_set_backdrop(NULL);
1531 #endif
1533 /* load high scores */
1534 highscore_load(HIGH_SCORE,highest,NUM_SCORES);
1535 resume = blackjack_loadgame(&bj);
1536 resume_file = resume;
1538 rb->lcd_setfont(FONT_SYSFIXED);
1540 while(!exit) {
1541 switch(blackjack(&bj)){
1542 case BJ_LOSE:
1543 rb->splash(HZ, "Not enough money to continue");
1544 /* fall through to BJ_END */
1546 case BJ_END:
1547 if(!resume && bj.player_money > 10) {
1548 /* There is no level, so store -1 to blank column */
1549 int position = highscore_update(bj.player_money, -1, "",
1550 highest, NUM_SCORES);
1551 if (position != -1) {
1552 if (position == 0) {
1553 rb->splash(HZ*2, "New High Score");
1555 highscore_show(position, highest, NUM_SCORES, false);
1558 break;
1560 case BJ_USB:
1561 rb->lcd_setfont(FONT_UI);
1562 highscore_save(HIGH_SCORE,highest,NUM_SCORES);
1563 return PLUGIN_USB_CONNECTED;
1565 case BJ_QUIT:
1566 rb->splash(HZ/5, "Saving Game and Scores...");
1567 blackjack_savegame(&bj);
1568 highscore_save(HIGH_SCORE,highest,NUM_SCORES);
1569 /* fall through */
1571 case BJ_QUIT_WITHOUT_SAVING:
1572 exit = true;
1573 break;
1575 default:
1576 break;
1580 rb->lcd_setfont(FONT_UI);
1581 return PLUGIN_OK;