fix red.
[kugel-rb.git] / apps / plugins / blackjack.c
blob7b3dbef8055ab22c12497abc5db6891b337bf7c8
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 SCORE_FILE 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_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 #define BJACK_SELECT_NAME "SELECT"
171 #define BJACK_STAY_NAME "RIGHT"
172 #define BJACK_QUIT_NAME "POWER"
173 #define BJACK_DOUBLE_NAME "LEFT"
174 #define BJACK_SELECT BUTTON_SELECT
175 #define BJACK_QUIT BUTTON_POWER
176 #define BJACK_MAX BUTTON_UP
177 #define BJACK_MIN BUTTON_DOWN
178 #define BJACK_STAY BUTTON_RIGHT
179 #define BJACK_DOUBLEDOWN BUTTON_LEFT
180 #define BJACK_UP BUTTON_SCROLL_FWD
181 #define BJACK_DOWN BUTTON_SCROLL_BACK
182 #define BJACK_RIGHT BUTTON_RIGHT
183 #define BJACK_LEFT BUTTON_LEFT
185 #elif CONFIG_KEYPAD == SANSA_FUZE_PAD
186 #define BJACK_SELECT_NAME "SELECT"
187 #define BJACK_STAY_NAME "RIGHT"
188 #define BJACK_QUIT_NAME "HOME"
189 #define BJACK_DOUBLE_NAME "LEFT"
190 #define BJACK_SELECT BUTTON_SELECT
191 #define BJACK_QUIT (BUTTON_HOME|BUTTON_REPEAT)
192 #define BJACK_MAX BUTTON_UP
193 #define BJACK_MIN BUTTON_DOWN
194 #define BJACK_STAY BUTTON_RIGHT
195 #define BJACK_DOUBLEDOWN BUTTON_LEFT
196 #define BJACK_UP BUTTON_SCROLL_FWD
197 #define BJACK_DOWN BUTTON_SCROLL_BACK
198 #define BJACK_RIGHT BUTTON_RIGHT
199 #define BJACK_LEFT BUTTON_LEFT
201 #elif CONFIG_KEYPAD == SANSA_C200_PAD
202 #define BJACK_SELECT_NAME "SELECT"
203 #define BJACK_STAY_NAME "RIGHT"
204 #define BJACK_QUIT_NAME "POWER"
205 #define BJACK_DOUBLE_NAME "LEFT"
206 #define BJACK_SELECT BUTTON_SELECT
207 #define BJACK_QUIT BUTTON_POWER
208 #define BJACK_MAX BUTTON_VOL_UP
209 #define BJACK_MIN BUTTON_VOL_DOWN
210 #define BJACK_STAY BUTTON_RIGHT
211 #define BJACK_DOUBLEDOWN BUTTON_LEFT
212 #define BJACK_UP BUTTON_UP
213 #define BJACK_DOWN BUTTON_DOWN
214 #define BJACK_RIGHT BUTTON_RIGHT
215 #define BJACK_LEFT BUTTON_LEFT
217 #elif CONFIG_KEYPAD == SANSA_CLIP_PAD
218 #define BJACK_SELECT_NAME "SELECT"
219 #define BJACK_STAY_NAME "RIGHT"
220 #define BJACK_QUIT_NAME "POWER"
221 #define BJACK_DOUBLE_NAME "LEFT"
222 #define BJACK_SELECT BUTTON_SELECT
223 #define BJACK_QUIT BUTTON_POWER
224 #define BJACK_MAX BUTTON_VOL_UP
225 #define BJACK_MIN BUTTON_VOL_DOWN
226 #define BJACK_STAY BUTTON_RIGHT
227 #define BJACK_DOUBLEDOWN BUTTON_LEFT
228 #define BJACK_UP BUTTON_UP
229 #define BJACK_DOWN BUTTON_DOWN
230 #define BJACK_RIGHT BUTTON_RIGHT
231 #define BJACK_LEFT BUTTON_LEFT
233 #elif CONFIG_KEYPAD == SANSA_M200_PAD
234 #define BJACK_SELECT_NAME "SELECT"
235 #define BJACK_STAY_NAME "RIGHT"
236 #define BJACK_QUIT_NAME "POWER"
237 #define BJACK_DOUBLE_NAME "LEFT"
238 #define BJACK_SELECT (BUTTON_SELECT | BUTTON_REL)
239 #define BJACK_QUIT BUTTON_POWER
240 #define BJACK_MAX BUTTON_VOL_UP
241 #define BJACK_MIN BUTTON_VOL_DOWN
242 #define BJACK_STAY BUTTON_RIGHT
243 #define BJACK_DOUBLEDOWN BUTTON_LEFT
244 #define BJACK_UP BUTTON_UP
245 #define BJACK_DOWN BUTTON_DOWN
246 #define BJACK_RIGHT BUTTON_RIGHT
247 #define BJACK_LEFT BUTTON_LEFT
249 #elif CONFIG_KEYPAD == TATUNG_TPJ1022_PAD
250 #define BJACK_SELECT_NAME "MAIN"
251 #define BJACK_STAY_NAME "MENU"
252 #define BJACK_QUIT_NAME "POWER"
253 #define BJACK_DOUBLE_NAME "DOWN"
254 #define BJACK_SELECT BUTTON_MAIN
255 #define BJACK_QUIT BUTTON_POWER
256 #define BJACK_MAX (BUTTON_REC|BUTTON_UP)
257 #define BJACK_MIN (BUTTON_REC|BUTTON_DOWN)
258 #define BJACK_STAY BUTTON_MENU
259 #define BJACK_DOUBLEDOWN BUTTON_DOWN
260 #define BJACK_UP BUTTON_UP
261 #define BJACK_DOWN BUTTON_DOWN
262 #define BJACK_RIGHT BUTTON_RIGHT
263 #define BJACK_LEFT BUTTON_LEFT
265 #elif CONFIG_KEYPAD == GIGABEAT_S_PAD
266 #define BJACK_SELECT_NAME "PLAY"
267 #define BJACK_STAY_NAME "VOL-"
268 #define BJACK_QUIT_NAME "BACK"
269 #define BJACK_DOUBLE_NAME "SELECT"
270 #define BJACK_SELECT BUTTON_PLAY
271 #define BJACK_QUIT BUTTON_BACK
272 #define BJACK_MAX BUTTON_VOL_UP
273 #define BJACK_MIN BUTTON_VOL_DOWN
274 #define BJACK_STAY BUTTON_VOL_DOWN
275 #define BJACK_DOUBLEDOWN BUTTON_SELECT
276 #define BJACK_UP BUTTON_UP
277 #define BJACK_DOWN BUTTON_DOWN
278 #define BJACK_RIGHT BUTTON_RIGHT
279 #define BJACK_LEFT BUTTON_LEFT
281 #elif CONFIG_KEYPAD == MROBE100_PAD
282 #define BJACK_SELECT_NAME "SELECT"
283 #define BJACK_STAY_NAME "DISPLAY"
284 #define BJACK_QUIT_NAME "POWER"
285 #define BJACK_DOUBLE_NAME "DOWN"
286 #define BJACK_SELECT BUTTON_SELECT
287 #define BJACK_QUIT BUTTON_POWER
288 #define BJACK_MAX BUTTON_MENU
289 #define BJACK_MIN BUTTON_DISPLAY
290 #define BJACK_STAY BUTTON_DISPLAY
291 #define BJACK_DOUBLEDOWN BUTTON_DOWN
292 #define BJACK_UP BUTTON_UP
293 #define BJACK_DOWN BUTTON_DOWN
294 #define BJACK_RIGHT BUTTON_RIGHT
295 #define BJACK_LEFT BUTTON_LEFT
297 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
298 #define BJACK_SELECT_NAME "RC","PLAY"
299 #define BJACK_STAY_NAME "RC", ">>|"
300 #define BJACK_QUIT_NAME "RC_REC"
301 #define BJACK_DOUBLE_NAME "RC_REW"
302 #define BJACK_SELECT BUTTON_RC_PLAY
303 #define BJACK_QUIT BUTTON_RC_REC
304 #define BJACK_STAY BUTTON_RC_FF
305 #define BJACK_DOUBLEDOWN BUTTON_RC_REW
306 #define BJACK_UP BUTTON_RC_VOL_UP
307 #define BJACK_DOWN BUTTON_RC_VOL_DOWN
308 #define BJACK_RIGHT BUTTON_RC_FF
309 #define BJACK_LEFT BUTTON_RC_REW
311 #elif CONFIG_KEYPAD == COWON_D2_PAD
312 #define BJACK_QUIT_NAME "POWER"
313 #define BJACK_DOUBLE_NAME "-"
314 #define BJACK_QUIT BUTTON_POWER
315 #define BJACK_DOUBLEDOWN BUTTON_MINUS
317 #elif CONFIG_KEYPAD == CREATIVEZVM_PAD
318 #define BJACK_SELECT_NAME "SELECT"
319 #define BJACK_STAY_NAME "PLAY"
320 #define BJACK_QUIT_NAME "POWER"
321 #define BJACK_DOUBLE_NAME "CUSTOM"
322 #define BJACK_SELECT BUTTON_SELECT
323 #define BJACK_QUIT BUTTON_POWER
324 #define BJACK_STAY BUTTON_PLAY
325 #define BJACK_MAX (BUTTON_CUSTOM|BUTTON_UP)
326 #define BJACK_MIN (BUTTON_CUSTOM|BUTTON_DOWN)
327 #define BJACK_DOUBLEDOWN BUTTON_CUSTOM
328 #define BJACK_UP BUTTON_UP
329 #define BJACK_DOWN BUTTON_DOWN
330 #define BJACK_RIGHT BUTTON_RIGHT
331 #define BJACK_LEFT BUTTON_LEFT
333 #elif CONFIG_KEYPAD == PHILIPS_HDD1630_PAD
334 #define BJACK_SELECT_NAME "SELECT"
335 #define BJACK_STAY_NAME "VOL-"
336 #define BJACK_QUIT_NAME "POWER"
337 #define BJACK_DOUBLE_NAME "MENU"
338 #define BJACK_SELECT BUTTON_SELECT
339 #define BJACK_QUIT BUTTON_POWER
340 #define BJACK_MAX BUTTON_VOL_UP
341 #define BJACK_MIN BUTTON_VOL_DOWN
342 #define BJACK_STAY BUTTON_VOL_DOWN
343 #define BJACK_DOUBLEDOWN BUTTON_MENU
344 #define BJACK_UP BUTTON_UP
345 #define BJACK_DOWN BUTTON_DOWN
346 #define BJACK_RIGHT BUTTON_RIGHT
347 #define BJACK_LEFT BUTTON_LEFT
349 #elif CONFIG_KEYPAD == PHILIPS_SA9200_PAD
350 #define BJACK_SELECT_NAME "MENU"
351 #define BJACK_STAY_NAME "VOL-"
352 #define BJACK_QUIT_NAME "POWER"
353 #define BJACK_DOUBLE_NAME "PLAY"
354 #define BJACK_SELECT BUTTON_MENU
355 #define BJACK_QUIT BUTTON_POWER
356 #define BJACK_MAX BUTTON_VOL_UP
357 #define BJACK_MIN BUTTON_VOL_DOWN
358 #define BJACK_STAY BUTTON_VOL_DOWN
359 #define BJACK_DOUBLEDOWN BUTTON_PLAY
360 #define BJACK_UP BUTTON_UP
361 #define BJACK_DOWN BUTTON_DOWN
362 #define BJACK_RIGHT BUTTON_NEXT
363 #define BJACK_LEFT BUTTON_PREV
365 #elif CONFIG_KEYPAD == ONDAVX747_PAD
366 #define BJACK_QUIT_NAME "POWER"
367 #define BJACK_DOUBLE_NAME "Vol-"
368 #define BJACK_QUIT BUTTON_POWER
369 #define BJACK_DOUBLEDOWN BUTTON_VOL_DOWN
371 #elif CONFIG_KEYPAD == ONDAVX777_PAD
372 #define BJACK_QUIT_NAME "POWER"
373 #define BJACK_QUIT BUTTON_POWER
375 #elif CONFIG_KEYPAD == MROBE500_PAD
376 #define BJACK_QUIT_NAME "POWER"
377 #define BJACK_QUIT BUTTON_POWER
379 #elif CONFIG_KEYPAD == SAMSUNG_YH_PAD
380 #define BJACK_SELECT_NAME "PLAY"
381 #define BJACK_STAY_NAME "RECORD"
382 #define BJACK_QUIT_NAME "REW"
383 #define BJACK_DOUBLE_NAME "FFWD"
384 #define BJACK_SELECT BUTTON_PLAY
385 #define BJACK_QUIT BUTTON_REW
386 #define BJACK_STAY BUTTON_REC
387 #define BJACK_DOUBLEDOWN BUTTON_FFWD
388 #define BJACK_UP BUTTON_UP
389 #define BJACK_DOWN BUTTON_DOWN
390 #define BJACK_RIGHT BUTTON_RIGHT
391 #define BJACK_LEFT BUTTON_LEFT
393 #elif CONFIG_KEYPAD == PBELL_VIBE500_PAD
394 #define BJACK_SELECT_NAME "OK"
395 #define BJACK_STAY_NAME "CANCEL"
396 #define BJACK_QUIT_NAME "REC"
397 #define BJACK_DOUBLE_NAME "MENU"
398 #define BJACK_SELECT BUTTON_OK
399 #define BJACK_QUIT BUTTON_REC
400 #define BJACK_STAY BUTTON_CANCEL
401 #define BJACK_DOUBLEDOWN BUTTON_MENU
402 #define BJACK_UP BUTTON_UP
403 #define BJACK_DOWN BUTTON_DOWN
404 #define BJACK_RIGHT BUTTON_NEXT
405 #define BJACK_LEFT BUTTON_PREV
407 #elif CONFIG_KEYPAD == MPIO_HD200_PAD
408 #define BJACK_SELECT_NAME "SELECT"
409 #define BJACK_STAY_NAME "RIGHT"
410 #define BJACK_RESUME_NAME "PLAY"
411 #define BJACK_QUIT_NAME "REC+PLAY"
412 #define BJACK_DOUBLE_NAME "LEFT"
413 #define BJACK_SELECT BUTTON_SELECT
414 #define BJACK_QUIT (BUTTON_REC|BUTTON_PLAY)
415 #define BJACK_STAY BUTTON_VOL_UP
416 #define BJACK_DOUBLEDOWN BUTTON_VOL_DOWN
417 #define BJACK_UP BUTTON_PREV
418 #define BJACK_DOWN BUTTON_NEXT
419 #define BJACK_RIGHT BUTTON_VOL_UP
420 #define BJACK_LEFT BUTTON_VOL_DOWN
422 #else
423 #error No keymap defined!
424 #endif
426 #ifdef HAVE_TOUCHSCREEN
427 #ifndef BJACK_DOUBLEDOWN
428 #define BJACK_DOUBLEDOWN BUTTON_MIDLEFT
429 #define BJACK_DOUBLE_NAME "BUTTON_MIDLEFT"
430 #endif
431 #ifndef BJACK_SELECT
432 #define BJACK_SELECT BUTTON_CENTER
433 #define BJACK_SELECT_NAME "BUTTON_CENTER"
434 #endif
435 #ifndef BJACK_MAX
436 #define BJACK_MAX BUTTON_TOPRIGHT
437 #endif
438 #ifndef BJACK_MIN
439 #define BJACK_MIN BUTTON_TOPLEFT
440 #endif
441 #ifndef BJACK_STAY
442 #define BJACK_STAY BUTTON_BOTTOMLEFT
443 #define BJACK_STAY_NAME "BUTTON_BOTTOMLEFT"
444 #endif
445 #ifndef BJACK_UP
446 #define BJACK_UP BUTTON_TOPMIDDLE
447 #endif
448 #ifndef BJACK_DOWN
449 #define BJACK_DOWN BUTTON_BOTTOMMIDDLE
450 #endif
451 #ifndef BJACK_RIGHT
452 #define BJACK_RIGHT BUTTON_MIDRIGHT
453 #endif
454 #ifndef BJACK_LEFT
455 #define BJACK_LEFT BUTTON_MIDLEFT
456 #endif
458 #endif
460 #ifdef HAVE_LCD_COLOR
461 #define BG_COLOR LCD_RGBPACK(0,157,0)
462 #define FG_COLOR LCD_WHITE
463 #elif LCD_DEPTH > 1
464 #define BG_COLOR LCD_WHITE
465 #define FG_COLOR LCD_BLACK
466 #endif
468 #define CARD_WIDTH BMPWIDTH_card_back
469 #define CARD_HEIGHT BMPHEIGHT_card_back
471 /* This is the max amount of cards onscreen before condensing */
472 #define MAX_CARDS LCD_WIDTH/(CARD_WIDTH+4)
474 extern const fb_data card_deck[];
475 extern const fb_data card_back[];
477 #define NEXT_CARD bj->player_cards[done][bj->num_player_cards[done]]
479 /* dealer and player card positions */
480 unsigned int dealer_x, dealer_y, player_x, player_y;
482 typedef struct card {
483 unsigned int value; /* Card's value in Blackjack */
484 unsigned int num; /* Value on card face 0-12 (0=Ace, 1=2, 11=Q) */
485 unsigned int suit; /* 0:Spades, 1:Hearts, 2: Clubs; 3: Diamonds */
486 bool is_soft_ace;
487 } card;
489 typedef struct game_context {
490 struct card player_cards[2][22]; /* 22 Cards means the deal was all aces */
491 struct card dealer_cards[22]; /* That is the worst-case scenario */
492 unsigned int player_total;
493 unsigned int dealer_total;
494 signed int player_money;
495 unsigned int num_player_cards[2];
496 unsigned int num_dealer_cards;
497 unsigned int current_bet;
498 unsigned int split_status; /* 0 = split hasn't been asked, *
499 * 1 = split did not occur *
500 * 2 = split occurred *
501 * 3 = split occurred and 1st hand done */
502 bool is_blackjack;
503 bool end_hand;
504 bool asked_insurance;
505 } game_context;
507 static bool resume = false;
508 static bool resume_file = false;
509 static struct highscore highscores[NUM_SCORES];
511 /*****************************************************************************
512 * blackjack_init() initializes blackjack data structures.
513 ******************************************************************************/
514 static void blackjack_init(struct game_context* bj) {
515 /* seed the rand generator */
516 rb->srand(*rb->current_tick);
518 /* reset card positions */
519 dealer_x = 4;
520 dealer_y = LCD_HEIGHT/4 - CARD_HEIGHT/2;
521 player_x = 4;
522 player_y = LCD_HEIGHT - LCD_HEIGHT/4 - CARD_HEIGHT/2;
524 /* check for resumed game */
525 if(resume) return;
527 /* reset scoring */
528 bj->player_total = 0;
529 bj->dealer_total = 0;
530 bj->num_player_cards[0] = 2;
531 bj->num_player_cards[1] = 0;
532 bj->num_dealer_cards = 2;
533 bj->end_hand = false;
534 bj->split_status = 0;
535 bj->is_blackjack = false;
536 bj->asked_insurance = false;
539 /*****************************************************************************
540 * blackjack_drawtable() draws the table and some text.
541 ******************************************************************************/
542 static void blackjack_drawtable(struct game_context* bj) {
543 unsigned int w, h, y_loc;
544 char str[10];
546 #if LCD_HEIGHT <= 64
547 rb->lcd_getstringsize("Bet", &w, &h);
548 rb->lcd_putsxy(LCD_WIDTH - w, 2*h + 1, "Bet");
549 rb->snprintf(str, 9, "$%d", bj->current_bet);
550 rb->lcd_getstringsize(str, &w, &h);
551 rb->lcd_putsxy(LCD_WIDTH - w, 3*h + 1, str);
552 y_loc = LCD_HEIGHT/2;
553 #else
554 rb->lcd_getstringsize("Bet", &w, &h);
555 rb->lcd_putsxy(LCD_WIDTH - w, 5*h / 2, "Bet");
556 rb->snprintf(str, 9, "$%d", bj->current_bet);
557 rb->lcd_getstringsize(str, &w, &h);
558 rb->lcd_putsxy(LCD_WIDTH - w, 7*h / 2, str);
559 rb->lcd_hline(0, LCD_WIDTH, LCD_HEIGHT/2);
560 y_loc = LCD_HEIGHT/2 + h;
561 #endif
563 rb->lcd_putsxy(0,0, "Dealer");
564 rb->lcd_getstringsize("Player", &w, &h);
565 rb->lcd_putsxy(0, y_loc, "Player");
566 rb->lcd_getstringsize("Total", &w, &h);
567 rb->lcd_putsxy(LCD_WIDTH - w, y_loc, "Total");
568 rb->lcd_getstringsize("Money", &w, &h);
569 rb->lcd_putsxy(LCD_WIDTH - w, 0, "Money");
570 rb->snprintf(str, 9, "$%d", bj->player_money - bj->current_bet);
571 rb->lcd_getstringsize(str, &w, &h);
572 rb->lcd_putsxy(LCD_WIDTH - w, h + 1, str);
573 rb->snprintf(str, 3, "%d", bj->player_total);
574 rb->lcd_getstringsize(str, &w, &h);
575 rb->lcd_putsxy(LCD_WIDTH - w, y_loc + h, str);
578 /*****************************************************************************
579 * find_value() is passed a card and returns its blackjack value.
580 ******************************************************************************/
581 static unsigned int find_value(unsigned int number) {
582 unsigned int thisValue;
583 if (number == 0)
584 thisValue = 11; /* Aces get a value of 11 at first */
585 else if (number < 10)
586 thisValue = number + 1;
587 else
588 thisValue = 10; /* Anything 10 or higher gets a value of 10 */
590 return thisValue;
593 /*****************************************************************************
594 * draw_card() draws a card to the screen.
595 ******************************************************************************/
596 static void draw_card(struct card temp_card, bool shown,
597 unsigned int x, unsigned int y) {
598 if(shown)
599 rb->lcd_bitmap_part(card_deck, CARD_WIDTH*temp_card.num,
600 CARD_HEIGHT*temp_card.suit,
601 STRIDE( SCREEN_MAIN, BMPWIDTH_card_deck,
602 BMPHEIGHT_card_deck),
603 x+1, y+1, CARD_WIDTH, CARD_HEIGHT);
604 else
605 rb->lcd_bitmap(card_back, x+1, y+1,CARD_WIDTH, CARD_HEIGHT);
606 #if LCD_DEPTH > 1
607 rb->lcd_set_foreground(LCD_BLACK);
608 #endif
610 /* Print outlines */
611 #if CARD_WIDTH >= 26
612 rb->lcd_hline(x+2, x+CARD_WIDTH-1, y);
613 rb->lcd_hline(x+2, x+CARD_WIDTH-1, y+CARD_HEIGHT+1);
614 rb->lcd_vline(x, y+2, y+CARD_HEIGHT-3);
615 rb->lcd_vline(x+CARD_WIDTH+1, y+2, y+CARD_HEIGHT-1);
616 rb->lcd_drawpixel(x+1, y+1);
617 rb->lcd_drawpixel(x+1, y+CARD_HEIGHT);
618 rb->lcd_drawpixel(x+CARD_WIDTH, y+1);
619 rb->lcd_drawpixel(x+CARD_WIDTH, y+CARD_HEIGHT);
620 #else
621 rb->lcd_hline(x+1, x+CARD_WIDTH, y);
622 rb->lcd_hline(x+1, x+CARD_WIDTH, y+CARD_HEIGHT+1);
623 rb->lcd_vline(x, y+1, y+CARD_HEIGHT);
624 rb->lcd_vline(x+CARD_WIDTH+1, y+1, y+CARD_HEIGHT);
625 #endif
627 #if LCD_DEPTH > 1
628 rb->lcd_set_foreground(FG_COLOR);
629 #endif
632 /*****************************************************************************
633 * new_card() initializes a new card and gives it values.
634 ******************************************************************************/
635 static struct card new_card(void) {
636 struct card new_card;
637 new_card.suit = rb->rand()%4; /* Random number 0-3 */
638 new_card.num = rb->rand()%13; /* Random number 0-12 */
639 new_card.value = find_value(new_card.num);
640 new_card.is_soft_ace = (new_card.num == 0);
641 return new_card;
644 /*****************************************************************************
645 * deal_init_card() deals and draws to the screen the player's and dealer's
646 * initial cards.
647 ******************************************************************************/
648 static void deal_init_cards(struct game_context* bj) {
649 bj->dealer_cards[0] = new_card();
650 bj->dealer_total += bj->dealer_cards[0].value;
652 draw_card(bj->dealer_cards[0], false, dealer_x, dealer_y);
654 bj->dealer_cards[1] = new_card();
655 bj->dealer_total += bj->dealer_cards[1].value;
656 draw_card(bj->dealer_cards[1], true, dealer_x + CARD_WIDTH + 4, dealer_y);
658 bj->player_cards[0][0] = new_card();
659 bj->player_total += bj->player_cards[0][0].value;
660 draw_card(bj->player_cards[0][0], true, player_x, player_y);
661 player_x += CARD_WIDTH + 4;
663 bj->player_cards[0][1] = new_card();
664 bj->player_total += bj->player_cards[0][1].value;
665 draw_card(bj->player_cards[0][1], true, player_x, player_y);
666 player_x += CARD_WIDTH + 4;
669 /*****************************************************************************
670 * redraw_board() redraws all the cards and the board
671 ******************************************************************************/
672 static void redraw_board(struct game_context* bj) {
673 unsigned int i, n, upper_bound;
674 rb->lcd_clear_display();
676 blackjack_drawtable(bj);
677 player_x = 4;
678 dealer_x = 4;
679 upper_bound = bj->split_status > 1 ? 2 : 1;
681 for (i = 0; i < bj->num_dealer_cards; i++) {
682 if (!bj->end_hand) {
683 draw_card(bj->dealer_cards[0], false, dealer_x, dealer_y);
685 /* increment i so the dealer's first card isn't displayed */
686 i++;
687 dealer_x += CARD_WIDTH + 4;
689 draw_card(bj->dealer_cards[i], true, dealer_x, dealer_y);
691 if (bj->num_dealer_cards > MAX_CARDS-1)
692 dealer_x += 10;
693 else
694 dealer_x += CARD_WIDTH + 4;
697 for (n = 0; n < upper_bound; n++) {
698 for (i = 0; i < bj->num_player_cards[n]; i++) {
699 draw_card(bj->player_cards[n][i], true, player_x, player_y);
700 if (bj->split_status>1 || bj->num_player_cards[n]>MAX_CARDS)
701 player_x += 10;
702 else
703 player_x += CARD_WIDTH + 4;
705 if (bj->split_status > 1)
706 player_x = LCD_WIDTH/2 + 4;
710 /*****************************************************************************
711 * update_total updates the player's total
712 ******************************************************************************/
713 static void update_total(struct game_context* bj) {
714 char total[3];
715 unsigned int w, h;
716 rb->snprintf(total, 3, "%d", bj->player_total);
717 rb->lcd_getstringsize(total, &w, &h);
718 #if LCD_HEIGHT > 64
719 h *= 2;
720 #endif
721 rb->lcd_putsxy(LCD_WIDTH - w, LCD_HEIGHT/2 + h, total);
722 rb->lcd_update_rect(LCD_WIDTH - w, LCD_HEIGHT/2 + h, w, h);
726 /*****************************************************************************
727 * check_for_aces() is passed an array of cards and returns where an ace is
728 * located. Otherwise, returns -1.
729 ******************************************************************************/
730 static signed int check_for_aces(struct card temp_cards[], unsigned int size) {
731 unsigned int i;
732 for(i = 0; i < size; i++) {
733 if (temp_cards[i].is_soft_ace)
734 return i;
736 return -1;
739 /*****************************************************************************
740 * check_totals() compares player and dealer totals.
741 * 0: bust 1: loss, 2: push, 3: win, 4: blackjack, 5: something's not right...
742 ******************************************************************************/
743 static unsigned int check_totals(struct game_context* bj) {
744 unsigned int temp;
745 if (bj->player_total > 21)
746 temp = 0;
747 else if (bj->player_total == 21 && bj->is_blackjack) {
748 if (bj->dealer_total == 21 && bj->num_dealer_cards == 2)
749 temp = 2;
750 else
751 temp = 4;
753 else if (bj->player_total == bj->dealer_total)
754 temp = 2;
755 else if (bj->dealer_total > 21 && bj->player_total < 22)
756 temp = 3;
757 else if (bj->dealer_total > bj->player_total)
758 temp = 1;
759 else if (bj->player_total > bj->dealer_total)
760 temp = 3;
761 else
762 temp = 5;
764 return temp;
767 /*****************************************************************************
768 * finish_dealer() draws cards for the dealer until he has 17 or more.
769 ******************************************************************************/
770 static void finish_dealer(struct game_context* bj) {
771 signed int temp = 0;
773 if (bj->dealer_total > 16 && bj->dealer_total < 22)
774 return;
776 while (bj->dealer_total < 17) {
777 bj->dealer_cards[bj->num_dealer_cards] = new_card();
778 bj->dealer_total += bj->dealer_cards[bj->num_dealer_cards].value;
779 bj->num_dealer_cards++;
782 while (bj->dealer_total > 21) {
783 temp = check_for_aces(bj->dealer_cards, bj->num_dealer_cards);
784 if(temp != -1) {
785 bj->dealer_cards[temp].is_soft_ace = false;
786 bj->dealer_total -= 10;
788 else
789 return;
793 /*****************************************************************************
794 * finish_game() completes the game once player's turn is over.
795 ******************************************************************************/
796 static void finish_game(struct game_context* bj) {
797 unsigned int rValue, w, h;
798 char str[19];
800 do {
801 finish_dealer(bj);
802 } while (bj->dealer_total < 17);
804 redraw_board(bj);
805 rValue = check_totals(bj);
807 if (rValue == 0) {
808 rb->snprintf(str, sizeof(str), " Bust! ");
809 bj->player_money -= bj->current_bet;
811 else if (rValue == 1) {
812 rb->snprintf(str, sizeof(str), " Sorry, you lost. ");
813 bj->player_money -= bj->current_bet;
815 else if (rValue == 2) {
816 rb->snprintf(str, sizeof(str), " Push ");
818 else if (rValue == 3) {
819 rb->snprintf(str, sizeof(str), " You won! ");
820 bj->player_money+= bj->current_bet;
822 else {
823 rb->snprintf(str, sizeof(str), " Blackjack! ");
824 bj->player_money += bj->current_bet * 3 / 2;
826 rb->lcd_getstringsize(str, &w, &h);
828 #if LCD_HEIGHT <= 64
829 rb->lcd_set_drawmode(DRMODE_BG+DRMODE_INVERSEVID);
830 rb->lcd_fillrect(0, LCD_HEIGHT/2, LCD_WIDTH, LCD_HEIGHT/2);
831 rb->lcd_set_drawmode(DRMODE_SOLID);
832 rb->lcd_putsxy(LCD_WIDTH/2 - w/2, LCD_HEIGHT/2 + h, str);
833 rb->snprintf(str, 12, "You have %d", bj->player_total);
834 rb->lcd_getstringsize(str, &w, &h);
835 rb->lcd_putsxy(LCD_WIDTH/2 - w/2, LCD_HEIGHT/2, str);
836 #else
837 rb->lcd_putsxy(LCD_WIDTH/2 - w/2, LCD_HEIGHT/2 - h/2, str);
838 #endif
839 rb->lcd_update();
842 /*****************************************************************************
843 * blackjack_loadgame() loads the saved game and returns load success.
844 ******************************************************************************/
845 static bool blackjack_loadgame(struct game_context* bj) {
846 signed int fd;
847 bool loaded = false;
849 /* open game file */
850 fd = rb->open(SAVE_FILE, O_RDONLY);
851 if(fd < 0) return false;
853 /* read in saved game */
854 if(rb->read(fd, bj, sizeof(struct game_context))
855 == (long)sizeof(struct game_context))
857 loaded = true;
860 rb->close(fd);
862 return loaded;
865 /*****************************************************************************
866 * blackjack_savegame() saves the current game state.
867 ******************************************************************************/
868 static void blackjack_savegame(struct game_context* bj) {
869 int fd;
871 if(!resume)
872 return;
873 /* write out the game state to the save file */
874 fd = rb->open(SAVE_FILE, O_WRONLY|O_CREAT, 0666);
875 if(fd < 0)
876 return;
877 rb->write(fd, bj, sizeof(struct game_context));
878 rb->close(fd);
881 /*****************************************************************************
882 * blackjack_get_yes_no() gets a yes/no answer from the user
883 ******************************************************************************/
884 static unsigned int blackjack_get_yes_no(char message[20]) {
885 int button;
886 unsigned int w, h, b, choice = 0;
887 bool breakout = false;
888 char message_yes[24], message_no[24];
890 rb->strcpy(message_yes, message);
891 rb->strcpy(message_no, message);
892 rb->strcat(message_yes, " Yes");
893 rb->strcat(message_no, " No");
894 rb->lcd_getstringsize(message_yes, &w, &h);
895 const char *stg[] = {message_yes, message_no};
897 #if LCD_HEIGHT <= 64
898 b = 2*h+1;
899 #else
900 b = h-1;
901 #endif
903 #ifdef HAVE_LCD_COLOR
904 rb->lcd_fillrect(LCD_WIDTH/2 - w/2, LCD_HEIGHT/2 + b, w+1, h+3);
905 rb->lcd_set_foreground(LCD_BLACK);
906 rb->lcd_set_background(LCD_WHITE);
907 #else
908 rb->lcd_set_drawmode(DRMODE_BG+DRMODE_INVERSEVID);
909 rb->lcd_fillrect(LCD_WIDTH/2 - w/2, LCD_HEIGHT/2 + b, w+1, h+3);
910 rb->lcd_set_drawmode(DRMODE_SOLID);
911 #endif
912 rb->lcd_drawrect(LCD_WIDTH/2 - w/2 - 1, LCD_HEIGHT/2 + b - 1, w+3, h+4);
914 while(!breakout) {
915 rb->lcd_putsxy(LCD_WIDTH/2 - w/2, LCD_HEIGHT/2 + b +1, stg[choice]);
916 rb->lcd_update_rect(LCD_WIDTH/2 - w/2 - 1, LCD_HEIGHT/2 + b -1,
917 w+3, h+4);
918 button = rb->button_get(true);
920 switch(button) {
921 case BJACK_LEFT:
922 case (BJACK_LEFT|BUTTON_REPEAT):
923 case BJACK_RIGHT:
924 case (BJACK_RIGHT|BUTTON_REPEAT):
925 choice ^= 1;
926 break;
927 case BJACK_SELECT: breakout = true;
928 break;
929 case BJACK_QUIT: breakout = true;
930 choice = 1;
931 break;
935 #if LCD_DEPTH > 1
936 rb->lcd_set_foreground(FG_COLOR);
937 rb->lcd_set_background(BG_COLOR);
938 #endif
939 return choice;
942 /*****************************************************************************
943 * blackjack_get_amount() gets an amount from the player to be used
944 ******************************************************************************/
945 static signed int blackjack_get_amount(char message[20], signed int lower_limit,
946 signed int upper_limit,
947 signed int start) {
948 int button;
949 char str[9];
950 bool breakout = false, changed = false;
951 unsigned int w, h;
952 signed int amount;
954 rb->lcd_getstringsize("A", &w, &h); /* find the size of one character */
956 if (start > upper_limit)
957 amount = upper_limit;
958 else if (start < lower_limit)
959 amount = lower_limit;
960 else
961 amount = start;
963 #if LCD_DEPTH > 1
964 rb->lcd_set_background(LCD_WHITE);
965 rb->lcd_set_foreground(LCD_BLACK);
966 #endif
968 #if LCD_HEIGHT <= 64
969 rb->lcd_clear_display();
970 rb->lcd_puts(0, 1, message);
971 rb->snprintf(str, 9, "$%d", amount);
972 rb->lcd_puts(0, 2, str);
973 rb->lcd_puts(0, 3, "RIGHT: +1");
974 rb->lcd_puts(0, 4, "LEFT: -1");
975 rb->lcd_puts(0, 5, "UP: +10");
976 rb->lcd_puts(0, 6, "DOWN: -10");
977 rb->lcd_update();
978 #else
979 rb->lcd_set_drawmode(DRMODE_BG+DRMODE_INVERSEVID);
980 rb->lcd_fillrect(LCD_WIDTH/2 - 9*w - 1, LCD_HEIGHT/2 - 4*h - 3,
981 37*w / 2, 8*h -3);
982 rb->lcd_set_drawmode(DRMODE_SOLID);
983 rb->lcd_drawrect(LCD_WIDTH/2 - 9*w - 1, LCD_HEIGHT/2 - 4*h - 3,
984 37*w / 2, 8*h -3);
985 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 4*h - 1, message);
986 rb->snprintf(str, 9, "$%d", amount);
987 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 3*h, str);
988 #if (CONFIG_KEYPAD == IPOD_4G_PAD) || \
989 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
990 (CONFIG_KEYPAD == IPOD_1G2G_PAD) || \
991 (CONFIG_KEYPAD == SANSA_E200_PAD) || \
992 (CONFIG_KEYPAD == SANSA_FUZE_PAD)
993 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - h-2, " >>|: +1");
994 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 1, " |<<: -1");
995 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 + h, "SCROLL+: +10");
996 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 + 2*h + 1, "SCROLL-: -10");
997 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
998 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - h-2, "RIGHT: +1");
999 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 1, "LEFT: -1");
1000 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 + h, "SCROLL+: +10");
1001 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 + 2*h + 1, "SCROLL-: -10");
1002 #else
1003 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - h-2, "RIGHT: +1");
1004 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 1, "LEFT: -1");
1005 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 + h, "UP: +10");
1006 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 + 2*h + 1, "DOWN: -10");
1007 #endif
1008 rb->lcd_update_rect(LCD_WIDTH/2 - 9*w - 1, LCD_HEIGHT/2 - 4*h - 3,
1009 37*w / 2, 8*h -3);
1010 #endif
1012 while(!breakout) {
1013 button = rb->button_get(true);
1015 switch(button) {
1016 case BJACK_UP:
1017 case (BJACK_UP|BUTTON_REPEAT):
1018 if (amount + 10 < upper_limit + 1) {
1019 amount += 10;
1020 changed = true;
1022 break;
1023 case BJACK_DOWN:
1024 case (BJACK_DOWN|BUTTON_REPEAT):
1025 if (amount - 10 > lower_limit - 1) {
1026 amount -= 10;
1027 changed = true;
1029 break;
1030 case BJACK_RIGHT:
1031 case (BJACK_RIGHT|BUTTON_REPEAT):
1032 if (amount + 1 < upper_limit + 1) {
1033 amount++;
1034 changed = true;
1036 break;
1037 case BJACK_LEFT:
1038 case (BJACK_LEFT|BUTTON_REPEAT):
1039 if (amount - 1 > lower_limit - 1) {
1040 amount--;
1041 changed = true;
1043 break;
1044 #ifdef BJACK_MAX
1045 case BJACK_MAX :
1046 amount = upper_limit;
1047 changed = true;
1048 break;
1049 #endif
1050 #ifdef BJACK_MIN
1051 case BJACK_MIN :
1052 amount = lower_limit;
1053 changed = true;
1054 break;
1055 #endif
1056 case BJACK_QUIT:
1057 breakout = true;
1058 amount = 0;
1059 break;
1060 case BJACK_SELECT:
1061 breakout = true;
1062 break;
1065 if(changed) {
1066 rb->snprintf(str, 9, "$%d", amount);
1067 #if LCD_HEIGHT <= 64
1068 rb->lcd_puts(0, 2, str);
1069 rb->lcd_update();
1070 #else
1071 rb->lcd_set_drawmode(DRMODE_BG+DRMODE_INVERSEVID);
1072 rb->lcd_fillrect(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 3*h, 5*w, h);
1073 rb->lcd_set_drawmode(DRMODE_SOLID);
1074 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 3*h, str);
1075 rb->lcd_update_rect(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 3*h, 5*w, h);
1076 #endif
1077 changed = false;
1081 #if LCD_DEPTH > 1
1082 rb->lcd_set_foreground(FG_COLOR);
1083 rb->lcd_set_background(BG_COLOR);
1084 #endif
1085 rb->lcd_clear_display();
1086 return amount;
1089 /*****************************************************************************
1090 * blackjack_get_bet() gets the player's bet.
1091 ******************************************************************************/
1092 static void blackjack_get_bet(struct game_context* bj) {
1093 bj->current_bet = blackjack_get_amount("Please enter a bet", 10,
1094 bj->player_money, bj->current_bet);
1097 /*****************************************************************************
1098 * double_down() returns one final card then finishes the game
1099 ******************************************************************************/
1100 static void double_down(struct game_context* bj) {
1101 bj->current_bet *= 2;
1102 bj->player_cards[0][bj->num_player_cards[0]] = new_card();
1103 bj->player_total += bj->player_cards[0][bj->num_player_cards[0]].value;
1104 bj->num_player_cards[0]++;
1107 /*****************************************************************************
1108 * split() checks if the player wants to split and acts accordingly.
1109 * When bj->split_status is 1, no split occurred. 2 means the player split and 3
1110 * means a split has already occurred and the first hand is done.
1111 ******************************************************************************/
1112 static void split(struct game_context* bj) {
1113 if (blackjack_get_yes_no("Split?") != 0)
1114 bj->split_status = 1;
1115 else {
1116 bj->split_status = 2;
1117 bj->current_bet *= 2;
1118 bj->num_player_cards[0] = 1;
1119 bj->num_player_cards[1] = 1;
1120 bj->player_cards[1][0] = bj->player_cards[0][1];
1121 bj->player_total = bj->player_cards[0][0].value;
1125 /*****************************************************************************
1126 * insurance() see if the player wants to buy insurance and how much.
1127 ******************************************************************************/
1128 static unsigned int insurance(struct game_context* bj) {
1129 unsigned int insurance, max_amount;
1131 insurance = blackjack_get_yes_no("Buy Insurance?");
1132 bj->asked_insurance = true;
1133 max_amount = bj->current_bet < (unsigned int)bj->player_money ?
1134 bj->current_bet/2 : (unsigned int)bj->player_money;
1135 if (insurance != 0) return 0;
1137 insurance = blackjack_get_amount("How much?", 0, max_amount, 0);
1138 redraw_board(bj);
1139 return insurance;
1142 /*****************************************************************************
1143 * play_again() checks to see if the player wants to keep playing.
1144 ******************************************************************************/
1145 static unsigned int play_again(void) {
1146 return blackjack_get_yes_no("Play Again?");
1149 /*****************************************************************************
1150 * blackjack_help() displays help text.
1151 ******************************************************************************/
1152 static bool blackjack_help(void) {
1153 static char *help_text[] = {
1154 "Blackjack", "", "Aim", "",
1155 "Try", "to", "get", "as", "close", "to", "21", "without", "going",
1156 "over", "or", "simply", "beat", "out", "the", "dealer", "for", "the",
1157 "best", "hand.", "", "",
1158 "Controls", "",
1159 BJACK_SELECT_NAME, ":", "hit", "/", "select", "",
1160 BJACK_STAY_NAME, ":", "stay", "",
1161 BJACK_DOUBLE_NAME, ":", "double", "down", "",
1162 BJACK_QUIT_NAME, ":", "go", "to", "menu", "",
1164 static struct style_text formation[]={
1165 { 0, TEXT_CENTER|TEXT_UNDERLINE },
1166 { 2, C_RED },
1167 { 26, C_RED },
1168 LAST_STYLE_ITEM
1171 rb->lcd_setfont(FONT_UI);
1172 #ifdef HAVE_LCD_COLOR
1173 rb->lcd_set_background(LCD_BLACK);
1174 rb->lcd_set_foreground(LCD_WHITE);
1175 #endif
1176 if (display_text(ARRAYLEN(help_text), help_text, formation, NULL, true))
1177 return true;
1178 rb->lcd_setfont(FONT_SYSFIXED);
1180 return false;
1183 static int blackjack_menu_cb(int action, const struct menu_item_ex *this_item)
1185 int i = ((intptr_t)this_item);
1186 if(action == ACTION_REQUEST_MENUITEM
1187 && !resume && (i==0 || i==5))
1188 return ACTION_EXIT_MENUITEM;
1189 return action;
1192 /*****************************************************************************
1193 * blackjack_menu() is the initial menu at the start of the game.
1194 ******************************************************************************/
1195 static unsigned int blackjack_menu(void) {
1196 int selection = 0;
1197 bool breakout = false;
1199 MENUITEM_STRINGLIST(menu, "BlackJack Menu", blackjack_menu_cb,
1200 "Resume Game", "Start New Game",
1201 "High Scores", "Help",
1202 "Playback Control",
1203 "Quit without Saving", "Quit");
1205 while(!breakout) {
1206 switch(rb->do_menu(&menu, &selection, NULL, false)) {
1207 case 0:
1208 breakout = true;
1209 if(resume_file)
1210 rb->remove(SAVE_FILE);
1211 resume_file = false;
1212 break;
1213 case 1:
1214 breakout = true;
1215 resume = false;
1216 break;
1217 case 2:
1218 highscore_show(-1, highscores, NUM_SCORES, false);
1219 break;
1220 case 3:
1221 if(blackjack_help())
1222 return BJ_USB;
1223 break;
1224 case 4:
1225 if (playback_control(NULL))
1226 return BJ_USB;
1227 break;
1228 case 5:
1229 return BJ_QUIT_WITHOUT_SAVING;
1230 case 6:
1231 if (resume)
1232 return BJ_QUIT;
1233 else
1234 return BJ_QUIT_WITHOUT_SAVING;
1236 case MENU_ATTACHED_USB:
1237 return BJ_USB;
1239 default:
1240 break;
1244 return 0;
1247 /*****************************************************************************
1248 * blackjack() is the main game subroutine, it returns the final game status.
1249 ******************************************************************************/
1250 static int blackjack(struct game_context* bj) {
1251 int button;
1252 unsigned int w, h, temp_var, done = 0, todo = 1;
1253 signed int temp;
1254 bool breakout = false;
1255 bool dbl_down = false;
1257 /********************
1258 * menu *
1259 ********************/
1260 temp_var = blackjack_menu();
1261 if (temp_var != 0)
1262 return temp_var;
1264 #if LCD_DEPTH > 1
1265 rb->lcd_set_background(BG_COLOR);
1266 rb->lcd_set_foreground(FG_COLOR);
1267 #endif
1269 /********************
1270 * init *
1271 ********************/
1272 blackjack_init(bj);
1274 /********************
1275 * play *
1276 ********************/
1278 resume_file = false;
1279 /* check for resumed game */
1280 if(resume) {
1281 resume = false;
1282 redraw_board(bj);
1283 if (bj->split_status == 2) {
1284 todo=2;
1285 player_x = bj->num_player_cards[0] * 10 + 4;
1287 else if (bj->split_status == 3) {
1288 player_x = bj->num_player_cards[1] * 10 + LCD_WIDTH/2 + 4;
1289 todo=2;
1290 done=1;
1293 else {
1294 bj->player_money = 1000;
1295 bj->current_bet = 10;
1296 blackjack_get_bet(bj);
1297 if (bj->current_bet == 0)
1298 return -1;
1299 rb->lcd_clear_display();
1300 deal_init_cards(bj);
1301 blackjack_drawtable(bj);
1304 rb->lcd_update();
1306 breakout = false;
1308 while(true){
1309 if(bj->player_total == 21 && bj->num_player_cards[0] == 2) {
1310 bj->is_blackjack = true;
1311 bj->end_hand = true;
1312 finish_game(bj);
1314 else if(bj->dealer_cards[1].is_soft_ace && !breakout &&
1315 !bj->asked_insurance) {
1316 temp_var = insurance(bj);
1317 if (bj->dealer_total == 21) {
1318 rb->splash(HZ, "Dealer has blackjack");
1319 bj->player_money += temp_var;
1320 bj->end_hand = true;
1321 breakout = true;
1322 redraw_board(bj);
1323 finish_game(bj);
1325 else {
1326 rb->splash(HZ, "Dealer does not have blackjack");
1327 bj->player_money -= temp_var;
1328 breakout = true;
1329 redraw_board(bj);
1330 rb->lcd_update();
1333 if(!bj->end_hand && bj->split_status == 0 &&
1334 bj->player_cards[0][0].num == bj->player_cards[0][1].num) {
1335 split(bj);
1336 redraw_board(bj);
1337 rb->lcd_update_rect(0, LCD_HEIGHT/2, LCD_WIDTH, LCD_HEIGHT/2);
1338 if (bj->split_status == 2) {
1339 todo++;
1340 player_x = bj->num_player_cards[0] * 10 + 4;
1344 while(!bj->end_hand && done < todo) {
1345 button = rb->button_get(true);
1347 switch(button) {
1348 case BJACK_SELECT:
1349 NEXT_CARD = new_card();
1350 bj->player_total += NEXT_CARD.value;
1351 draw_card(NEXT_CARD, true, player_x, player_y);
1352 bj->num_player_cards[done]++;
1353 if (bj->num_player_cards[done] == MAX_CARDS + 1) {
1354 redraw_board(bj);
1355 rb->lcd_update_rect(0, LCD_HEIGHT/2, LCD_WIDTH,
1356 LCD_HEIGHT/2);
1358 else if (bj->num_player_cards[done]>MAX_CARDS || todo > 1) {
1359 rb->lcd_update_rect(player_x, player_y, CARD_WIDTH+2,
1360 CARD_HEIGHT+2);
1361 player_x += 10;
1363 else {
1364 rb->lcd_update_rect(player_x, player_y, CARD_WIDTH+2,
1365 CARD_HEIGHT+2);
1366 player_x += CARD_WIDTH + 4;
1368 update_total(bj);
1370 break;
1371 case BJACK_STAY:
1372 bj->end_hand = true;
1373 break;
1374 case BJACK_DOUBLEDOWN:
1375 if ((signed int)bj->current_bet * 2 <
1376 bj->player_money + 1 &&
1377 bj->num_player_cards[0]==2 && todo==1) {
1378 double_down(bj);
1379 dbl_down = true;
1380 if (bj->player_total < 22) {
1381 bj->end_hand = true;
1382 finish_game(bj);
1385 else if((signed int)bj->current_bet * 2 >
1386 bj->player_money){
1387 rb->splash(HZ, "Not enough money to double down.");
1388 redraw_board(bj);
1389 rb->lcd_update();
1391 break;
1393 case BJACK_QUIT:
1394 resume = true;
1395 return BJ_END;
1398 while (bj->player_total > 21 && !bj->end_hand) {
1399 temp = check_for_aces(bj->player_cards[done],
1400 bj->num_player_cards[done]);
1401 if(temp != -1) {
1402 bj->player_cards[done][temp].is_soft_ace = false;
1403 bj->player_total -= 10;
1404 update_total(bj);
1405 if (dbl_down) {
1406 bj->end_hand = true;
1407 finish_game(bj);
1410 else
1411 bj->end_hand = true;
1414 if (bj->end_hand) {
1415 done++;
1416 if(todo > 1) {
1417 if (done == 2) {
1418 temp = bj->player_total;
1419 bj->player_total = temp_var;
1420 temp_var = temp;
1421 finish_game(bj);
1422 rb->lcd_getstringsize(" Split 1 ", &w, &h);
1423 rb->lcd_putsxy(LCD_WIDTH/2-w/2, LCD_HEIGHT/2-3*h/2,
1424 " Split 1 ");
1425 rb->lcd_update_rect(LCD_WIDTH/2-w/2, LCD_HEIGHT/2-3*h/2,
1426 w,h);
1427 bj->current_bet /= 2;
1428 rb->lcd_update_rect(LCD_WIDTH/2-w/2, LCD_HEIGHT/2-3*h/2,
1429 w,h);
1430 rb->sleep(HZ*2);
1431 bj->player_total = temp_var;
1432 finish_game(bj);
1433 rb->lcd_getstringsize(" Split 2 ", &w, &h);
1434 rb->lcd_putsxy(LCD_WIDTH/2-w/2, LCD_HEIGHT/2-3*h/2,
1435 " Split 2 ");
1436 rb->lcd_update_rect(LCD_WIDTH/2-w/2, LCD_HEIGHT/2-3*h/2,
1437 w,h);
1438 rb->sleep(HZ*2);
1440 else {
1441 bj->end_hand = false;
1442 bj->split_status = 3;
1443 temp_var = bj->player_total;
1444 bj->player_total = bj->player_cards[1][0].value;
1445 update_total(bj);
1446 redraw_board(bj);
1447 player_x += 10;
1448 rb->lcd_update();
1451 else
1452 finish_game(bj);
1456 if (bj->player_money < 10) {
1457 rb->sleep(HZ);
1458 return BJ_LOSE;
1461 if (bj->end_hand) { /* If hand is over */
1462 if (play_again() != 0) /* User wants to quit */
1463 return BJ_END;
1464 else { /* User keeps playing */
1465 breakout = false;
1466 temp = bj->current_bet;
1467 bj->current_bet = 0;
1468 redraw_board(bj);
1469 rb->lcd_update();
1470 bj->current_bet = temp;
1471 if(dbl_down) {
1472 bj->current_bet /= 2;
1473 dbl_down = false;
1475 done = 0;
1476 todo = 1;
1477 blackjack_init(bj);
1478 blackjack_get_bet(bj);
1479 if (bj->current_bet == 0)
1480 return BJ_END;
1481 deal_init_cards(bj);
1482 blackjack_drawtable(bj);
1483 rb->lcd_update();
1487 /* Never reached */
1488 return PLUGIN_OK;
1491 /*****************************************************************************
1492 * plugin entry point.
1493 ******************************************************************************/
1494 enum plugin_status plugin_start(const void* parameter)
1496 struct game_context bj;
1497 bool exit = false;
1499 (void)parameter;
1501 #if LCD_DEPTH > 1
1502 rb->lcd_set_backdrop(NULL);
1503 #endif
1505 /* load high scores */
1506 highscore_load(SCORE_FILE, highscores, NUM_SCORES);
1507 resume = blackjack_loadgame(&bj);
1508 resume_file = resume;
1510 rb->lcd_setfont(FONT_SYSFIXED);
1512 while(!exit) {
1513 switch(blackjack(&bj)){
1514 case BJ_LOSE:
1515 rb->splash(HZ, "Not enough money to continue");
1516 /* fall through to BJ_END */
1518 case BJ_END:
1519 if(!resume && bj.player_money > 10) {
1520 /* There is no level, so store -1 to blank column */
1521 int position = highscore_update(bj.player_money, -1, "",
1522 highscores, NUM_SCORES);
1523 if (position != -1)
1525 if (position==0)
1526 rb->splash(HZ*2, "New High Score");
1527 highscore_show(position, highscores, NUM_SCORES, false);
1530 break;
1532 case BJ_USB:
1533 highscore_save(SCORE_FILE, highscores, NUM_SCORES);
1534 return PLUGIN_USB_CONNECTED;
1536 case BJ_QUIT:
1537 rb->splash(HZ*1, "Saving game...");
1538 blackjack_savegame(&bj);
1539 /* fall through */
1541 case BJ_QUIT_WITHOUT_SAVING:
1542 exit = true;
1543 break;
1545 default:
1546 break;
1549 highscore_save(SCORE_FILE, highscores, NUM_SCORES);
1550 return PLUGIN_OK;