1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
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 ****************************************************************************/
23 #include "pluginbitmaps/card_deck.h"
24 #include "pluginbitmaps/card_back.h"
29 #define SCORE_FILE PLUGIN_GAMES_DIR "/blackjack.score"
30 #define SAVE_FILE PLUGIN_GAMES_DIR "/blackjack.save"
32 #define NUM_SCORES LCD_HEIGHT/8-2
34 /* final game return status */
40 #if CONFIG_KEYPAD == RECORDER_PAD
41 #define BJACK_START BUTTON_ON
42 #define BJACK_QUIT BUTTON_OFF
43 #define BJACK_MAX (BUTTON_ON|BUTTON_UP)
44 #define BJACK_MIN (BUTTON_ON|BUTTON_DOWN)
45 #define BJACK_HIT BUTTON_F1
46 #define BJACK_STAY BUTTON_F2
47 #define BJACK_DOUBLEDOWN BUTTON_F3
48 #define BJACK_SCORES BUTTON_RIGHT
49 #define BJACK_RESUME BUTTON_PLAY
50 #define BJACK_UP BUTTON_UP
51 #define BJACK_DOWN BUTTON_DOWN
52 #define BJACK_RIGHT BUTTON_RIGHT
53 #define BJACK_LEFT BUTTON_LEFT
55 #elif CONFIG_KEYPAD == ONDIO_PAD
56 #define BJACK_START BUTTON_MENU
57 #define BJACK_QUIT BUTTON_OFF
58 #define BJACK_MAX (BUTTON_MENU|BUTTON_UP)
59 #define BJACK_MIN (BUTTON_MENU|BUTTON_DOWN)
60 #define BJACK_HIT BUTTON_LEFT
61 #define BJACK_STAY BUTTON_RIGHT
62 #define BJACK_DOUBLEDOWN BUTTON_UP
63 #define BJACK_SCORES BUTTON_UP
64 #define BJACK_RESUME BUTTON_DOWN
65 #define BJACK_UP BUTTON_UP
66 #define BJACK_DOWN BUTTON_DOWN
67 #define BJACK_RIGHT BUTTON_RIGHT
68 #define BJACK_LEFT BUTTON_LEFT
70 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
71 #define BJACK_START BUTTON_PLAY
72 #define BJACK_QUIT BUTTON_POWER
73 #define BJACK_MAX (BUTTON_PLAY|BUTTON_SCROLL_UP)
74 #define BJACK_MIN (BUTTON_PLAY|BUTTON_SCROLL_DOWN)
75 #define BJACK_HIT BUTTON_PLAY
76 #define BJACK_STAY BUTTON_FF
77 #define BJACK_DOUBLEDOWN BUTTON_REW
78 #define BJACK_SCORES BUTTON_LEFT
79 #define BJACK_RESUME BUTTON_RIGHT
80 #define BJACK_UP BUTTON_SCROLL_UP
81 #define BJACK_DOWN BUTTON_SCROLL_DOWN
82 #define BJACK_RIGHT BUTTON_RIGHT
83 #define BJACK_LEFT BUTTON_LEFT
85 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
86 (CONFIG_KEYPAD == IRIVER_H300_PAD)
87 #define BJACK_START BUTTON_ON
88 #define BJACK_QUIT BUTTON_OFF
89 #define BJACK_MAX (BUTTON_ON|BUTTON_UP)
90 #define BJACK_MIN (BUTTON_ON|BUTTON_DOWN)
91 #define BJACK_HIT BUTTON_ON
92 #define BJACK_STAY BUTTON_REC
93 #define BJACK_DOUBLEDOWN BUTTON_SELECT
94 #define BJACK_SCORES BUTTON_SELECT
95 #define BJACK_RESUME BUTTON_MODE
96 #define BJACK_UP BUTTON_UP
97 #define BJACK_DOWN BUTTON_DOWN
98 #define BJACK_RIGHT BUTTON_RIGHT
99 #define BJACK_LEFT BUTTON_LEFT
101 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \
102 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
103 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
104 #define BJACK_START BUTTON_SELECT
105 #define BJACK_QUIT BUTTON_MENU
106 #define BJACK_MAX (BUTTON_SELECT|BUTTON_SCROLL_FWD)
107 #define BJACK_MIN (BUTTON_SELECT|BUTTON_SCROLL_BACK)
108 #define BJACK_HIT BUTTON_SELECT
109 #define BJACK_STAY BUTTON_RIGHT
110 #define BJACK_DOUBLEDOWN BUTTON_LEFT
111 #define BJACK_SCORES BUTTON_RIGHT
112 #define BJACK_RESUME BUTTON_PLAY
113 #define BJACK_UP BUTTON_SCROLL_FWD
114 #define BJACK_DOWN BUTTON_SCROLL_BACK
115 #define BJACK_RIGHT BUTTON_RIGHT
116 #define BJACK_LEFT BUTTON_LEFT
118 #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD
119 #define BJACK_START BUTTON_PLAY
120 #define BJACK_QUIT BUTTON_POWER
121 #define BJACK_MAX (BUTTON_PLAY|BUTTON_UP)
122 #define BJACK_MIN (BUTTON_PLAY|BUTTON_DOWN)
123 #define BJACK_HIT BUTTON_SELECT
124 #define BJACK_STAY BUTTON_REC
125 #define BJACK_DOUBLEDOWN BUTTON_PLAY
126 #define BJACK_SCORES BUTTON_RIGHT
127 #define BJACK_RESUME BUTTON_DOWN
128 #define BJACK_UP BUTTON_UP
129 #define BJACK_DOWN BUTTON_DOWN
130 #define BJACK_RIGHT BUTTON_RIGHT
131 #define BJACK_LEFT BUTTON_LEFT
133 #elif CONFIG_KEYPAD == IRIVER_IFP7XX_PAD
134 #define BJACK_START BUTTON_MODE
135 #define BJACK_QUIT BUTTON_PLAY
136 #define BJACK_MAX (BUTTON_EQ|BUTTON_UP)
137 #define BJACK_MIN (BUTTON_EQ|BUTTON_DOWN)
138 #define BJACK_HIT BUTTON_EQ
139 #define BJACK_STAY BUTTON_MODE
140 #define BJACK_DOUBLEDOWN BUTTON_SELECT
141 #define BJACK_SCORES BUTTON_SELECT
142 #define BJACK_RESUME (BUTTON_EQ|BUTTON_MODE)
143 #define BJACK_UP BUTTON_UP
144 #define BJACK_DOWN BUTTON_DOWN
145 #define BJACK_RIGHT BUTTON_RIGHT
146 #define BJACK_LEFT BUTTON_LEFT
148 #elif CONFIG_KEYPAD == GIGABEAT_PAD
149 #define BJACK_START BUTTON_A
150 #define BJACK_QUIT BUTTON_POWER
151 #define BJACK_MAX BUTTON_VOL_UP
152 #define BJACK_MIN BUTTON_VOL_DOWN
153 #define BJACK_HIT BUTTON_VOL_UP
154 #define BJACK_STAY BUTTON_VOL_DOWN
155 #define BJACK_DOUBLEDOWN BUTTON_SELECT
156 #define BJACK_SCORES BUTTON_RIGHT
157 #define BJACK_RESUME BUTTON_MENU
158 #define BJACK_UP BUTTON_UP
159 #define BJACK_DOWN BUTTON_DOWN
160 #define BJACK_RIGHT BUTTON_RIGHT
161 #define BJACK_LEFT BUTTON_LEFT
163 #elif CONFIG_KEYPAD == SANSA_E200_PAD
164 #define BJACK_START BUTTON_SELECT
165 #define BJACK_QUIT BUTTON_POWER
166 #define BJACK_MAX (BUTTON_REC|BUTTON_UP)
167 #define BJACK_MIN (BUTTON_REC|BUTTON_DOWN)
168 #define BJACK_HIT BUTTON_SELECT
169 #define BJACK_STAY BUTTON_RIGHT
170 #define BJACK_DOUBLEDOWN BUTTON_LEFT
171 #define BJACK_SCORES BUTTON_UP
172 #define BJACK_RESUME BUTTON_DOWN
173 #define BJACK_UP BUTTON_SCROLL_FWD
174 #define BJACK_DOWN BUTTON_SCROLL_BACK
175 #define BJACK_RIGHT BUTTON_RIGHT
176 #define BJACK_LEFT BUTTON_LEFT
178 #elif CONFIG_KEYPAD == SANSA_FUZE_PAD
179 #define BJACK_START BUTTON_SELECT
180 #define BJACK_QUIT BUTTON_POWER
181 #define BJACK_MAX (BUTTON_SELECT|BUTTON_UP)
182 #define BJACK_MIN (BUTTON_SELECT|BUTTON_DOWN)
183 #define BJACK_HIT (BUTTON_SELECT|BUTTON_REL)
184 #define BJACK_STAY BUTTON_RIGHT
185 #define BJACK_DOUBLEDOWN BUTTON_LEFT
186 #define BJACK_SCORES BUTTON_DOWN
187 #define BJACK_RESUME BUTTON_UP
188 #define BJACK_UP BUTTON_SCROLL_FWD
189 #define BJACK_DOWN BUTTON_SCROLL_BACK
190 #define BJACK_RIGHT BUTTON_RIGHT
191 #define BJACK_LEFT BUTTON_LEFT
194 #elif CONFIG_KEYPAD == SANSA_C200_PAD
195 #define BJACK_START BUTTON_SELECT
196 #define BJACK_QUIT BUTTON_POWER
197 #define BJACK_MAX BUTTON_VOL_UP
198 #define BJACK_MIN BUTTON_VOL_DOWN
199 #define BJACK_HIT BUTTON_SELECT
200 #define BJACK_STAY BUTTON_RIGHT
201 #define BJACK_DOUBLEDOWN BUTTON_LEFT
202 #define BJACK_SCORES BUTTON_REC
203 #define BJACK_RESUME BUTTON_DOWN
204 #define BJACK_UP BUTTON_UP
205 #define BJACK_DOWN BUTTON_DOWN
206 #define BJACK_RIGHT BUTTON_RIGHT
207 #define BJACK_LEFT BUTTON_LEFT
209 #elif CONFIG_KEYPAD == SANSA_CLIP_PAD
210 #define BJACK_START BUTTON_SELECT
211 #define BJACK_QUIT BUTTON_POWER
212 #define BJACK_MAX BUTTON_VOL_UP
213 #define BJACK_MIN BUTTON_VOL_DOWN
214 #define BJACK_HIT BUTTON_SELECT
215 #define BJACK_STAY BUTTON_RIGHT
216 #define BJACK_DOUBLEDOWN BUTTON_LEFT
217 #define BJACK_SCORES BUTTON_HOME
218 #define BJACK_RESUME BUTTON_DOWN
219 #define BJACK_UP BUTTON_UP
220 #define BJACK_DOWN BUTTON_DOWN
221 #define BJACK_RIGHT BUTTON_RIGHT
222 #define BJACK_LEFT BUTTON_LEFT
224 #elif CONFIG_KEYPAD == SANSA_M200_PAD
225 #define BJACK_START (BUTTON_SELECT | BUTTON_REL)
226 #define BJACK_QUIT BUTTON_POWER
227 #define BJACK_MAX BUTTON_VOL_UP
228 #define BJACK_MIN BUTTON_VOL_DOWN
229 #define BJACK_HIT (BUTTON_SELECT | BUTTON_REL)
230 #define BJACK_STAY BUTTON_RIGHT
231 #define BJACK_DOUBLEDOWN BUTTON_LEFT
232 #define BJACK_SCORES (BUTTON_SELECT | BUTTON_UP)
233 #define BJACK_RESUME BUTTON_DOWN
234 #define BJACK_UP BUTTON_UP
235 #define BJACK_DOWN BUTTON_DOWN
236 #define BJACK_RIGHT BUTTON_RIGHT
237 #define BJACK_LEFT BUTTON_LEFT
239 #elif CONFIG_KEYPAD == ELIO_TPJ1022_PAD
240 #define BJACK_START BUTTON_MAIN
241 #define BJACK_QUIT BUTTON_POWER
242 #define BJACK_MAX (BUTTON_REC|BUTTON_UP)
243 #define BJACK_MIN (BUTTON_REC|BUTTON_DOWN)
244 #define BJACK_HIT BUTTON_MAIN
245 #define BJACK_STAY BUTTON_MENU
246 #define BJACK_DOUBLEDOWN BUTTON_DOWN
247 #define BJACK_SCORES BUTTON_UP
248 #define BJACK_RESUME BUTTON_FF
249 #define BJACK_UP BUTTON_UP
250 #define BJACK_DOWN BUTTON_DOWN
251 #define BJACK_RIGHT BUTTON_RIGHT
252 #define BJACK_LEFT BUTTON_LEFT
254 #elif CONFIG_KEYPAD == GIGABEAT_S_PAD
255 #define BJACK_START BUTTON_PLAY
256 #define BJACK_QUIT BUTTON_BACK
257 #define BJACK_MAX BUTTON_VOL_UP
258 #define BJACK_MIN BUTTON_VOL_DOWN
259 #define BJACK_HIT BUTTON_VOL_UP
260 #define BJACK_STAY BUTTON_VOL_DOWN
261 #define BJACK_DOUBLEDOWN BUTTON_SELECT
262 #define BJACK_SCORES BUTTON_RIGHT
263 #define BJACK_RESUME BUTTON_MENU
264 #define BJACK_UP BUTTON_UP
265 #define BJACK_DOWN BUTTON_DOWN
266 #define BJACK_RIGHT BUTTON_RIGHT
267 #define BJACK_LEFT BUTTON_LEFT
269 #elif CONFIG_KEYPAD == MROBE100_PAD
271 #define BJACK_START BUTTON_SELECT
272 #define BJACK_QUIT BUTTON_POWER
273 #define BJACK_MAX BUTTON_MENU
274 #define BJACK_MIN BUTTON_DISPLAY
275 #define BJACK_HIT BUTTON_MENU
276 #define BJACK_STAY BUTTON_DISPLAY
277 #define BJACK_DOUBLEDOWN BUTTON_DOWN
278 #define BJACK_SCORES BUTTON_RIGHT
279 #define BJACK_RESUME BUTTON_PLAY
280 #define BJACK_UP BUTTON_UP
281 #define BJACK_DOWN BUTTON_DOWN
282 #define BJACK_RIGHT BUTTON_RIGHT
283 #define BJACK_LEFT BUTTON_LEFT
285 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
287 #define BJACK_START BUTTON_RC_PLAY
288 #define BJACK_QUIT BUTTON_RC_REC
289 #define BJACK_MAX (BUTTON_RC_PLAY|BUTTON_RC_VOL_UP)
290 #define BJACK_MIN (BUTTON_RC_PLAY|BUTTON_RC_VOL_DOWN)
291 #define BJACK_HIT BUTTON_RC_PLAY
292 #define BJACK_STAY BUTTON_RC_FF
293 #define BJACK_DOUBLEDOWN BUTTON_RC_REW
294 #define BJACK_SCORES BUTTON_RC_MENU
295 #define BJACK_RESUME BUTTON_RC_MODE
296 #define BJACK_UP BUTTON_RC_VOL_UP
297 #define BJACK_DOWN BUTTON_RC_VOL_DOWN
298 #define BJACK_RIGHT BUTTON_RC_FF
299 #define BJACK_LEFT BUTTON_RC_REW
301 #elif CONFIG_KEYPAD == COWOND2_PAD
302 #define BJACK_QUIT BUTTON_POWER
303 #define BJACK_DOUBLEDOWN BUTTON_MINUS
304 #define BJACK_SCORES BUTTON_MENU
306 #elif CONFIG_KEYPAD == CREATIVEZVM_PAD
307 #define BJACK_START BUTTON_SELECT
308 #define BJACK_QUIT BUTTON_BACK
309 #define BJACK_MAX (BUTTON_CUSTOM|BUTTON_UP)
310 #define BJACK_MIN (BUTTON_CUSTOM|BUTTON_DOWN)
311 #define BJACK_HIT BUTTON_UP
312 #define BJACK_STAY BUTTON_DOWN
313 #define BJACK_DOUBLEDOWN BUTTON_CUSTOM
314 #define BJACK_SCORES BUTTON_RIGHT
315 #define BJACK_RESUME BUTTON_MENU
316 #define BJACK_UP BUTTON_UP
317 #define BJACK_DOWN BUTTON_DOWN
318 #define BJACK_RIGHT BUTTON_RIGHT
319 #define BJACK_LEFT BUTTON_LEFT
321 #elif CONFIG_KEYPAD == PHILIPS_HDD1630_PAD
322 #define BJACK_START BUTTON_MENU
323 #define BJACK_QUIT BUTTON_POWER
324 #define BJACK_MAX BUTTON_VOL_UP
325 #define BJACK_MIN BUTTON_VOL_DOWN
326 #define BJACK_HIT BUTTON_VOL_UP
327 #define BJACK_STAY BUTTON_VOL_DOWN
328 #define BJACK_DOUBLEDOWN BUTTON_SELECT
329 #define BJACK_SCORES BUTTON_RIGHT
330 #define BJACK_RESUME BUTTON_VIEW
331 #define BJACK_UP BUTTON_UP
332 #define BJACK_DOWN BUTTON_DOWN
333 #define BJACK_RIGHT BUTTON_RIGHT
334 #define BJACK_LEFT BUTTON_LEFT
337 #error No keymap defined!
340 #ifdef HAVE_TOUCHSCREEN
342 #define BJACK_START BUTTON_CENTER
345 #define BJACK_HIT BUTTON_CENTER
348 #define BJACK_MAX BUTTON_TOPRIGHT
351 #define BJACK_MIN BUTTON_TOPLEFT
354 #define BJACK_RESUME BUTTON_BOTTOMRIGHT
357 #define BJACK_STAY BUTTON_BOTTOMLEFT
360 #define BJACK_UP BUTTON_TOPMIDDLE
363 #define BJACK_DOWN BUTTON_BOTTOMMIDDLE
366 #define BJACK_RIGHT BUTTON_MIDRIGHT
369 #define BJACK_LEFT BUTTON_MIDLEFT
374 #ifdef HAVE_LCD_COLOR
375 #define BG_COLOR LCD_RGBPACK(0,157,0)
376 #define FG_COLOR LCD_WHITE
378 #define BG_COLOR LCD_WHITE
379 #define FG_COLOR LCD_BLACK
382 #define CARD_WIDTH BMPWIDTH_card_back
383 #define CARD_HEIGHT BMPHEIGHT_card_back
385 /* This is the max amount of cards onscreen before condensing */
386 #define MAX_CARDS LCD_WIDTH/(CARD_WIDTH+4)
388 extern const fb_data card_deck
[];
389 extern const fb_data card_back
[];
391 #define NEXT_CARD bj->player_cards[done][bj->num_player_cards[done]]
393 /* dealer and player card positions */
394 unsigned int dealer_x
, dealer_y
, player_x
, player_y
;
396 typedef struct card
{
397 unsigned int value
; /* Card's value in Blackjack */
398 unsigned int num
; /* Value on card face 0-12 (0=Ace, 1=2, 11=Q) */
399 unsigned int suit
; /* 0:Spades, 1:Hearts, 2: Clubs; 3: Diamonds */
403 typedef struct game_context
{
404 struct card player_cards
[2][22]; /* 22 Cards means the deal was all aces */
405 struct card dealer_cards
[22]; /* That is the worst-case scenario */
406 unsigned int player_total
;
407 unsigned int dealer_total
;
408 signed int player_money
;
409 unsigned int num_player_cards
[2];
410 unsigned int num_dealer_cards
;
411 unsigned int current_bet
;
412 unsigned int split_status
; /* 0 = split hasn't been asked, *
413 * 1 = split did not occur *
414 * 2 = split occurred *
415 * 3 = split occurred and 1st hand done */
418 bool asked_insurance
;
419 signed short highscores
[NUM_SCORES
];
424 /*****************************************************************************
425 * blackjack_init() initializes blackjack data structures.
426 ******************************************************************************/
427 static void blackjack_init(struct game_context
* bj
) {
428 /* seed the rand generator */
429 rb
->srand(*rb
->current_tick
);
431 /* reset card positions */
433 dealer_y
= LCD_HEIGHT
/4 - CARD_HEIGHT
/2;
435 player_y
= LCD_HEIGHT
- LCD_HEIGHT
/4 - CARD_HEIGHT
/2;
437 /* check for resumed game */
438 if(bj
->resume
) return;
441 bj
->player_total
= 0;
442 bj
->dealer_total
= 0;
443 bj
->num_player_cards
[0] = 2;
444 bj
->num_player_cards
[1] = 0;
445 bj
->num_dealer_cards
= 2;
446 bj
->end_hand
= false;
447 bj
->split_status
= 0;
448 bj
->is_blackjack
= false;
449 bj
->asked_insurance
= false;
452 /*****************************************************************************
453 * blackjack_drawtable() draws the table and some text.
454 ******************************************************************************/
455 static void blackjack_drawtable(struct game_context
* bj
) {
456 unsigned int w
, h
, y_loc
;
460 rb
->lcd_getstringsize("Bet", &w
, &h
);
461 rb
->lcd_putsxy(LCD_WIDTH
- w
, 2*h
+ 1, "Bet");
462 rb
->snprintf(str
, 9, "$%d", bj
->current_bet
);
463 rb
->lcd_getstringsize(str
, &w
, &h
);
464 rb
->lcd_putsxy(LCD_WIDTH
- w
, 3*h
+ 1, str
);
465 y_loc
= LCD_HEIGHT
/2;
467 rb
->lcd_getstringsize("Bet", &w
, &h
);
468 rb
->lcd_putsxy(LCD_WIDTH
- w
, 5*h
/ 2, "Bet");
469 rb
->snprintf(str
, 9, "$%d", bj
->current_bet
);
470 rb
->lcd_getstringsize(str
, &w
, &h
);
471 rb
->lcd_putsxy(LCD_WIDTH
- w
, 7*h
/ 2, str
);
472 rb
->lcd_hline(0, LCD_WIDTH
, LCD_HEIGHT
/2);
473 y_loc
= LCD_HEIGHT
/2 + h
;
476 rb
->lcd_putsxy(0,0, "Dealer");
477 rb
->lcd_getstringsize("Player", &w
, &h
);
478 rb
->lcd_putsxy(0, y_loc
, "Player");
479 rb
->lcd_getstringsize("Total", &w
, &h
);
480 rb
->lcd_putsxy(LCD_WIDTH
- w
, y_loc
, "Total");
481 rb
->lcd_getstringsize("Money", &w
, &h
);
482 rb
->lcd_putsxy(LCD_WIDTH
- w
, 0, "Money");
483 rb
->snprintf(str
, 9, "$%d", bj
->player_money
- bj
->current_bet
);
484 rb
->lcd_getstringsize(str
, &w
, &h
);
485 rb
->lcd_putsxy(LCD_WIDTH
- w
, h
+ 1, str
);
486 rb
->snprintf(str
, 3, "%d", bj
->player_total
);
487 rb
->lcd_getstringsize(str
, &w
, &h
);
488 rb
->lcd_putsxy(LCD_WIDTH
- w
, y_loc
+ h
, str
);
491 /*****************************************************************************
492 * find_value() is passed a card and returns its blackjack value.
493 ******************************************************************************/
494 static unsigned int find_value(unsigned int number
) {
495 unsigned int thisValue
;
497 thisValue
= 11; /* Aces get a value of 11 at first */
498 else if (number
< 10)
499 thisValue
= number
+ 1;
501 thisValue
= 10; /* Anything 10 or higher gets a value of 10 */
506 /*****************************************************************************
507 * draw_card() draws a card to the screen.
508 ******************************************************************************/
509 static void draw_card(struct card temp_card
, bool shown
, unsigned int x
,
512 rb
->lcd_bitmap_part(card_deck
, CARD_WIDTH
*temp_card
.num
,
513 CARD_HEIGHT
*temp_card
.suit
, BMPWIDTH_card_deck
,
514 x
+1, y
+1, CARD_WIDTH
, CARD_HEIGHT
);
516 rb
->lcd_bitmap(card_back
, x
+1, y
+1,CARD_WIDTH
, CARD_HEIGHT
);
518 rb
->lcd_set_foreground(LCD_BLACK
);
523 rb
->lcd_hline(x
+2, x
+CARD_WIDTH
-1, y
);
524 rb
->lcd_hline(x
+2, x
+CARD_WIDTH
-1, y
+CARD_HEIGHT
+1);
525 rb
->lcd_vline(x
, y
+2, y
+CARD_HEIGHT
-3);
526 rb
->lcd_vline(x
+CARD_WIDTH
+1, y
+2, y
+CARD_HEIGHT
-1);
527 rb
->lcd_drawpixel(x
+1, y
+1);
528 rb
->lcd_drawpixel(x
+1, y
+CARD_HEIGHT
);
529 rb
->lcd_drawpixel(x
+CARD_WIDTH
, y
+1);
530 rb
->lcd_drawpixel(x
+CARD_WIDTH
, y
+CARD_HEIGHT
);
532 rb
->lcd_hline(x
+1, x
+CARD_WIDTH
, y
);
533 rb
->lcd_hline(x
+1, x
+CARD_WIDTH
, y
+CARD_HEIGHT
+1);
534 rb
->lcd_vline(x
, y
+1, y
+CARD_HEIGHT
);
535 rb
->lcd_vline(x
+CARD_WIDTH
+1, y
+1, y
+CARD_HEIGHT
);
539 rb
->lcd_set_foreground(FG_COLOR
);
543 /*****************************************************************************
544 * new_card() initializes a new card and gives it values.
545 ******************************************************************************/
546 static struct card
new_card(void) {
547 struct card new_card
;
548 new_card
.suit
= rb
->rand()%4; /* Random number 0-3 */
549 new_card
.num
= rb
->rand()%13; /* Random number 0-12 */
550 new_card
.value
= find_value(new_card
.num
);
551 new_card
.is_soft_ace
= new_card
.num
== 0 ? true : false;
555 /*****************************************************************************
556 * deal_init_card() deals and draws to the screen the player's and dealer's
558 ******************************************************************************/
559 static void deal_init_cards(struct game_context
* bj
) {
560 bj
->dealer_cards
[0] = new_card();
561 bj
->dealer_total
+= bj
->dealer_cards
[0].value
;
563 draw_card(bj
->dealer_cards
[0], false, dealer_x
, dealer_y
);
565 bj
->dealer_cards
[1] = new_card();
566 bj
->dealer_total
+= bj
->dealer_cards
[1].value
;
567 draw_card(bj
->dealer_cards
[1], true, dealer_x
+ CARD_WIDTH
+ 4, dealer_y
);
569 bj
->player_cards
[0][0] = new_card();
570 bj
->player_total
+= bj
->player_cards
[0][0].value
;
571 draw_card(bj
->player_cards
[0][0], true, player_x
, player_y
);
572 player_x
+= CARD_WIDTH
+ 4;
574 bj
->player_cards
[0][1] = new_card();
575 bj
->player_total
+= bj
->player_cards
[0][1].value
;
576 draw_card(bj
->player_cards
[0][1], true, player_x
, player_y
);
577 player_x
+= CARD_WIDTH
+ 4;
580 /*****************************************************************************
581 * redraw_board() redraws all the cards and the board
582 ******************************************************************************/
583 static void redraw_board(struct game_context
* bj
) {
584 unsigned int i
, n
, upper_bound
;
585 rb
->lcd_clear_display();
587 blackjack_drawtable(bj
);
590 upper_bound
= bj
->split_status
> 1 ? 2 : 1;
592 for (i
= 0; i
< bj
->num_dealer_cards
; i
++) {
594 draw_card(bj
->dealer_cards
[0], false, dealer_x
, dealer_y
);
596 /* increment i so the dealer's first card isn't displayed */
598 dealer_x
+= CARD_WIDTH
+ 4;
600 draw_card(bj
->dealer_cards
[i
], true, dealer_x
, dealer_y
);
602 if (bj
->num_dealer_cards
> MAX_CARDS
-1)
605 dealer_x
+= CARD_WIDTH
+ 4;
608 for (n
= 0; n
< upper_bound
; n
++) {
609 for (i
= 0; i
< bj
->num_player_cards
[n
]; i
++) {
610 draw_card(bj
->player_cards
[n
][i
], true, player_x
, player_y
);
611 if (bj
->split_status
>1 || bj
->num_player_cards
[n
]>MAX_CARDS
)
614 player_x
+= CARD_WIDTH
+ 4;
616 if (bj
->split_status
> 1)
617 player_x
= LCD_WIDTH
/2 + 4;
621 /*****************************************************************************
622 * update_total updates the player's total
623 ******************************************************************************/
624 static void update_total(struct game_context
* bj
) {
627 rb
->snprintf(total
, 3, "%d", bj
->player_total
);
628 rb
->lcd_getstringsize(total
, &w
, &h
);
632 rb
->lcd_putsxy(LCD_WIDTH
- w
, LCD_HEIGHT
/2 + h
, total
);
633 rb
->lcd_update_rect(LCD_WIDTH
- w
, LCD_HEIGHT
/2 + h
, w
, h
);
637 /*****************************************************************************
638 * check_for_aces() is passed an array of cards and returns where an ace is
639 * located. Otherwise, returns -1.
640 ******************************************************************************/
641 static signed int check_for_aces(struct card temp_cards
[],
644 for(i
= 0; i
< size
; i
++) {
645 if (temp_cards
[i
].is_soft_ace
== true)
651 /*****************************************************************************
652 * check_totals() compares player and dealer totals.
653 * 0: bust 1: loss, 2: push, 3: win, 4: blackjack, 5: something's not right...
654 ******************************************************************************/
655 static unsigned int check_totals(struct game_context
* bj
)
658 if (bj
->player_total
> 21)
660 else if (bj
->player_total
== 21 && bj
->is_blackjack
)
661 if (bj
->dealer_total
== 21 && bj
->num_dealer_cards
== 2)
665 else if (bj
->player_total
== bj
->dealer_total
)
667 else if (bj
->dealer_total
> 21 && bj
->player_total
< 22)
669 else if (bj
->dealer_total
> bj
->player_total
)
671 else if (bj
->player_total
> bj
->dealer_total
)
679 /*****************************************************************************
680 * finish_dealer() draws cards for the dealer until he has 17 or more.
681 ******************************************************************************/
682 static void finish_dealer(struct game_context
* bj
) {
685 if (bj
->dealer_total
> 16 && bj
->dealer_total
< 22)
688 while (bj
->dealer_total
< 17) {
689 bj
->dealer_cards
[bj
->num_dealer_cards
] = new_card();
690 bj
->dealer_total
+= bj
->dealer_cards
[bj
->num_dealer_cards
].value
;
691 bj
->num_dealer_cards
++;
694 while (bj
->dealer_total
> 21) {
695 temp
= check_for_aces(bj
->dealer_cards
, bj
->num_dealer_cards
);
697 bj
->dealer_cards
[temp
].is_soft_ace
= false;
698 bj
->dealer_total
-= 10;
705 /*****************************************************************************
706 * finish_game() completes the game once player's turn is over.
707 ******************************************************************************/
708 static void finish_game(struct game_context
* bj
) {
709 unsigned int rValue
, w
, h
;
714 } while (bj
->dealer_total
< 17);
717 rValue
= check_totals(bj
);
720 rb
->snprintf(str
, sizeof(str
), " Bust! ");
721 bj
->player_money
-= bj
->current_bet
;
723 else if (rValue
== 1) {
724 rb
->snprintf(str
, sizeof(str
), " Sorry, you lost. ");
725 bj
->player_money
-= bj
->current_bet
;
727 else if (rValue
== 2) {
728 rb
->snprintf(str
, sizeof(str
), " Push ");
730 else if (rValue
== 3) {
731 rb
->snprintf(str
, sizeof(str
), " You won! ");
732 bj
->player_money
+= bj
->current_bet
;
735 rb
->snprintf(str
, sizeof(str
), " Blackjack! ");
736 bj
->player_money
+= bj
->current_bet
* 3 / 2;
738 rb
->lcd_getstringsize(str
, &w
, &h
);
741 rb
->lcd_set_drawmode(DRMODE_BG
+DRMODE_INVERSEVID
);
742 rb
->lcd_fillrect(0, LCD_HEIGHT
/2, LCD_WIDTH
, LCD_HEIGHT
/2);
743 rb
->lcd_set_drawmode(DRMODE_SOLID
);
744 rb
->lcd_putsxy(LCD_WIDTH
/2 - w
/2, LCD_HEIGHT
/2 + h
, str
);
745 rb
->snprintf(str
, 12, "You have %d", bj
->player_total
);
746 rb
->lcd_getstringsize(str
, &w
, &h
);
747 rb
->lcd_putsxy(LCD_WIDTH
/2 - w
/2, LCD_HEIGHT
/2, str
);
749 rb
->lcd_putsxy(LCD_WIDTH
/2 - w
/2, LCD_HEIGHT
/2 - h
/2, str
);
754 /*****************************************************************************
755 * blackjack_recordscore() inserts a high score into the high scores list and
756 * returns the high score position.
757 ******************************************************************************/
758 static unsigned int blackjack_recordscore(struct game_context
* bj
) {
760 unsigned int position
= 0;
761 signed short current
, temp
;
763 /* calculate total score */
764 current
= bj
->player_money
;
765 if(current
<= 10) return 0;
767 /* insert the current score into the high scores */
768 for(i
=0; i
<NUM_SCORES
; i
++) {
769 if(current
>= bj
->highscores
[i
]) {
774 temp
= bj
->highscores
[i
];
775 bj
->highscores
[i
] = current
;
783 /*****************************************************************************
784 * blackjack_loadscores() loads the high scores saved file.
785 ******************************************************************************/
786 static void blackjack_loadscores(struct game_context
* bj
) {
791 /* clear high scores */
792 rb
->memset(bj
->highscores
, 0, sizeof(bj
->highscores
));
794 /* open scores file */
795 fd
= rb
->open(SCORE_FILE
, O_RDONLY
);
798 /* read in high scores */
799 if(rb
->read(fd
, bj
->highscores
, sizeof(bj
->highscores
)) <= 0) {
800 /* scores are bad, reset */
801 rb
->memset(bj
->highscores
, 0, sizeof(bj
->highscores
));
807 /*****************************************************************************
808 * blackjack_savescores() saves the high scores saved file.
809 ******************************************************************************/
810 static void blackjack_savescores(struct game_context
* bj
) {
813 /* write out the high scores to the save file */
814 fd
= rb
->open(SCORE_FILE
, O_WRONLY
|O_CREAT
);
815 rb
->write(fd
, bj
->highscores
, sizeof(bj
->highscores
));
820 /*****************************************************************************
821 * blackjack_loadgame() loads the saved game and returns load success.
822 ******************************************************************************/
823 static bool blackjack_loadgame(struct game_context
* bj
) {
828 fd
= rb
->open(SAVE_FILE
, O_RDONLY
);
829 if(fd
< 0) return loaded
;
831 /* read in saved game */
833 if(rb
->read(fd
, &bj
->player_money
, sizeof(bj
->player_money
)) <= 0) break;
834 if(rb
->read(fd
, &bj
->player_total
, sizeof(bj
->player_total
)) <= 0) break;
835 if(rb
->read(fd
, &bj
->dealer_total
, sizeof(bj
->dealer_total
)) <= 0) break;
836 if(rb
->read(fd
, &bj
->num_player_cards
, sizeof(bj
->num_player_cards
))<=0)
838 if(rb
->read(fd
, &bj
->num_dealer_cards
, sizeof(bj
->num_dealer_cards
))<=0)
840 if(rb
->read(fd
, &bj
->current_bet
, sizeof(bj
->current_bet
)) <= 0) break;
841 if(rb
->read(fd
, &bj
->is_blackjack
, sizeof(bj
->is_blackjack
)) <= 0) break;
842 if(rb
->read(fd
, &bj
->split_status
, sizeof(bj
->split_status
)) <= 0) break;
843 if(rb
->read(fd
, &bj
->asked_insurance
, sizeof(bj
->asked_insurance
)) <= 0)
845 if(rb
->read(fd
, &bj
->end_hand
, sizeof(bj
->end_hand
)) <= 0) break;
846 if(rb
->read(fd
, &bj
->player_cards
, sizeof(bj
->player_cards
)) <= 0) break;
847 if(rb
->read(fd
, &bj
->dealer_cards
, sizeof(bj
->dealer_cards
)) <= 0) break;
855 /* delete saved file */
856 rb
->remove(SAVE_FILE
);
860 /*****************************************************************************
861 * blackjack_savegame() saves the current game state.
862 ******************************************************************************/
863 static void blackjack_savegame(struct game_context
* bj
) {
866 /* write out the game state to the save file */
867 fd
= rb
->open(SAVE_FILE
, O_WRONLY
|O_CREAT
);
868 rb
->write(fd
, &bj
->player_money
, sizeof(bj
->player_money
));
869 rb
->write(fd
, &bj
->player_total
, sizeof(bj
->player_total
));
870 rb
->write(fd
, &bj
->dealer_total
, sizeof(bj
->dealer_total
));
871 rb
->write(fd
, &bj
->num_player_cards
, sizeof(bj
->num_player_cards
));
872 rb
->write(fd
, &bj
->num_dealer_cards
, sizeof(bj
->num_dealer_cards
));
873 rb
->write(fd
, &bj
->current_bet
, sizeof(bj
->current_bet
));
874 rb
->write(fd
, &bj
->is_blackjack
, sizeof(bj
->is_blackjack
));
875 rb
->write(fd
, &bj
->split_status
, sizeof(bj
->split_status
));
876 rb
->write(fd
, &bj
->asked_insurance
, sizeof(bj
->asked_insurance
));
877 rb
->write(fd
, &bj
->end_hand
, sizeof(bj
->end_hand
));
878 rb
->write(fd
, &bj
->player_cards
, sizeof(bj
->player_cards
));
879 rb
->write(fd
, &bj
->dealer_cards
, sizeof(bj
->dealer_cards
));
885 /*****************************************************************************
886 * blackjack_callback() is the default event handler callback which is called
887 * on usb connect and shutdown.
888 ******************************************************************************/
889 static void blackjack_callback(void* param
) {
890 struct game_context
* bj
= (struct game_context
*) param
;
892 rb
->splash(HZ
, "Saving high scores...");
893 blackjack_savescores(bj
);
897 /*****************************************************************************
898 * blackjack_get_yes_no() gets a yes/no answer from the user
899 ******************************************************************************/
900 static unsigned int blackjack_get_yes_no(char message
[20]) {
902 unsigned int w
, h
, b
, choice
= 0;
903 bool breakout
= false;
904 char message_yes
[24], message_no
[24];
906 rb
->strcpy(message_yes
, message
);
907 rb
->strcpy(message_no
, message
);
908 rb
->strcat(message_yes
, " Yes");
909 rb
->strcat(message_no
, " No");
910 rb
->lcd_getstringsize(message_yes
, &w
, &h
);
911 const char *stg
[] = {message_yes
, message_no
};
919 #ifdef HAVE_LCD_COLOR
920 rb
->lcd_fillrect(LCD_WIDTH
/2 - w
/2, LCD_HEIGHT
/2 + b
, w
+1, h
+3);
921 rb
->lcd_set_foreground(LCD_BLACK
);
922 rb
->lcd_set_background(LCD_WHITE
);
924 rb
->lcd_set_drawmode(DRMODE_BG
+DRMODE_INVERSEVID
);
925 rb
->lcd_fillrect(LCD_WIDTH
/2 - w
/2, LCD_HEIGHT
/2 + b
, w
+1, h
+3);
926 rb
->lcd_set_drawmode(DRMODE_SOLID
);
928 rb
->lcd_drawrect(LCD_WIDTH
/2 - w
/2 - 1, LCD_HEIGHT
/2 + b
- 1, w
+3, h
+4);
931 rb
->lcd_putsxy(LCD_WIDTH
/2 - w
/2, LCD_HEIGHT
/2 + b
+1, stg
[choice
]);
932 rb
->lcd_update_rect(LCD_WIDTH
/2 - w
/2 - 1, LCD_HEIGHT
/2 + b
-1,
934 button
= rb
->button_get(true);
938 case (BJACK_LEFT
|BUTTON_REPEAT
):
940 case (BJACK_RIGHT
|BUTTON_REPEAT
):
943 case BJACK_START
: breakout
= true;
945 case BJACK_QUIT
: breakout
= true;
952 rb
->lcd_set_foreground(FG_COLOR
);
953 rb
->lcd_set_background(BG_COLOR
);
958 /*****************************************************************************
959 * blackjack_get_amount() gets an amount from the player to be used
960 ******************************************************************************/
961 static signed int blackjack_get_amount(char message
[20], signed int lower_limit
,
962 signed int upper_limit
,
966 bool changed
= false;
970 rb
->lcd_getstringsize("A", &w
, &h
); /* find the size of one character */
972 if (start
> upper_limit
)
973 amount
= upper_limit
;
974 else if (start
< lower_limit
)
975 amount
= lower_limit
;
980 rb
->lcd_set_background(LCD_WHITE
);
981 rb
->lcd_set_foreground(LCD_BLACK
);
985 rb
->lcd_clear_display();
986 rb
->lcd_puts(0, 1, message
);
987 rb
->snprintf(str
, 9, "$%d", amount
);
988 rb
->lcd_puts(0, 2, str
);
989 rb
->lcd_puts(0, 3, "RIGHT: +1");
990 rb
->lcd_puts(0, 4, "LEFT: -1");
991 rb
->lcd_puts(0, 5, "UP: +10");
992 rb
->lcd_puts(0, 6, "DOWN: -10");
995 rb
->lcd_set_drawmode(DRMODE_BG
+DRMODE_INVERSEVID
);
996 rb
->lcd_fillrect(LCD_WIDTH
/2 - 9*w
- 1, LCD_HEIGHT
/2 - 4*h
- 3, 37*w
/ 2,
998 rb
->lcd_set_drawmode(DRMODE_SOLID
);
999 rb
->lcd_drawrect(LCD_WIDTH
/2 - 9*w
- 1, LCD_HEIGHT
/2 - 4*h
- 3, 37*w
/ 2,
1001 rb
->lcd_putsxy(LCD_WIDTH
/2 - 9*w
, LCD_HEIGHT
/2 - 4*h
- 1, message
);
1002 rb
->snprintf(str
, 9, "$%d", amount
);
1003 rb
->lcd_putsxy(LCD_WIDTH
/2 - 9*w
, LCD_HEIGHT
/2 - 3*h
, str
);
1004 #if (CONFIG_KEYPAD == IPOD_4G_PAD) || \
1005 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
1006 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
1007 rb
->lcd_putsxy(LCD_WIDTH
/2 - 9*w
, LCD_HEIGHT
/2 - h
-2, " >>|: +1");
1008 rb
->lcd_putsxy(LCD_WIDTH
/2 - 9*w
, LCD_HEIGHT
/2 - 1, " |<<: -1");
1009 rb
->lcd_putsxy(LCD_WIDTH
/2 - 9*w
, LCD_HEIGHT
/2 + h
, "SCROLL+: +10");
1010 rb
->lcd_putsxy(LCD_WIDTH
/2 - 9*w
, LCD_HEIGHT
/2 + 2*h
+ 1, "SCROLL-: -10");
1011 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
1012 rb
->lcd_putsxy(LCD_WIDTH
/2 - 9*w
, LCD_HEIGHT
/2 - h
-2, "RIGHT: +1");
1013 rb
->lcd_putsxy(LCD_WIDTH
/2 - 9*w
, LCD_HEIGHT
/2 - 1, "LEFT: -1");
1014 rb
->lcd_putsxy(LCD_WIDTH
/2 - 9*w
, LCD_HEIGHT
/2 + h
, "SCROLL+: +10");
1015 rb
->lcd_putsxy(LCD_WIDTH
/2 - 9*w
, LCD_HEIGHT
/2 + 2*h
+ 1, "SCROLL-: -10");
1017 rb
->lcd_putsxy(LCD_WIDTH
/2 - 9*w
, LCD_HEIGHT
/2 - h
-2, "RIGHT: +1");
1018 rb
->lcd_putsxy(LCD_WIDTH
/2 - 9*w
, LCD_HEIGHT
/2 - 1, "LEFT: -1");
1019 rb
->lcd_putsxy(LCD_WIDTH
/2 - 9*w
, LCD_HEIGHT
/2 + h
, "UP: +10");
1020 rb
->lcd_putsxy(LCD_WIDTH
/2 - 9*w
, LCD_HEIGHT
/2 + 2*h
+ 1, "DOWN: -10");
1022 rb
->lcd_update_rect(LCD_WIDTH
/2 - 9*w
- 2, LCD_HEIGHT
/2 - 9*h
/2, 37*w
/2 + 1,
1027 button
= rb
->button_get(true);
1031 case (BJACK_UP
|BUTTON_REPEAT
):
1032 if (amount
+ 10 < upper_limit
+ 1) {
1038 case (BJACK_DOWN
|BUTTON_REPEAT
):
1039 if (amount
- 10 > lower_limit
- 1) {
1045 case (BJACK_RIGHT
|BUTTON_REPEAT
):
1046 if (amount
+ 1 < upper_limit
+ 1) {
1052 case (BJACK_LEFT
|BUTTON_REPEAT
):
1053 if (amount
- 1 > lower_limit
- 1) {
1059 amount
= upper_limit
;
1063 amount
= lower_limit
;
1070 rb
->lcd_set_foreground(FG_COLOR
);
1071 rb
->lcd_set_background(BG_COLOR
);
1073 rb
->lcd_clear_display();
1078 rb
->snprintf(str
, 9, "$%d", amount
);
1079 #if LCD_HEIGHT <= 64
1080 rb
->lcd_puts(0, 2, str
);
1083 rb
->lcd_set_drawmode(DRMODE_BG
+DRMODE_INVERSEVID
);
1084 rb
->lcd_fillrect(LCD_WIDTH
/2 - 9*w
, LCD_HEIGHT
/2 - 3*h
, 5*w
, h
);
1085 rb
->lcd_set_drawmode(DRMODE_SOLID
);
1086 rb
->lcd_putsxy(LCD_WIDTH
/2 - 9*w
, LCD_HEIGHT
/2 - 3*h
, str
);
1087 rb
->lcd_update_rect(LCD_WIDTH
/2 - 9*w
, LCD_HEIGHT
/2 - 3*h
, 5*w
, h
);
1094 /*****************************************************************************
1095 * blackjack_get_bet() gets the player's bet.
1096 ******************************************************************************/
1097 static void blackjack_get_bet(struct game_context
* bj
) {
1098 bj
->current_bet
= blackjack_get_amount("Please enter a bet", 10,
1099 bj
->player_money
, bj
->current_bet
);
1102 /*****************************************************************************
1103 * double_down() returns one final card then finishes the game
1104 ******************************************************************************/
1105 static void double_down(struct game_context
* bj
) {
1106 bj
->current_bet
*= 2;
1107 bj
->player_cards
[0][bj
->num_player_cards
[0]] = new_card();
1108 bj
->player_total
+= bj
->player_cards
[0][bj
->num_player_cards
[0]].value
;
1109 bj
->num_player_cards
[0]++;
1112 /*****************************************************************************
1113 * split() checks if the player wants to split and acts accordingly.
1114 * When bj->split_status is 1, no split occurred. 2 means the player split and 3
1115 * means a split has already occurred and the first hand is done.
1116 ******************************************************************************/
1117 static void split(struct game_context
* bj
) {
1118 if (blackjack_get_yes_no("Split?") == 1)
1119 bj
->split_status
= 1;
1121 bj
->split_status
= 2;
1122 bj
->current_bet
*= 2;
1123 bj
->num_player_cards
[0] = 1;
1124 bj
->num_player_cards
[1] = 1;
1125 bj
->player_cards
[1][0] = bj
->player_cards
[0][1];
1126 bj
->player_total
= bj
->player_cards
[0][0].value
;
1130 /*****************************************************************************
1131 * insurance() see if the player wants to buy insurance and how much.
1132 ******************************************************************************/
1133 static unsigned int insurance(struct game_context
* bj
) {
1134 unsigned int insurance
, max_amount
;
1136 insurance
= blackjack_get_yes_no("Buy Insurance?");
1137 bj
->asked_insurance
= true;
1138 max_amount
= bj
->current_bet
< (unsigned int)bj
->player_money
?
1139 bj
->current_bet
/2 : (unsigned int)bj
->player_money
;
1140 if (insurance
== 1) return 0;
1142 insurance
= blackjack_get_amount("How much?", 0, max_amount
, 0);
1147 /*****************************************************************************
1148 * play_again() checks to see if the player wants to keep playing.
1149 ******************************************************************************/
1150 static unsigned int play_again(void) {
1151 return blackjack_get_yes_no("Play Again?");
1154 /*****************************************************************************
1155 * blackjack_menu() is the initial menu at the start of the game.
1156 ******************************************************************************/
1157 static unsigned int blackjack_menu(struct game_context
* bj
) {
1159 char *title
= "Blackjack";
1161 unsigned int i
, w
, h
;
1162 bool breakout
= false;
1163 bool showscores
= false;
1167 rb
->lcd_set_background(BG_COLOR
);
1168 rb
->lcd_set_foreground(FG_COLOR
);
1170 rb
->lcd_clear_display();
1173 /* welcome screen to display key bindings */
1174 rb
->lcd_getstringsize(title
, &w
, &h
);
1175 rb
->lcd_putsxy((LCD_WIDTH
-w
)/2, 0, title
);
1177 #if CONFIG_KEYPAD == RECORDER_PAD
1178 rb
->lcd_puts(0, 1, "ON: start");
1179 rb
->lcd_puts(0, 2, "OFF: exit");
1180 rb
->lcd_puts(0, 3, "F1: hit");
1181 rb
->lcd_puts(0, 4, "F2: stay");
1182 rb
->lcd_puts(0, 5, "F3: double down");
1183 rb
->lcd_puts(0, 6, "PLAY: save/resume");
1184 rb
->snprintf(str
, 21, "High Score: $%d", bj
->highscores
[0]);
1185 rb
->lcd_puts(0, 7, str
);
1186 #elif CONFIG_KEYPAD == ONDIO_PAD
1187 rb
->lcd_puts(0, 1, "MENU: start");
1188 rb
->lcd_puts(0, 2, "OFF: exit");
1189 rb
->lcd_puts(0, 3, "LEFT: hit");
1190 rb
->lcd_puts(0, 4, "RIGHT: stay");
1191 rb
->lcd_puts(0, 5, "UP: double down");
1192 rb
->lcd_puts(0, 6, "DOWN: save/resume");
1193 rb
->snprintf(str
, 21, "High Score: $%d", bj
->highscores
[0]);
1194 rb
->lcd_puts(0, 7, str
);
1195 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || (CONFIG_KEYPAD == IRIVER_H300_PAD)
1196 rb
->lcd_puts(0, 2, "PLAY to start & to hit");
1197 rb
->lcd_puts(0, 3, "STOP to exit");
1198 rb
->lcd_puts(0, 4, "REC to stay");
1199 rb
->lcd_puts(0, 5, "NAVI to double down ");
1200 rb
->lcd_puts(0, 6, " & to view highscores");
1201 rb
->lcd_puts(0, 7, "AB to save/resume");
1202 rb
->snprintf(str
, 21, "High Score: $%d", bj
->highscores
[0]);
1203 rb
->lcd_puts(0, 8, str
);
1204 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
1205 rb
->lcd_puts(0, 2, "PLAY to start & hit");
1206 rb
->lcd_puts(0, 3, "POWER to exit");
1207 rb
->lcd_puts(0, 4, ">>| to stay");
1208 rb
->lcd_puts(0, 5, "|<< to double down");
1209 rb
->lcd_puts(0, 6, "LEFT to view scores");
1210 rb
->lcd_puts(0, 7, "RIGHT to save/resume");
1211 rb
->snprintf(str
, 21, "High Score: $%d", bj
->highscores
[0]);
1212 rb
->lcd_puts(0, 8, str
);
1214 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \
1215 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
1216 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
1218 rb
->lcd_puts(0, 2, "SELECT to start & to hit");
1219 rb
->lcd_puts(0, 3, "MENU to exit");
1220 rb
->lcd_puts(0, 4, ">>| to stay & to view highscores");
1221 rb
->lcd_puts(0, 5, "|<< to double down");
1222 rb
->lcd_puts(0, 6, "PLAY to save/resume");
1223 rb
->snprintf(str
, 21, "High Score: $%d", bj
->highscores
[0]);
1224 rb
->lcd_puts(0, 7, str
);
1226 rb
->lcd_puts(0, 2, "SELECT to start & to ");
1227 rb
->lcd_puts(0, 3, " hit");
1228 rb
->lcd_puts(0, 4, "MENU to exit");
1229 rb
->lcd_puts(0, 5, ">>| to stay & to view ");
1230 rb
->lcd_puts(0, 6, " highscores");
1231 rb
->lcd_puts(0, 7, "|<< to double down");
1232 rb
->lcd_puts(0, 8, "PLAY to save/resume");
1233 rb
->snprintf(str
, 21, "High Score: $%d", bj
->highscores
[0]);
1234 rb
->lcd_puts(0, 9, str
);
1236 #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD
1237 rb
->lcd_puts(0, 2, "PLAY to start to hit");
1238 rb
->lcd_puts(0, 3, "POWER to exit");
1239 rb
->lcd_puts(0, 4, "SELECT to hit");
1240 rb
->lcd_puts(0, 5, "REC to stay");
1241 rb
->lcd_puts(0, 6, "PLAY to double down");
1242 rb
->lcd_puts(0, 7, "RIGHT to view highscores ");
1243 rb
->lcd_puts(0, 8, "DOWN to save/resume");
1244 rb
->snprintf(str
, 21, "High Score: $%d", bj
->highscores
[0]);
1245 rb
->lcd_puts(0, 9, str
);
1246 #elif CONFIG_KEYPAD == IRIVER_IFP7XX_PAD
1247 rb
->lcd_puts(0, 2, "AB to start & to");
1248 rb
->lcd_puts(0, 3, " stay");
1249 rb
->lcd_puts(0, 4, "EQ to hit");
1250 rb
->lcd_puts(0, 5, "PLAY to exit");
1251 rb
->lcd_puts(0, 6, "CLICK to double down");
1252 rb
->lcd_puts(0, 7, "& to view highscores");
1253 rb
->lcd_puts(0, 8, "AB+EQ to save/resume");
1254 rb
->snprintf(str
, 21, "High Score: $%d", bj
->highscores
[0]);
1255 rb
->lcd_puts(0, 9, str
);
1256 #elif CONFIG_KEYPAD == GIGABEAT_PAD
1257 rb
->lcd_puts(0, 2, "A to start");
1258 rb
->lcd_puts(0, 3, "POWER to exit");
1259 rb
->lcd_puts(0, 4, "VOL+ to hit");
1260 rb
->lcd_puts(0, 5, "VOL- to stay");
1261 rb
->lcd_puts(0, 6, "CENTER to double down");
1262 rb
->lcd_puts(0, 6, "RIGHT to view highscores ");
1263 rb
->lcd_puts(0, 8, "MENU to save/resume");
1264 rb
->snprintf(str
, 21, "High Score: $%d", bj
->highscores
[0]);
1265 rb
->lcd_puts(0, 9, str
);
1266 #elif CONFIG_KEYPAD == MROBE100_PAD
1267 rb
->lcd_puts(0, 2, "CENTER to start");
1268 rb
->lcd_puts(0, 3, "POWER to exit");
1269 rb
->lcd_puts(0, 4, "MENU to hit");
1270 rb
->lcd_puts(0, 5, "DISPLAY to stay");
1271 rb
->lcd_puts(0, 6, "DOWN to double down");
1272 rb
->lcd_puts(0, 6, "RIGHT to view highscores ");
1273 rb
->lcd_puts(0, 8, "PLAY to save/resume");
1274 rb
->snprintf(str
, 21, "High Score: $%d", bj
->highscores
[0]);
1275 rb
->lcd_puts(0, 9, str
);
1276 #elif (CONFIG_KEYPAD == SANSA_E200_PAD)
1277 rb
->lcd_puts(0, 2, "SELECT to start & to hit");
1278 rb
->lcd_puts(0, 3, "POWER to exit");
1279 rb
->lcd_puts(0, 4, "RIGHT to stay");
1280 rb
->lcd_puts(0, 5, "LEFT to double down");
1281 rb
->lcd_puts(0, 6, "REC to save/resume");
1282 rb
->lcd_puts(0, 7, "UP to view scores");
1283 rb
->snprintf(str
, 21, "High Score: $%d", bj
->highscores
[0]);
1284 rb
->lcd_puts(0, 8, str
);
1285 #elif (CONFIG_KEYPAD == SANSA_C200_PAD)
1286 rb
->lcd_puts(0, 2, "SELECT to start & to hit");
1287 rb
->lcd_puts(0, 3, "POWER to exit");
1288 rb
->lcd_puts(0, 4, "RIGHT to stay");
1289 rb
->lcd_puts(0, 5, "LEFT to double down");
1290 rb
->lcd_puts(0, 6, "DOWN to save/resume");
1291 rb
->lcd_puts(0, 7, "REC to view scores");
1292 rb
->snprintf(str
, 21, "High Score: $%d", bj
->highscores
[0]);
1293 rb
->lcd_puts(0, 9, str
);
1294 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
1295 rb
->lcd_puts(0, 2, "PLAY to start & to");
1296 rb
->lcd_puts(0, 3, " hit");
1297 rb
->lcd_puts(0, 4, "REC to exit");
1298 rb
->lcd_puts(0, 5, "FF to stay");
1299 rb
->lcd_puts(0, 6, "REW to double down");
1300 rb
->lcd_puts(0, 7, "MODE to save/resume");
1301 rb
->lcd_puts(0, 8, "MENU to view scores");
1302 rb
->snprintf(str
, 21, "High Score: $%d", bj
->highscores
[0]);
1303 rb
->lcd_puts(0, 10, str
);
1304 #elif CONFIG_KEYPAD == COWOND2_PAD
1305 rb
->lcd_puts(0, 6, "POWER to exit");
1306 rb
->lcd_puts(0, 7, "MINUS to double down");
1307 rb
->lcd_puts(0, 8, "MENU to view scores");
1308 rb
->snprintf(str
, 21, "High Score: $%d", bj
->highscores
[0]);
1309 rb
->lcd_puts(0, 10, str
);
1312 #ifdef HAVE_TOUCHSCREEN
1313 rb
->lcd_puts(0, 2, "LCD CENTRE to start & to hit");
1314 rb
->lcd_puts(0, 3, "LCD BOTTOMLEFT to stay");
1315 rb
->lcd_puts(0, 4, "LCD BOTTOMRIGHT to save/resume");
1318 rb
->snprintf(str
, 12, "%s", "High Scores");
1319 rb
->lcd_getstringsize(str
, &w
, &h
);
1320 rb
->lcd_putsxy((LCD_WIDTH
-w
)/2, 0, str
);
1322 /* print high scores */
1323 for(i
=0; i
<NUM_SCORES
; i
++) {
1324 rb
->snprintf(str
, 14, "#%02d: $%d", i
+1, bj
->highscores
[i
]);
1325 rb
->lcd_puts(0, i
+1, str
);
1331 /* handle menu button presses */
1332 button
= rb
->button_get(true);
1335 case BJACK_START
: /* start playing */
1339 case BJACK_QUIT
: /* quit program */
1346 case BJACK_RESUME
:/* resume game */
1347 if(!blackjack_loadgame(bj
)) {
1348 rb
->splash(HZ
*2, "Nothing to resume");
1350 rb
->splash(HZ
*2, "Loading...");
1355 case BJACK_SCORES
:/* toggle high scores */
1356 showscores
= !showscores
;
1360 if(rb
->default_event_handler_ex(button
, blackjack_callback
,
1361 (void*) bj
) == SYS_USB_CONNECTED
)
1372 /*****************************************************************************
1373 * blackjack() is the main game subroutine, it returns the final game status.
1374 ******************************************************************************/
1375 static int blackjack(struct game_context
* bj
) {
1377 unsigned int w
, h
, temp_var
, done
= 0, todo
= 1;
1379 bool breakout
= false;
1380 bool dbl_down
= false;
1382 /* don't resume by default */
1385 /********************
1387 ********************/
1388 temp_var
= blackjack_menu(bj
);
1389 if (temp_var
== BJ_QUIT
|| temp_var
== BJ_USB
)
1393 /********************
1395 ********************/
1399 /********************
1401 ********************/
1403 /* check for resumed game */
1407 if (bj
->split_status
== 2) {
1409 player_x
= bj
->num_player_cards
[0] * 10 + 4;
1411 else if (bj
->split_status
== 3) {
1412 player_x
= bj
->num_player_cards
[1] * 10 + LCD_WIDTH
/2 + 4;
1419 bj
->player_money
= 1000;
1420 blackjack_get_bet(bj
);
1421 if (bj
->current_bet
== 0)
1423 rb
->lcd_clear_display();
1424 deal_init_cards(bj
);
1425 blackjack_drawtable(bj
);
1433 if(bj
->player_total
== 21 && bj
->num_player_cards
[0] == 2) {
1434 bj
->is_blackjack
= true;
1435 bj
->end_hand
= true;
1438 else if(bj
->dealer_cards
[1].is_soft_ace
&& !breakout
&&
1439 !bj
->asked_insurance
) {
1440 temp_var
= insurance(bj
);
1441 if (bj
->dealer_total
== 21) {
1442 rb
->splash(HZ
, "Dealer has blackjack");
1443 bj
->player_money
+= temp_var
;
1444 bj
->end_hand
= true;
1450 rb
->splash(HZ
, "Dealer does not have blackjack");
1451 bj
->player_money
-= temp_var
;
1457 if(!bj
->end_hand
&& bj
->split_status
== 0 &&
1458 bj
->player_cards
[0][0].num
== bj
->player_cards
[0][1].num
) {
1461 rb
->lcd_update_rect(0, LCD_HEIGHT
/2, LCD_WIDTH
, LCD_HEIGHT
/2);
1462 if (bj
->split_status
== 2) {
1464 player_x
= bj
->num_player_cards
[0] * 10 + 4;
1468 while(!bj
->end_hand
&& done
< todo
) {
1469 button
= rb
->button_get(true);
1473 NEXT_CARD
= new_card();
1474 bj
->player_total
+= NEXT_CARD
.value
;
1475 draw_card(NEXT_CARD
, true, player_x
, player_y
);
1476 bj
->num_player_cards
[done
]++;
1477 if (bj
->num_player_cards
[done
] == MAX_CARDS
+ 1) {
1479 rb
->lcd_update_rect(0, LCD_HEIGHT
/2, LCD_WIDTH
,
1482 else if (bj
->num_player_cards
[done
]>MAX_CARDS
|| todo
> 1) {
1483 rb
->lcd_update_rect(player_x
, player_y
, CARD_WIDTH
+2,
1488 rb
->lcd_update_rect(player_x
, player_y
, CARD_WIDTH
+2,
1490 player_x
+= CARD_WIDTH
+ 4;
1496 bj
->end_hand
= true;
1498 case BJACK_DOUBLEDOWN
:
1499 if ((signed int)bj
->current_bet
* 2 < bj
->player_money
+ 1 &&
1500 bj
->num_player_cards
[0]==2 && todo
==1) {
1503 if (bj
->player_total
< 22) {
1504 bj
->end_hand
= true;
1508 else if((signed int)bj
->current_bet
* 2 > bj
->player_money
) {
1509 rb
->splash(HZ
, "Not enough money to double down.");
1514 case BJACK_RESUME
: /* save and end game */
1515 rb
->splash(HZ
, "Saving game...");
1516 blackjack_savegame(bj
);
1517 /* fall through to BJACK_QUIT */
1523 while (bj
->player_total
> 21 && !bj
->end_hand
) {
1524 temp
= check_for_aces(bj
->player_cards
[done
],
1525 bj
->num_player_cards
[done
]);
1527 bj
->player_cards
[done
][temp
].is_soft_ace
= false;
1528 bj
->player_total
-= 10;
1531 bj
->end_hand
= true;
1536 bj
->end_hand
= true;
1543 temp
= bj
->player_total
;
1544 bj
->player_total
= temp_var
;
1547 rb
->lcd_getstringsize(" Split 1 ", &w
, &h
);
1548 rb
->lcd_putsxy(LCD_WIDTH
/2-w
/2, LCD_HEIGHT
/2-3*h
/2,
1550 rb
->lcd_update_rect(LCD_WIDTH
/2-w
/2, LCD_HEIGHT
/2-3*h
/2,
1552 bj
->current_bet
/= 2;
1553 rb
->lcd_update_rect(LCD_WIDTH
/2-w
/2, LCD_HEIGHT
/2-3*h
/2,
1556 bj
->player_total
= temp_var
;
1558 rb
->lcd_getstringsize(" Split 2 ", &w
, &h
);
1559 rb
->lcd_putsxy(LCD_WIDTH
/2-w
/2, LCD_HEIGHT
/2-3*h
/2,
1561 rb
->lcd_update_rect(LCD_WIDTH
/2-w
/2, LCD_HEIGHT
/2-3*h
/2,
1566 bj
->end_hand
= false;
1567 bj
->split_status
= 3;
1568 temp_var
= bj
->player_total
;
1569 bj
->player_total
= bj
->player_cards
[1][0].value
;
1581 if (bj
->player_money
< 10) {
1586 if (bj
->end_hand
) { /* If hand is over */
1587 if (play_again() != 0) /* User wants to quit */
1589 else { /* User keeps playing */
1593 bj
->current_bet
/= 2;
1599 blackjack_get_bet(bj
);
1600 if (bj
->current_bet
== 0)
1602 deal_init_cards(bj
);
1603 blackjack_drawtable(bj
);
1612 /*****************************************************************************
1613 * plugin entry point.
1614 ******************************************************************************/
1615 enum plugin_status
plugin_start(const void* parameter
)
1617 struct game_context bj
;
1619 unsigned int position
;
1625 rb
->lcd_set_backdrop(NULL
);
1628 /* load high scores */
1629 blackjack_loadscores(&bj
);
1631 rb
->lcd_setfont(FONT_SYSFIXED
);
1634 switch(blackjack(&bj
)){
1636 rb
->splash(HZ
, "Not enough money to continue");
1637 /* fall through to BJ_END */
1641 if((position
= blackjack_recordscore(&bj
))) {
1642 rb
->snprintf(str
, 19, "New high score #%d!", position
);
1643 rb
->splash(HZ
*2, str
);
1649 rb
->lcd_setfont(FONT_UI
);
1650 return PLUGIN_USB_CONNECTED
;
1654 rb
->splash(HZ
, "Saving high scores...");
1655 blackjack_savescores(&bj
);
1665 rb
->lcd_setfont(FONT_UI
);