1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2006 Tom Ross
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
21 #include "card_deck.h"
22 #include "card_back.h"
27 #define SCORE_FILE PLUGIN_GAMES_DIR "/blackjack.score"
28 #define SAVE_FILE PLUGIN_GAMES_DIR "/blackjack.save"
30 #define NUM_SCORES LCD_HEIGHT/8-2
32 /* final game return status */
38 #if CONFIG_KEYPAD == RECORDER_PAD
39 #define BJACK_START BUTTON_ON
40 #define BJACK_QUIT BUTTON_OFF
41 #define BJACK_MAX (BUTTON_ON|BUTTON_UP)
42 #define BJACK_MIN (BUTTON_ON|BUTTON_DOWN)
43 #define BJACK_HIT BUTTON_F1
44 #define BJACK_STAY BUTTON_F2
45 #define BJACK_DOUBLEDOWN BUTTON_F3
46 #define BJACK_SCORES BUTTON_RIGHT
47 #define BJACK_RESUME BUTTON_PLAY
48 #define BJACK_UP BUTTON_UP
49 #define BJACK_DOWN BUTTON_DOWN
50 #define BJACK_RIGHT BUTTON_RIGHT
51 #define BJACK_LEFT BUTTON_LEFT
53 #elif CONFIG_KEYPAD == ONDIO_PAD
54 #define BJACK_START BUTTON_MENU
55 #define BJACK_QUIT BUTTON_OFF
56 #define BJACK_MAX (BUTTON_MENU|BUTTON_UP)
57 #define BJACK_MIN (BUTTON_MENU|BUTTON_DOWN)
58 #define BJACK_HIT BUTTON_LEFT
59 #define BJACK_STAY BUTTON_RIGHT
60 #define BJACK_DOUBLEDOWN BUTTON_UP
61 #define BJACK_SCORES BUTTON_UP
62 #define BJACK_RESUME BUTTON_DOWN
63 #define BJACK_UP BUTTON_UP
64 #define BJACK_DOWN BUTTON_DOWN
65 #define BJACK_RIGHT BUTTON_RIGHT
66 #define BJACK_LEFT BUTTON_LEFT
68 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
69 #define BJACK_START BUTTON_PLAY
70 #define BJACK_QUIT BUTTON_POWER
71 #define BJACK_MAX (BUTTON_PLAY|BUTTON_SCROLL_UP)
72 #define BJACK_MIN (BUTTON_PLAY|BUTTON_SCROLL_DOWN)
73 #define BJACK_HIT BUTTON_PLAY
74 #define BJACK_STAY BUTTON_FF
75 #define BJACK_DOUBLEDOWN BUTTON_REW
76 #define BJACK_SCORES BUTTON_LEFT
77 #define BJACK_RESUME BUTTON_RIGHT
78 #define BJACK_UP BUTTON_SCROLL_UP
79 #define BJACK_DOWN BUTTON_SCROLL_DOWN
80 #define BJACK_RIGHT BUTTON_RIGHT
81 #define BJACK_LEFT BUTTON_LEFT
83 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
84 (CONFIG_KEYPAD == IRIVER_H300_PAD)
85 #define BJACK_START BUTTON_ON
86 #define BJACK_QUIT BUTTON_OFF
87 #define BJACK_MAX (BUTTON_ON|BUTTON_UP)
88 #define BJACK_MIN (BUTTON_ON|BUTTON_DOWN)
89 #define BJACK_HIT BUTTON_ON
90 #define BJACK_STAY BUTTON_REC
91 #define BJACK_DOUBLEDOWN BUTTON_SELECT
92 #define BJACK_SCORES BUTTON_SELECT
93 #define BJACK_RESUME BUTTON_MODE
94 #define BJACK_UP BUTTON_UP
95 #define BJACK_DOWN BUTTON_DOWN
96 #define BJACK_RIGHT BUTTON_RIGHT
97 #define BJACK_LEFT BUTTON_LEFT
99 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \
100 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
101 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
102 #define BJACK_START BUTTON_SELECT
103 #define BJACK_QUIT BUTTON_MENU
104 #define BJACK_MAX (BUTTON_SELECT|BUTTON_SCROLL_FWD)
105 #define BJACK_MIN (BUTTON_SELECT|BUTTON_SCROLL_BACK)
106 #define BJACK_HIT BUTTON_SELECT
107 #define BJACK_STAY BUTTON_RIGHT
108 #define BJACK_DOUBLEDOWN BUTTON_LEFT
109 #define BJACK_SCORES BUTTON_RIGHT
110 #define BJACK_RESUME BUTTON_PLAY
111 #define BJACK_UP BUTTON_SCROLL_FWD
112 #define BJACK_DOWN BUTTON_SCROLL_BACK
113 #define BJACK_RIGHT BUTTON_RIGHT
114 #define BJACK_LEFT BUTTON_LEFT
116 #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD
117 #define BJACK_START BUTTON_PLAY
118 #define BJACK_QUIT BUTTON_POWER
119 #define BJACK_MAX (BUTTON_PLAY|BUTTON_UP)
120 #define BJACK_MIN (BUTTON_PLAY|BUTTON_DOWN)
121 #define BJACK_HIT BUTTON_SELECT
122 #define BJACK_STAY BUTTON_REC
123 #define BJACK_DOUBLEDOWN BUTTON_PLAY
124 #define BJACK_SCORES BUTTON_RIGHT
125 #define BJACK_RESUME BUTTON_DOWN
126 #define BJACK_UP BUTTON_UP
127 #define BJACK_DOWN BUTTON_DOWN
128 #define BJACK_RIGHT BUTTON_RIGHT
129 #define BJACK_LEFT BUTTON_LEFT
131 #elif CONFIG_KEYPAD == IRIVER_IFP7XX_PAD
132 #define BJACK_START BUTTON_MODE
133 #define BJACK_QUIT BUTTON_PLAY
134 #define BJACK_MAX (BUTTON_EQ|BUTTON_UP)
135 #define BJACK_MIN (BUTTON_EQ|BUTTON_DOWN)
136 #define BJACK_HIT BUTTON_EQ
137 #define BJACK_STAY BUTTON_MODE
138 #define BJACK_DOUBLEDOWN BUTTON_SELECT
139 #define BJACK_SCORES BUTTON_SELECT
140 #define BJACK_RESUME (BUTTON_EQ|BUTTON_MODE)
141 #define BJACK_UP BUTTON_UP
142 #define BJACK_DOWN BUTTON_DOWN
143 #define BJACK_RIGHT BUTTON_RIGHT
144 #define BJACK_LEFT BUTTON_LEFT
146 #elif CONFIG_KEYPAD == GIGABEAT_PAD
147 #define BJACK_START BUTTON_POWER
148 #define BJACK_QUIT BUTTON_A
149 #define BJACK_MAX BUTTON_VOL_UP
150 #define BJACK_MIN BUTTON_VOL_DOWN
151 #define BJACK_HIT BUTTON_VOL_UP
152 #define BJACK_STAY BUTTON_VOL_DOWN
153 #define BJACK_DOUBLEDOWN BUTTON_SELECT
154 #define BJACK_SCORES BUTTON_RIGHT
155 #define BJACK_RESUME BUTTON_MENU
156 #define BJACK_UP BUTTON_UP
157 #define BJACK_DOWN BUTTON_DOWN
158 #define BJACK_RIGHT BUTTON_RIGHT
159 #define BJACK_LEFT BUTTON_LEFT
161 #elif CONFIG_KEYPAD == SANSA_E200_PAD
162 #define BJACK_START BUTTON_SELECT
163 #define BJACK_QUIT BUTTON_POWER
164 #define BJACK_MAX (BUTTON_REC|BUTTON_UP)
165 #define BJACK_MIN (BUTTON_REC|BUTTON_DOWN)
166 #define BJACK_HIT BUTTON_SELECT
167 #define BJACK_STAY BUTTON_RIGHT
168 #define BJACK_DOUBLEDOWN BUTTON_LEFT
169 #define BJACK_SCORES BUTTON_UP
170 #define BJACK_RESUME BUTTON_REC
171 #define BJACK_UP BUTTON_SCROLL_FWD
172 #define BJACK_DOWN BUTTON_SCROLL_BACK
173 #define BJACK_RIGHT BUTTON_RIGHT
174 #define BJACK_LEFT BUTTON_LEFT
176 #elif CONFIG_KEYPAD == SANSA_C200_PAD
177 #define BJACK_START BUTTON_SELECT
178 #define BJACK_QUIT BUTTON_POWER
179 #define BJACK_MAX BUTTON_VOL_UP
180 #define BJACK_MIN BUTTON_VOL_DOWN
181 #define BJACK_HIT BUTTON_SELECT
182 #define BJACK_STAY BUTTON_RIGHT
183 #define BJACK_DOUBLEDOWN BUTTON_LEFT
184 #define BJACK_SCORES BUTTON_REC
185 #define BJACK_RESUME BUTTON_DOWN
186 #define BJACK_UP BUTTON_UP
187 #define BJACK_DOWN BUTTON_DOWN
188 #define BJACK_RIGHT BUTTON_RIGHT
189 #define BJACK_LEFT BUTTON_LEFT
191 #elif CONFIG_KEYPAD == ELIO_TPJ1022_PAD
192 #define BJACK_START BUTTON_MAIN
193 #define BJACK_QUIT BUTTON_POWER
194 #define BJACK_MAX (BUTTON_REC|BUTTON_UP)
195 #define BJACK_MIN (BUTTON_REC|BUTTON_DOWN)
196 #define BJACK_HIT BUTTON_MAIN
197 #define BJACK_STAY BUTTON_MENU
198 #define BJACK_DOUBLEDOWN BUTTON_DOWN
199 #define BJACK_SCORES BUTTON_UP
200 #define BJACK_RESUME BUTTON_FF
201 #define BJACK_UP BUTTON_UP
202 #define BJACK_DOWN BUTTON_DOWN
203 #define BJACK_RIGHT BUTTON_RIGHT
204 #define BJACK_LEFT BUTTON_LEFT
206 #elif CONFIG_KEYPAD == GIGABEAT_S_PAD
207 #define BJACK_START BUTTON_PLAY
208 #define BJACK_QUIT BUTTON_BACK
209 #define BJACK_MAX BUTTON_VOL_UP
210 #define BJACK_MIN BUTTON_VOL_DOWN
211 #define BJACK_HIT BUTTON_VOL_UP
212 #define BJACK_STAY BUTTON_VOL_DOWN
213 #define BJACK_DOUBLEDOWN BUTTON_SELECT
214 #define BJACK_SCORES BUTTON_RIGHT
215 #define BJACK_RESUME BUTTON_MENU
216 #define BJACK_UP BUTTON_UP
217 #define BJACK_DOWN BUTTON_DOWN
218 #define BJACK_RIGHT BUTTON_RIGHT
219 #define BJACK_LEFT BUTTON_LEFT
221 #elif CONFIG_KEYPAD == MROBE100_PAD
223 #define BJACK_START BUTTON_SELECT
224 #define BJACK_QUIT BUTTON_POWER
225 #define BJACK_MAX BUTTON_MENU
226 #define BJACK_MIN BUTTON_DISPLAY
227 #define BJACK_HIT BUTTON_MENU
228 #define BJACK_STAY BUTTON_DISPLAY
229 #define BJACK_DOUBLEDOWN BUTTON_SELECT
230 #define BJACK_SCORES BUTTON_RIGHT
231 #define BJACK_RESUME BUTTON_PLAY
232 #define BJACK_UP BUTTON_UP
233 #define BJACK_DOWN BUTTON_DOWN
234 #define BJACK_RIGHT BUTTON_RIGHT
235 #define BJACK_LEFT BUTTON_LEFT
237 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
239 #define BJACK_START BUTTON_RC_PLAY
240 #define BJACK_QUIT BUTTON_RC_REC
241 #define BJACK_MAX (BUTTON_RC_PLAY|BUTTON_RC_VOL_UP)
242 #define BJACK_MIN (BUTTON_RC_PLAY|BUTTON_RC_VOL_DOWN)
243 #define BJACK_HIT BUTTON_RC_PLAY
244 #define BJACK_STAY BUTTON_RC_FF
245 #define BJACK_DOUBLEDOWN BUTTON_RC_REW
246 #define BJACK_SCORES BUTTON_RC_MENU
247 #define BJACK_RESUME BUTTON_RC_MODE
248 #define BJACK_UP BUTTON_RC_VOL_UP
249 #define BJACK_DOWN BUTTON_RC_VOL_DOWN
250 #define BJACK_RIGHT BUTTON_RC_FF
251 #define BJACK_LEFT BUTTON_RC_REW
253 #elif CONFIG_KEYPAD == COWOND2_PAD
254 #define BJACK_START BUTTON_SELECT
255 #define BJACK_QUIT BUTTON_POWER
256 #define BJACK_MAX BUTTON_PLUS
257 #define BJACK_MIN BUTTON_MINUS
258 #define BJACK_HIT BUTTON_SELECT
259 #define BJACK_STAY BUTTON_MENU
260 #define BJACK_DOUBLEDOWN (BUTTON_DOWN|BUTTON_MENU)
261 #define BJACK_SCORES (BUTTON_SELECT|BUTTON_MENU)
262 #define BJACK_RESUME (BUTTON_SELECT|BUTTON_PLUS)
263 #define BJACK_UP BUTTON_UP
264 #define BJACK_DOWN BUTTON_DOWN
265 #define BJACK_RIGHT BUTTON_RIGHT
266 #define BJACK_LEFT BUTTON_LEFT
269 #error No keymap defined!
272 #ifdef HAVE_LCD_COLOR
273 #define BG_COLOR LCD_RGBPACK(0,157,0)
274 #define FG_COLOR LCD_WHITE
276 #define BG_COLOR LCD_WHITE
277 #define FG_COLOR LCD_BLACK
280 #define CARD_WIDTH BMPWIDTH_card_back
281 #define CARD_HEIGHT BMPHEIGHT_card_back
283 /* This is the max amount of cards onscreen before condensing */
284 #define MAX_CARDS LCD_WIDTH/(CARD_WIDTH+4)
286 extern const fb_data card_deck
[];
287 extern const fb_data card_back
[];
289 #define NEXT_CARD bj->player_cards[done][bj->num_player_cards[done]]
291 /* global rockbox api */
292 static struct plugin_api
* rb
;
294 MEM_FUNCTION_WRAPPERS(rb
);
296 /* dealer and player card positions */
297 unsigned int dealer_x
, dealer_y
, player_x
, player_y
;
299 typedef struct card
{
300 unsigned int value
; /* Card's value in Blackjack */
301 unsigned int num
; /* Value on card face 0-12 (0=Ace, 1=2, 11=Q) */
302 unsigned int suit
; /* 0:Spades, 1:Hearts, 2: Clubs; 3: Diamonds */
306 typedef struct game_context
{
307 struct card player_cards
[2][22]; /* 22 Cards means the deal was all aces */
308 struct card dealer_cards
[22]; /* That is the worst-case scenario */
309 unsigned int player_total
;
310 unsigned int dealer_total
;
311 signed int player_money
;
312 unsigned int num_player_cards
[2];
313 unsigned int num_dealer_cards
;
314 unsigned int current_bet
;
315 unsigned int split_status
; /* 0 = split hasn't been asked, *
316 * 1 = split did not occur *
317 * 2 = split occurred *
318 * 3 = split occurred and 1st hand done */
321 bool asked_insurance
;
322 signed short highscores
[NUM_SCORES
];
327 /*****************************************************************************
328 * blackjack_init() initializes blackjack data structures.
329 ******************************************************************************/
330 static void blackjack_init(struct game_context
* bj
) {
331 /* seed the rand generator */
332 rb
->srand(*rb
->current_tick
);
334 /* reset card positions */
336 dealer_y
= LCD_HEIGHT
/4 - CARD_HEIGHT
/2;
338 player_y
= LCD_HEIGHT
- LCD_HEIGHT
/4 - CARD_HEIGHT
/2;
340 /* check for resumed game */
341 if(bj
->resume
) return;
344 bj
->player_total
= 0;
345 bj
->dealer_total
= 0;
346 bj
->num_player_cards
[0] = 2;
347 bj
->num_player_cards
[1] = 0;
348 bj
->num_dealer_cards
= 2;
349 bj
->end_hand
= false;
350 bj
->split_status
= 0;
351 bj
->is_blackjack
= false;
352 bj
->asked_insurance
= false;
355 /*****************************************************************************
356 * blackjack_drawtable() draws the table and some text.
357 ******************************************************************************/
358 static void blackjack_drawtable(struct game_context
* bj
) {
359 unsigned int w
, h
, y_loc
;
363 rb
->lcd_getstringsize("Bet", &w
, &h
);
364 rb
->lcd_putsxy(LCD_WIDTH
- w
, 2*h
+ 1, "Bet");
365 rb
->snprintf(str
, 9, "$%d", bj
->current_bet
);
366 rb
->lcd_getstringsize(str
, &w
, &h
);
367 rb
->lcd_putsxy(LCD_WIDTH
- w
, 3*h
+ 1, str
);
368 y_loc
= LCD_HEIGHT
/2;
370 rb
->lcd_getstringsize("Bet", &w
, &h
);
371 rb
->lcd_putsxy(LCD_WIDTH
- w
, 5*h
/ 2, "Bet");
372 rb
->snprintf(str
, 9, "$%d", bj
->current_bet
);
373 rb
->lcd_getstringsize(str
, &w
, &h
);
374 rb
->lcd_putsxy(LCD_WIDTH
- w
, 7*h
/ 2, str
);
375 rb
->lcd_hline(0, LCD_WIDTH
, LCD_HEIGHT
/2);
376 y_loc
= LCD_HEIGHT
/2 + h
;
379 rb
->lcd_putsxy(0,0, "Dealer");
380 rb
->lcd_getstringsize("Player", &w
, &h
);
381 rb
->lcd_putsxy(0, y_loc
, "Player");
382 rb
->lcd_getstringsize("Total", &w
, &h
);
383 rb
->lcd_putsxy(LCD_WIDTH
- w
, y_loc
, "Total");
384 rb
->lcd_getstringsize("Money", &w
, &h
);
385 rb
->lcd_putsxy(LCD_WIDTH
- w
, 0, "Money");
386 rb
->snprintf(str
, 9, "$%d", bj
->player_money
- bj
->current_bet
);
387 rb
->lcd_getstringsize(str
, &w
, &h
);
388 rb
->lcd_putsxy(LCD_WIDTH
- w
, h
+ 1, str
);
389 rb
->snprintf(str
, 3, "%d", bj
->player_total
);
390 rb
->lcd_getstringsize(str
, &w
, &h
);
391 rb
->lcd_putsxy(LCD_WIDTH
- w
, y_loc
+ h
, str
);
394 /*****************************************************************************
395 * find_value() is passed a card and returns its blackjack value.
396 ******************************************************************************/
397 static unsigned int find_value(unsigned int number
) {
398 unsigned int thisValue
;
400 thisValue
= 11; /* Aces get a value of 11 at first */
401 else if (number
< 10)
402 thisValue
= number
+ 1;
404 thisValue
= 10; /* Anything 10 or higher gets a value of 10 */
409 /*****************************************************************************
410 * draw_card() draws a card to the screen.
411 ******************************************************************************/
412 static void draw_card(struct card temp_card
, bool shown
, unsigned int x
,
415 rb
->lcd_bitmap_part(card_deck
, CARD_WIDTH
*temp_card
.num
,
416 CARD_HEIGHT
*temp_card
.suit
, BMPWIDTH_card_deck
,
417 x
+1, y
+1, CARD_WIDTH
, CARD_HEIGHT
);
419 rb
->lcd_bitmap(card_back
, x
+1, y
+1,CARD_WIDTH
, CARD_HEIGHT
);
421 rb
->lcd_set_foreground(LCD_BLACK
);
426 rb
->lcd_hline(x
+2, x
+CARD_WIDTH
-1, y
);
427 rb
->lcd_hline(x
+2, x
+CARD_WIDTH
-1, y
+CARD_HEIGHT
+1);
428 rb
->lcd_vline(x
, y
+2, y
+CARD_HEIGHT
-3);
429 rb
->lcd_vline(x
+CARD_WIDTH
+1, y
+2, y
+CARD_HEIGHT
-1);
430 rb
->lcd_drawpixel(x
+1, y
+1);
431 rb
->lcd_drawpixel(x
+1, y
+CARD_HEIGHT
);
432 rb
->lcd_drawpixel(x
+CARD_WIDTH
, y
+1);
433 rb
->lcd_drawpixel(x
+CARD_WIDTH
, y
+CARD_HEIGHT
);
435 rb
->lcd_hline(x
+1, x
+CARD_WIDTH
, y
);
436 rb
->lcd_hline(x
+1, x
+CARD_WIDTH
, y
+CARD_HEIGHT
+1);
437 rb
->lcd_vline(x
, y
+1, y
+CARD_HEIGHT
);
438 rb
->lcd_vline(x
+CARD_WIDTH
+1, y
+1, y
+CARD_HEIGHT
);
442 rb
->lcd_set_foreground(FG_COLOR
);
446 /*****************************************************************************
447 * new_card() initializes a new card and gives it values.
448 ******************************************************************************/
449 static struct card
new_card(void) {
450 struct card new_card
;
451 new_card
.suit
= rb
->rand()%4; /* Random number 0-3 */
452 new_card
.num
= rb
->rand()%13; /* Random number 0-12 */
453 new_card
.value
= find_value(new_card
.num
);
454 new_card
.is_soft_ace
= new_card
.num
== 0 ? true : false;
458 /*****************************************************************************
459 * deal_init_card() deals and draws to the screen the player's and dealer's
461 ******************************************************************************/
462 static void deal_init_cards(struct game_context
* bj
) {
463 bj
->dealer_cards
[0] = new_card();
464 bj
->dealer_total
+= bj
->dealer_cards
[0].value
;
466 draw_card(bj
->dealer_cards
[0], false, dealer_x
, dealer_y
);
468 bj
->dealer_cards
[1] = new_card();
469 bj
->dealer_total
+= bj
->dealer_cards
[1].value
;
470 draw_card(bj
->dealer_cards
[1], true, dealer_x
+ CARD_WIDTH
+ 4, dealer_y
);
472 bj
->player_cards
[0][0] = new_card();
473 bj
->player_total
+= bj
->player_cards
[0][0].value
;
474 draw_card(bj
->player_cards
[0][0], true, player_x
, player_y
);
475 player_x
+= CARD_WIDTH
+ 4;
477 bj
->player_cards
[0][1] = new_card();
478 bj
->player_total
+= bj
->player_cards
[0][1].value
;
479 draw_card(bj
->player_cards
[0][1], true, player_x
, player_y
);
480 player_x
+= CARD_WIDTH
+ 4;
483 /*****************************************************************************
484 * redraw_board() redraws all the cards and the board
485 ******************************************************************************/
486 static void redraw_board(struct game_context
* bj
) {
487 unsigned int i
, n
, upper_bound
;
488 rb
->lcd_clear_display();
490 blackjack_drawtable(bj
);
493 upper_bound
= bj
->split_status
> 1 ? 2 : 1;
495 for (i
= 0; i
< bj
->num_dealer_cards
; i
++) {
497 draw_card(bj
->dealer_cards
[0], false, dealer_x
, dealer_y
);
499 /* increment i so the dealer's first card isn't displayed */
501 dealer_x
+= CARD_WIDTH
+ 4;
503 draw_card(bj
->dealer_cards
[i
], true, dealer_x
, dealer_y
);
505 if (bj
->num_dealer_cards
> MAX_CARDS
-1)
508 dealer_x
+= CARD_WIDTH
+ 4;
511 for (n
= 0; n
< upper_bound
; n
++) {
512 for (i
= 0; i
< bj
->num_player_cards
[n
]; i
++) {
513 draw_card(bj
->player_cards
[n
][i
], true, player_x
, player_y
);
514 if (bj
->split_status
>1 || bj
->num_player_cards
[n
]>MAX_CARDS
)
517 player_x
+= CARD_WIDTH
+ 4;
519 if (bj
->split_status
> 1)
520 player_x
= LCD_WIDTH
/2 + 4;
524 /*****************************************************************************
525 * update_total updates the player's total
526 ******************************************************************************/
527 static void update_total(struct game_context
* bj
) {
530 rb
->snprintf(total
, 3, "%d", bj
->player_total
);
531 rb
->lcd_getstringsize(total
, &w
, &h
);
535 rb
->lcd_putsxy(LCD_WIDTH
- w
, LCD_HEIGHT
/2 + h
, total
);
536 rb
->lcd_update_rect(LCD_WIDTH
- w
, LCD_HEIGHT
/2 + h
, w
, h
);
540 /*****************************************************************************
541 * check_for_aces() is passed an array of cards and returns where an ace is
542 * located. Otherwise, returns -1.
543 ******************************************************************************/
544 static signed int check_for_aces(struct card temp_cards
[],
547 for(i
= 0; i
< size
; i
++) {
548 if (temp_cards
[i
].is_soft_ace
== true)
554 /*****************************************************************************
555 * check_totals() compares player and dealer totals.
556 * 0: bust 1: loss, 2: push, 3: win, 4: blackjack, 5: something's not right...
557 ******************************************************************************/
558 static unsigned int check_totals(struct game_context
* bj
)
561 if (bj
->player_total
> 21)
563 else if (bj
->player_total
== 21 && bj
->is_blackjack
)
564 if (bj
->dealer_total
== 21 && bj
->num_dealer_cards
== 2)
568 else if (bj
->player_total
== bj
->dealer_total
)
570 else if (bj
->dealer_total
> 21 && bj
->player_total
< 22)
572 else if (bj
->dealer_total
> bj
->player_total
)
574 else if (bj
->player_total
> bj
->dealer_total
)
582 /*****************************************************************************
583 * finish_dealer() draws cards for the dealer until he has 17 or more.
584 ******************************************************************************/
585 static void finish_dealer(struct game_context
* bj
) {
588 if (bj
->dealer_total
> 16 && bj
->dealer_total
< 22)
591 while (bj
->dealer_total
< 17) {
592 bj
->dealer_cards
[bj
->num_dealer_cards
] = new_card();
593 bj
->dealer_total
+= bj
->dealer_cards
[bj
->num_dealer_cards
].value
;
594 bj
->num_dealer_cards
++;
597 while (bj
->dealer_total
> 21) {
598 temp
= check_for_aces(bj
->dealer_cards
, bj
->num_dealer_cards
);
600 bj
->dealer_cards
[temp
].is_soft_ace
= false;
601 bj
->dealer_total
-= 10;
608 /*****************************************************************************
609 * finish_game() completes the game once player's turn is over.
610 ******************************************************************************/
611 static void finish_game(struct game_context
* bj
) {
612 unsigned int rValue
, w
, h
;
617 } while (bj
->dealer_total
< 17);
620 rValue
= check_totals(bj
);
623 rb
->snprintf(str
, sizeof(str
), " Bust! ");
624 bj
->player_money
-= bj
->current_bet
;
626 else if (rValue
== 1) {
627 rb
->snprintf(str
, sizeof(str
), " Sorry, you lost. ");
628 bj
->player_money
-= bj
->current_bet
;
630 else if (rValue
== 2) {
631 rb
->snprintf(str
, sizeof(str
), " Push ");
633 else if (rValue
== 3) {
634 rb
->snprintf(str
, sizeof(str
), " You won! ");
635 bj
->player_money
+= bj
->current_bet
;
638 rb
->snprintf(str
, sizeof(str
), " Blackjack! ");
639 bj
->player_money
+= bj
->current_bet
* 3 / 2;
641 rb
->lcd_getstringsize(str
, &w
, &h
);
644 rb
->lcd_set_drawmode(DRMODE_BG
+DRMODE_INVERSEVID
);
645 rb
->lcd_fillrect(0, LCD_HEIGHT
/2, LCD_WIDTH
, LCD_HEIGHT
/2);
646 rb
->lcd_set_drawmode(DRMODE_SOLID
);
647 rb
->lcd_putsxy(LCD_WIDTH
/2 - w
/2, LCD_HEIGHT
/2 + h
, str
);
648 rb
->snprintf(str
, 12, "You have %d", bj
->player_total
);
649 rb
->lcd_getstringsize(str
, &w
, &h
);
650 rb
->lcd_putsxy(LCD_WIDTH
/2 - w
/2, LCD_HEIGHT
/2, str
);
652 rb
->lcd_putsxy(LCD_WIDTH
/2 - w
/2, LCD_HEIGHT
/2 - h
/2, str
);
657 /*****************************************************************************
658 * blackjack_recordscore() inserts a high score into the high scores list and
659 * returns the high score position.
660 ******************************************************************************/
661 static unsigned int blackjack_recordscore(struct game_context
* bj
) {
663 unsigned int position
= 0;
664 signed short current
, temp
;
666 /* calculate total score */
667 current
= bj
->player_money
;
668 if(current
<= 10) return 0;
670 /* insert the current score into the high scores */
671 for(i
=0; i
<NUM_SCORES
; i
++) {
672 if(current
>= bj
->highscores
[i
]) {
677 temp
= bj
->highscores
[i
];
678 bj
->highscores
[i
] = current
;
686 /*****************************************************************************
687 * blackjack_loadscores() loads the high scores saved file.
688 ******************************************************************************/
689 static void blackjack_loadscores(struct game_context
* bj
) {
694 /* clear high scores */
695 rb
->memset(bj
->highscores
, 0, sizeof(bj
->highscores
));
697 /* open scores file */
698 fd
= rb
->open(SCORE_FILE
, O_RDONLY
);
701 /* read in high scores */
702 if(rb
->read(fd
, bj
->highscores
, sizeof(bj
->highscores
)) <= 0) {
703 /* scores are bad, reset */
704 rb
->memset(bj
->highscores
, 0, sizeof(bj
->highscores
));
710 /*****************************************************************************
711 * blackjack_savescores() saves the high scores saved file.
712 ******************************************************************************/
713 static void blackjack_savescores(struct game_context
* bj
) {
716 /* write out the high scores to the save file */
717 fd
= rb
->open(SCORE_FILE
, O_WRONLY
|O_CREAT
);
718 rb
->write(fd
, bj
->highscores
, sizeof(bj
->highscores
));
723 /*****************************************************************************
724 * blackjack_loadgame() loads the saved game and returns load success.
725 ******************************************************************************/
726 static bool blackjack_loadgame(struct game_context
* bj
) {
731 fd
= rb
->open(SAVE_FILE
, O_RDONLY
);
732 if(fd
< 0) return loaded
;
734 /* read in saved game */
736 if(rb
->read(fd
, &bj
->player_money
, sizeof(bj
->player_money
)) <= 0) break;
737 if(rb
->read(fd
, &bj
->player_total
, sizeof(bj
->player_total
)) <= 0) break;
738 if(rb
->read(fd
, &bj
->dealer_total
, sizeof(bj
->dealer_total
)) <= 0) break;
739 if(rb
->read(fd
, &bj
->num_player_cards
, sizeof(bj
->num_player_cards
))<=0)
741 if(rb
->read(fd
, &bj
->num_dealer_cards
, sizeof(bj
->num_dealer_cards
))<=0)
743 if(rb
->read(fd
, &bj
->current_bet
, sizeof(bj
->current_bet
)) <= 0) break;
744 if(rb
->read(fd
, &bj
->is_blackjack
, sizeof(bj
->is_blackjack
)) <= 0) break;
745 if(rb
->read(fd
, &bj
->split_status
, sizeof(bj
->split_status
)) <= 0) break;
746 if(rb
->read(fd
, &bj
->asked_insurance
, sizeof(bj
->asked_insurance
)) <= 0)
748 if(rb
->read(fd
, &bj
->end_hand
, sizeof(bj
->end_hand
)) <= 0) break;
749 if(rb
->read(fd
, &bj
->player_cards
, sizeof(bj
->player_cards
)) <= 0) break;
750 if(rb
->read(fd
, &bj
->dealer_cards
, sizeof(bj
->dealer_cards
)) <= 0) break;
758 /* delete saved file */
759 rb
->remove(SAVE_FILE
);
763 /*****************************************************************************
764 * blackjack_savegame() saves the current game state.
765 ******************************************************************************/
766 static void blackjack_savegame(struct game_context
* bj
) {
769 /* write out the game state to the save file */
770 fd
= rb
->open(SAVE_FILE
, O_WRONLY
|O_CREAT
);
771 rb
->write(fd
, &bj
->player_money
, sizeof(bj
->player_money
));
772 rb
->write(fd
, &bj
->player_total
, sizeof(bj
->player_total
));
773 rb
->write(fd
, &bj
->dealer_total
, sizeof(bj
->dealer_total
));
774 rb
->write(fd
, &bj
->num_player_cards
, sizeof(bj
->num_player_cards
));
775 rb
->write(fd
, &bj
->num_dealer_cards
, sizeof(bj
->num_dealer_cards
));
776 rb
->write(fd
, &bj
->current_bet
, sizeof(bj
->current_bet
));
777 rb
->write(fd
, &bj
->is_blackjack
, sizeof(bj
->is_blackjack
));
778 rb
->write(fd
, &bj
->split_status
, sizeof(bj
->split_status
));
779 rb
->write(fd
, &bj
->asked_insurance
, sizeof(bj
->asked_insurance
));
780 rb
->write(fd
, &bj
->end_hand
, sizeof(bj
->end_hand
));
781 rb
->write(fd
, &bj
->player_cards
, sizeof(bj
->player_cards
));
782 rb
->write(fd
, &bj
->dealer_cards
, sizeof(bj
->dealer_cards
));
788 /*****************************************************************************
789 * blackjack_callback() is the default event handler callback which is called
790 * on usb connect and shutdown.
791 ******************************************************************************/
792 static void blackjack_callback(void* param
) {
793 struct game_context
* bj
= (struct game_context
*) param
;
795 rb
->splash(HZ
, "Saving high scores...");
796 blackjack_savescores(bj
);
800 /*****************************************************************************
801 * blackjack_get_yes_no() gets a yes/no answer from the user
802 ******************************************************************************/
803 static unsigned int blackjack_get_yes_no(char message
[20]) {
805 unsigned int w
, h
, b
, choice
= 0;
806 bool breakout
= false;
807 char message_yes
[24], message_no
[24];
809 rb
->strcpy(message_yes
, message
);
810 rb
->strcpy(message_no
, message
);
811 rb
->strcat(message_yes
, " Yes");
812 rb
->strcat(message_no
, " No");
813 rb
->lcd_getstringsize(message_yes
, &w
, &h
);
814 const char *stg
[] = {message_yes
, message_no
};
822 #ifdef HAVE_LCD_COLOR
823 rb
->lcd_fillrect(LCD_WIDTH
/2 - w
/2, LCD_HEIGHT
/2 + b
, w
+1, h
+3);
824 rb
->lcd_set_foreground(LCD_BLACK
);
825 rb
->lcd_set_background(LCD_WHITE
);
827 rb
->lcd_set_drawmode(DRMODE_BG
+DRMODE_INVERSEVID
);
828 rb
->lcd_fillrect(LCD_WIDTH
/2 - w
/2, LCD_HEIGHT
/2 + b
, w
+1, h
+3);
829 rb
->lcd_set_drawmode(DRMODE_SOLID
);
831 rb
->lcd_drawrect(LCD_WIDTH
/2 - w
/2 - 1, LCD_HEIGHT
/2 + b
- 1, w
+3, h
+4);
834 rb
->lcd_putsxy(LCD_WIDTH
/2 - w
/2, LCD_HEIGHT
/2 + b
+1, stg
[choice
]);
835 rb
->lcd_update_rect(LCD_WIDTH
/2 - w
/2 - 1, LCD_HEIGHT
/2 + b
-1,
837 button
= rb
->button_get(true);
841 case (BJACK_LEFT
|BUTTON_REPEAT
):
843 case (BJACK_RIGHT
|BUTTON_REPEAT
):
846 case BJACK_START
: breakout
= true;
848 case BJACK_QUIT
: breakout
= true;
855 rb
->lcd_set_foreground(FG_COLOR
);
856 rb
->lcd_set_background(BG_COLOR
);
861 /*****************************************************************************
862 * blackjack_get_amount() gets an amount from the player to be used
863 ******************************************************************************/
864 static signed int blackjack_get_amount(char message
[20], signed int lower_limit
,
865 signed int upper_limit
,
869 bool changed
= false;
873 rb
->lcd_getstringsize("A", &w
, &h
); /* find the size of one character */
875 if (start
> upper_limit
)
876 amount
= upper_limit
;
877 else if (start
< lower_limit
)
878 amount
= lower_limit
;
883 rb
->lcd_set_background(LCD_WHITE
);
884 rb
->lcd_set_foreground(LCD_BLACK
);
888 rb
->lcd_clear_display();
889 rb
->lcd_puts(0, 1, message
);
890 rb
->snprintf(str
, 9, "$%d", amount
);
891 rb
->lcd_puts(0, 2, str
);
892 rb
->lcd_puts(0, 3, "RIGHT: +1");
893 rb
->lcd_puts(0, 4, "LEFT: -1");
894 rb
->lcd_puts(0, 5, "UP: +10");
895 rb
->lcd_puts(0, 6, "DOWN: -10");
898 rb
->lcd_set_drawmode(DRMODE_BG
+DRMODE_INVERSEVID
);
899 rb
->lcd_fillrect(LCD_WIDTH
/2 - 9*w
- 1, LCD_HEIGHT
/2 - 4*h
- 3, 37*w
/ 2,
901 rb
->lcd_set_drawmode(DRMODE_SOLID
);
902 rb
->lcd_drawrect(LCD_WIDTH
/2 - 9*w
- 1, LCD_HEIGHT
/2 - 4*h
- 3, 37*w
/ 2,
904 rb
->lcd_putsxy(LCD_WIDTH
/2 - 9*w
, LCD_HEIGHT
/2 - 4*h
- 1, message
);
905 rb
->snprintf(str
, 9, "$%d", amount
);
906 rb
->lcd_putsxy(LCD_WIDTH
/2 - 9*w
, LCD_HEIGHT
/2 - 3*h
, str
);
907 #if (CONFIG_KEYPAD == IPOD_4G_PAD) || \
908 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
909 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
910 rb
->lcd_putsxy(LCD_WIDTH
/2 - 9*w
, LCD_HEIGHT
/2 - h
-2, " >>|: +1");
911 rb
->lcd_putsxy(LCD_WIDTH
/2 - 9*w
, LCD_HEIGHT
/2 - 1, " |<<: -1");
912 rb
->lcd_putsxy(LCD_WIDTH
/2 - 9*w
, LCD_HEIGHT
/2 + h
, "SCROLL+: +10");
913 rb
->lcd_putsxy(LCD_WIDTH
/2 - 9*w
, LCD_HEIGHT
/2 + 2*h
+ 1, "SCROLL-: -10");
914 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
915 rb
->lcd_putsxy(LCD_WIDTH
/2 - 9*w
, LCD_HEIGHT
/2 - h
-2, "RIGHT: +1");
916 rb
->lcd_putsxy(LCD_WIDTH
/2 - 9*w
, LCD_HEIGHT
/2 - 1, "LEFT: -1");
917 rb
->lcd_putsxy(LCD_WIDTH
/2 - 9*w
, LCD_HEIGHT
/2 + h
, "SCROLL+: +10");
918 rb
->lcd_putsxy(LCD_WIDTH
/2 - 9*w
, LCD_HEIGHT
/2 + 2*h
+ 1, "SCROLL-: -10");
920 rb
->lcd_putsxy(LCD_WIDTH
/2 - 9*w
, LCD_HEIGHT
/2 - h
-2, "RIGHT: +1");
921 rb
->lcd_putsxy(LCD_WIDTH
/2 - 9*w
, LCD_HEIGHT
/2 - 1, "LEFT: -1");
922 rb
->lcd_putsxy(LCD_WIDTH
/2 - 9*w
, LCD_HEIGHT
/2 + h
, "UP: +10");
923 rb
->lcd_putsxy(LCD_WIDTH
/2 - 9*w
, LCD_HEIGHT
/2 + 2*h
+ 1, "DOWN: -10");
925 rb
->lcd_update_rect(LCD_WIDTH
/2 - 9*w
- 2, LCD_HEIGHT
/2 - 9*h
/2, 37*w
/2 + 1,
930 button
= rb
->button_get(true);
934 case (BJACK_UP
|BUTTON_REPEAT
):
935 if (amount
+ 10 < upper_limit
+ 1) {
941 case (BJACK_DOWN
|BUTTON_REPEAT
):
942 if (amount
- 10 > lower_limit
- 1) {
948 case (BJACK_RIGHT
|BUTTON_REPEAT
):
949 if (amount
+ 1 < upper_limit
+ 1) {
955 case (BJACK_LEFT
|BUTTON_REPEAT
):
956 if (amount
- 1 > lower_limit
- 1) {
962 amount
= upper_limit
;
966 amount
= lower_limit
;
973 rb
->lcd_set_foreground(FG_COLOR
);
974 rb
->lcd_set_background(BG_COLOR
);
976 rb
->lcd_clear_display();
981 rb
->snprintf(str
, 9, "$%d", amount
);
983 rb
->lcd_puts(0, 2, str
);
986 rb
->lcd_set_drawmode(DRMODE_BG
+DRMODE_INVERSEVID
);
987 rb
->lcd_fillrect(LCD_WIDTH
/2 - 9*w
, LCD_HEIGHT
/2 - 3*h
, 5*w
, h
);
988 rb
->lcd_set_drawmode(DRMODE_SOLID
);
989 rb
->lcd_putsxy(LCD_WIDTH
/2 - 9*w
, LCD_HEIGHT
/2 - 3*h
, str
);
990 rb
->lcd_update_rect(LCD_WIDTH
/2 - 9*w
, LCD_HEIGHT
/2 - 3*h
, 5*w
, h
);
997 /*****************************************************************************
998 * blackjack_get_bet() gets the player's bet.
999 ******************************************************************************/
1000 static void blackjack_get_bet(struct game_context
* bj
) {
1001 bj
->current_bet
= blackjack_get_amount("Please enter a bet", 10,
1002 bj
->player_money
, bj
->current_bet
);
1005 /*****************************************************************************
1006 * double_down() returns one final card then finishes the game
1007 ******************************************************************************/
1008 static void double_down(struct game_context
* bj
) {
1009 bj
->current_bet
*= 2;
1010 bj
->player_cards
[0][bj
->num_player_cards
[0]] = new_card();
1011 bj
->player_total
+= bj
->player_cards
[0][bj
->num_player_cards
[0]].value
;
1012 bj
->num_player_cards
[0]++;
1015 /*****************************************************************************
1016 * split() checks if the player wants to split and acts accordingly.
1017 * When bj->split_status is 1, no split occurred. 2 means the player split and 3
1018 * means a split has already occurred and the first hand is done.
1019 ******************************************************************************/
1020 static void split(struct game_context
* bj
) {
1021 if (blackjack_get_yes_no("Split?") == 1)
1022 bj
->split_status
= 1;
1024 bj
->split_status
= 2;
1025 bj
->current_bet
*= 2;
1026 bj
->num_player_cards
[0] = 1;
1027 bj
->num_player_cards
[1] = 1;
1028 bj
->player_cards
[1][0] = bj
->player_cards
[0][1];
1029 bj
->player_total
= bj
->player_cards
[0][0].value
;
1033 /*****************************************************************************
1034 * insurance() see if the player wants to buy insurance and how much.
1035 ******************************************************************************/
1036 static unsigned int insurance(struct game_context
* bj
) {
1037 unsigned int insurance
, max_amount
;
1039 insurance
= blackjack_get_yes_no("Buy Insurance?");
1040 bj
->asked_insurance
= true;
1041 max_amount
= bj
->current_bet
< (unsigned int)bj
->player_money
?
1042 bj
->current_bet
/2 : (unsigned int)bj
->player_money
;
1043 if (insurance
== 1) return 0;
1045 insurance
= blackjack_get_amount("How much?", 0, max_amount
, 0);
1050 /*****************************************************************************
1051 * play_again() checks to see if the player wants to keep playing.
1052 ******************************************************************************/
1053 static unsigned int play_again(void) {
1054 return blackjack_get_yes_no("Play Again?");
1057 /*****************************************************************************
1058 * blackjack_menu() is the initial menu at the start of the game.
1059 ******************************************************************************/
1060 static unsigned int blackjack_menu(struct game_context
* bj
) {
1062 char *title
= "Blackjack";
1064 unsigned int i
, w
, h
;
1065 bool breakout
= false;
1066 bool showscores
= false;
1070 rb
->lcd_set_background(BG_COLOR
);
1071 rb
->lcd_set_foreground(FG_COLOR
);
1073 rb
->lcd_clear_display();
1076 /* welcome screen to display key bindings */
1077 rb
->lcd_getstringsize(title
, &w
, &h
);
1078 rb
->lcd_putsxy((LCD_WIDTH
-w
)/2, 0, title
);
1080 #if CONFIG_KEYPAD == RECORDER_PAD
1081 rb
->lcd_puts(0, 1, "ON: start");
1082 rb
->lcd_puts(0, 2, "OFF: exit");
1083 rb
->lcd_puts(0, 3, "F1: hit");
1084 rb
->lcd_puts(0, 4, "F2: stay");
1085 rb
->lcd_puts(0, 5, "F3: double down");
1086 rb
->lcd_puts(0, 6, "PLAY: save/resume");
1087 rb
->snprintf(str
, 21, "High Score: $%d", bj
->highscores
[0]);
1088 rb
->lcd_puts(0, 7, str
);
1089 #elif CONFIG_KEYPAD == ONDIO_PAD
1090 rb
->lcd_puts(0, 1, "MENU: start");
1091 rb
->lcd_puts(0, 2, "OFF: exit");
1092 rb
->lcd_puts(0, 3, "LEFT: hit");
1093 rb
->lcd_puts(0, 4, "RIGHT: stay");
1094 rb
->lcd_puts(0, 5, "UP: double down");
1095 rb
->lcd_puts(0, 6, "DOWN: save/resume");
1096 rb
->snprintf(str
, 21, "High Score: $%d", bj
->highscores
[0]);
1097 rb
->lcd_puts(0, 7, str
);
1098 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || (CONFIG_KEYPAD == IRIVER_H300_PAD)
1099 rb
->lcd_puts(0, 2, "PLAY to start & to hit");
1100 rb
->lcd_puts(0, 3, "STOP to exit");
1101 rb
->lcd_puts(0, 4, "REC to stay");
1102 rb
->lcd_puts(0, 5, "NAVI to double down ");
1103 rb
->lcd_puts(0, 6, " & to view highscores");
1104 rb
->lcd_puts(0, 7, "AB to save/resume");
1105 rb
->snprintf(str
, 21, "High Score: $%d", bj
->highscores
[0]);
1106 rb
->lcd_puts(0, 8, str
);
1107 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
1108 rb
->lcd_puts(0, 2, "PLAY to start & hit");
1109 rb
->lcd_puts(0, 3, "POWER to exit");
1110 rb
->lcd_puts(0, 4, ">>| to stay");
1111 rb
->lcd_puts(0, 5, "|<< to double down");
1112 rb
->lcd_puts(0, 6, "LEFT to view scores");
1113 rb
->lcd_puts(0, 7, "RIGHT to save/resume");
1114 rb
->snprintf(str
, 21, "High Score: $%d", bj
->highscores
[0]);
1115 rb
->lcd_puts(0, 8, str
);
1117 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \
1118 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
1119 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
1121 rb
->lcd_puts(0, 2, "SELECT to start & to hit");
1122 rb
->lcd_puts(0, 3, "MENU to exit");
1123 rb
->lcd_puts(0, 4, ">>| to stay & to view highscores");
1124 rb
->lcd_puts(0, 5, "|<< to double down");
1125 rb
->lcd_puts(0, 6, "PLAY to save/resume");
1126 rb
->snprintf(str
, 21, "High Score: $%d", bj
->highscores
[0]);
1127 rb
->lcd_puts(0, 7, str
);
1129 rb
->lcd_puts(0, 2, "SELECT to start & to ");
1130 rb
->lcd_puts(0, 3, " hit");
1131 rb
->lcd_puts(0, 4, "MENU to exit");
1132 rb
->lcd_puts(0, 5, ">>| to stay & to view ");
1133 rb
->lcd_puts(0, 6, " highscores");
1134 rb
->lcd_puts(0, 7, "|<< to double down");
1135 rb
->lcd_puts(0, 8, "PLAY to save/resume");
1136 rb
->snprintf(str
, 21, "High Score: $%d", bj
->highscores
[0]);
1137 rb
->lcd_puts(0, 9, str
);
1139 #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD
1140 rb
->lcd_puts(0, 2, "PLAY to start to hit");
1141 rb
->lcd_puts(0, 3, "POWER to exit");
1142 rb
->lcd_puts(0, 4, "SELECT to hit");
1143 rb
->lcd_puts(0, 5, "REC to stay");
1144 rb
->lcd_puts(0, 6, "PLAY to double down");
1145 rb
->lcd_puts(0, 7, "RIGHT to view highscores ");
1146 rb
->lcd_puts(0, 8, "DOWN to save/resume");
1147 rb
->snprintf(str
, 21, "High Score: $%d", bj
->highscores
[0]);
1148 rb
->lcd_puts(0, 9, str
);
1149 #elif CONFIG_KEYPAD == IRIVER_IFP7XX_PAD
1150 rb
->lcd_puts(0, 2, "AB to start & to");
1151 rb
->lcd_puts(0, 3, " stay");
1152 rb
->lcd_puts(0, 4, "EQ to hit");
1153 rb
->lcd_puts(0, 5, "PLAY to exit");
1154 rb
->lcd_puts(0, 6, "CLICK to double down");
1155 rb
->lcd_puts(0, 7, "& to view highscores");
1156 rb
->lcd_puts(0, 8, "AB+EQ to save/resume");
1157 rb
->snprintf(str
, 21, "High Score: $%d", bj
->highscores
[0]);
1158 rb
->lcd_puts(0, 9, str
);
1159 #elif CONFIG_KEYPAD == GIGABEAT_PAD
1160 rb
->lcd_puts(0, 2, "POWER to start");
1161 rb
->lcd_puts(0, 3, "A to exit");
1162 rb
->lcd_puts(0, 4, "VOL+ to hit");
1163 rb
->lcd_puts(0, 5, "VOL- to stay");
1164 rb
->lcd_puts(0, 6, "CENTER to double down");
1165 rb
->lcd_puts(0, 6, "RIGHT to view highscores ");
1166 rb
->lcd_puts(0, 8, "MENU to save/resume");
1167 rb
->snprintf(str
, 21, "High Score: $%d", bj
->highscores
[0]);
1168 rb
->lcd_puts(0, 9, str
);
1169 #elif (CONFIG_KEYPAD == SANSA_E200_PAD)
1170 rb
->lcd_puts(0, 2, "SELECT to start & to hit");
1171 rb
->lcd_puts(0, 3, "POWER to exit");
1172 rb
->lcd_puts(0, 4, "RIGHT to stay");
1173 rb
->lcd_puts(0, 5, "LEFT to double down");
1174 rb
->lcd_puts(0, 6, "REC to save/resume");
1175 rb
->lcd_puts(0, 7, "UP to view scores");
1176 rb
->snprintf(str
, 21, "High Score: $%d", bj
->highscores
[0]);
1177 rb
->lcd_puts(0, 8, str
);
1178 #elif (CONFIG_KEYPAD == SANSA_C200_PAD)
1179 rb
->lcd_puts(0, 2, "SELECT to start & to hit");
1180 rb
->lcd_puts(0, 3, "POWER to exit");
1181 rb
->lcd_puts(0, 4, "RIGHT to stay");
1182 rb
->lcd_puts(0, 5, "LEFT to double down");
1183 rb
->lcd_puts(0, 6, "DOWN to save/resume");
1184 rb
->lcd_puts(0, 7, "REC to view scores");
1185 rb
->snprintf(str
, 21, "High Score: $%d", bj
->highscores
[0]);
1186 rb
->lcd_puts(0, 9, str
);
1187 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
1188 rb
->lcd_puts(0, 2, "PLAY to start & to");
1189 rb
->lcd_puts(0, 3, " hit");
1190 rb
->lcd_puts(0, 4, "REC to exit");
1191 rb
->lcd_puts(0, 5, "FF to stay");
1192 rb
->lcd_puts(0, 6, "REW to double down");
1193 rb
->lcd_puts(0, 7, "MODE to save/resume");
1194 rb
->lcd_puts(0, 8, "MENU to view scores");
1195 rb
->snprintf(str
, 21, "High Score: $%d", bj
->highscores
[0]);
1196 rb
->lcd_puts(0, 10, str
);
1199 rb
->snprintf(str
, 12, "%s", "High Scores");
1200 rb
->lcd_getstringsize(str
, &w
, &h
);
1201 rb
->lcd_putsxy((LCD_WIDTH
-w
)/2, 0, str
);
1203 /* print high scores */
1204 for(i
=0; i
<NUM_SCORES
; i
++) {
1205 rb
->snprintf(str
, 14, "#%02d: $%d", i
+1, bj
->highscores
[i
]);
1206 rb
->lcd_puts(0, i
+1, str
);
1212 /* handle menu button presses */
1213 button
= rb
->button_get(true);
1216 case BJACK_START
: /* start playing */
1220 case BJACK_QUIT
: /* quit program */
1227 case BJACK_RESUME
:/* resume game */
1228 if(!blackjack_loadgame(bj
)) {
1229 rb
->splash(HZ
*2, "Nothing to resume");
1231 rb
->splash(HZ
*2, "Loading...");
1236 case BJACK_SCORES
:/* toggle high scores */
1237 showscores
= !showscores
;
1241 if(rb
->default_event_handler_ex(button
, blackjack_callback
,
1242 (void*) bj
) == SYS_USB_CONNECTED
)
1253 /*****************************************************************************
1254 * blackjack() is the main game subroutine, it returns the final game status.
1255 ******************************************************************************/
1256 static int blackjack(struct game_context
* bj
) {
1258 unsigned int w
, h
, temp_var
, done
= 0, todo
= 1;
1260 bool breakout
= false;
1261 bool dbl_down
= false;
1263 /* don't resume by default */
1266 /********************
1268 ********************/
1269 temp_var
= blackjack_menu(bj
);
1270 if (temp_var
== BJ_QUIT
|| temp_var
== BJ_USB
)
1274 /********************
1276 ********************/
1280 /********************
1282 ********************/
1284 /* check for resumed game */
1288 if (bj
->split_status
== 2) {
1290 player_x
= bj
->num_player_cards
[0] * 10 + 4;
1292 else if (bj
->split_status
== 3) {
1293 player_x
= bj
->num_player_cards
[1] * 10 + LCD_WIDTH
/2 + 4;
1300 bj
->player_money
= 1000;
1301 blackjack_get_bet(bj
);
1302 if (bj
->current_bet
== 0)
1304 rb
->lcd_clear_display();
1305 deal_init_cards(bj
);
1306 blackjack_drawtable(bj
);
1314 if(bj
->player_total
== 21 && bj
->num_player_cards
[0] == 2) {
1315 bj
->is_blackjack
= true;
1316 bj
->end_hand
= true;
1319 else if(bj
->dealer_cards
[1].is_soft_ace
&& !breakout
&&
1320 !bj
->asked_insurance
) {
1321 temp_var
= insurance(bj
);
1322 if (bj
->dealer_total
== 21) {
1323 rb
->splash(HZ
, "Dealer has blackjack");
1324 bj
->player_money
+= temp_var
;
1325 bj
->end_hand
= true;
1331 rb
->splash(HZ
, "Dealer does not have blackjack");
1332 bj
->player_money
-= temp_var
;
1338 if(bj
->split_status
== 0 &&
1339 bj
->player_cards
[0][0].num
== bj
->player_cards
[0][1].num
) {
1342 rb
->lcd_update_rect(0, LCD_HEIGHT
/2, LCD_WIDTH
, LCD_HEIGHT
/2);
1343 if (bj
->split_status
== 2) {
1345 player_x
= bj
->num_player_cards
[0] * 10 + 4;
1349 while(done
< todo
) {
1350 button
= rb
->button_get(true);
1354 NEXT_CARD
= new_card();
1355 bj
->player_total
+= NEXT_CARD
.value
;
1356 draw_card(NEXT_CARD
, true, player_x
, player_y
);
1357 bj
->num_player_cards
[done
]++;
1358 if (bj
->num_player_cards
[done
] == MAX_CARDS
+ 1) {
1360 rb
->lcd_update_rect(0, LCD_HEIGHT
/2, LCD_WIDTH
,
1363 else if (bj
->num_player_cards
[done
]>MAX_CARDS
|| todo
> 1) {
1364 rb
->lcd_update_rect(player_x
, player_y
, CARD_WIDTH
+2,
1369 rb
->lcd_update_rect(player_x
, player_y
, CARD_WIDTH
+2,
1371 player_x
+= CARD_WIDTH
+ 4;
1377 bj
->end_hand
= true;
1379 case BJACK_DOUBLEDOWN
:
1380 if ((signed int)bj
->current_bet
* 2 < bj
->player_money
+ 1 &&
1381 bj
->num_player_cards
[0]==2 && todo
==1) {
1384 if (bj
->player_total
< 22) {
1385 bj
->end_hand
= true;
1389 else if((signed int)bj
->current_bet
* 2 > bj
->player_money
) {
1390 rb
->splash(HZ
, "Not enough money to double down.");
1395 case BJACK_RESUME
: /* save and end game */
1396 rb
->splash(HZ
, "Saving game...");
1397 blackjack_savegame(bj
);
1398 /* fall through to BJACK_QUIT */
1404 while (bj
->player_total
> 21 && !bj
->end_hand
) {
1405 temp
= check_for_aces(bj
->player_cards
[done
],
1406 bj
->num_player_cards
[done
]);
1408 bj
->player_cards
[done
][temp
].is_soft_ace
= false;
1409 bj
->player_total
-= 10;
1412 bj
->end_hand
= true;
1417 bj
->end_hand
= true;
1424 temp
= bj
->player_total
;
1425 bj
->player_total
= temp_var
;
1428 rb
->lcd_getstringsize(" Split 1 ", &w
, &h
);
1429 rb
->lcd_putsxy(LCD_WIDTH
/2-w
/2, LCD_HEIGHT
/2-3*h
/2,
1431 rb
->lcd_update_rect(LCD_WIDTH
/2-w
/2, LCD_HEIGHT
/2-3*h
/2,
1433 bj
->current_bet
/= 2;
1434 rb
->lcd_update_rect(LCD_WIDTH
/2-w
/2, LCD_HEIGHT
/2-3*h
/2,
1437 bj
->player_total
= temp_var
;
1439 rb
->lcd_getstringsize(" Split 2 ", &w
, &h
);
1440 rb
->lcd_putsxy(LCD_WIDTH
/2-w
/2, LCD_HEIGHT
/2-3*h
/2,
1442 rb
->lcd_update_rect(LCD_WIDTH
/2-w
/2, LCD_HEIGHT
/2-3*h
/2,
1447 bj
->end_hand
= false;
1448 bj
->split_status
= 3;
1449 temp_var
= bj
->player_total
;
1450 bj
->player_total
= bj
->player_cards
[1][0].value
;
1462 if (bj
->player_money
< 10) {
1467 if (bj
->end_hand
) { /* If hand is over */
1468 if (play_again() != 0) /* User wants to quit */
1470 else { /* User keeps playing */
1474 bj
->current_bet
/= 2;
1480 blackjack_get_bet(bj
);
1481 if (bj
->current_bet
== 0)
1483 deal_init_cards(bj
);
1484 blackjack_drawtable(bj
);
1493 /*****************************************************************************
1494 * plugin entry point.
1495 ******************************************************************************/
1496 enum plugin_status
plugin_start(struct plugin_api
* api
, void* parameter
) {
1497 struct game_context bj
;
1499 unsigned int position
;
1506 rb
->lcd_set_backdrop(NULL
);
1509 /* load high scores */
1510 blackjack_loadscores(&bj
);
1512 rb
->lcd_setfont(FONT_SYSFIXED
);
1515 switch(blackjack(&bj
)){
1517 rb
->splash(HZ
, "Not enough money to continue");
1518 /* fall through to BJ_END */
1522 if((position
= blackjack_recordscore(&bj
))) {
1523 rb
->snprintf(str
, 19, "New high score #%d!", position
);
1524 rb
->splash(HZ
*2, str
);
1530 rb
->lcd_setfont(FONT_UI
);
1531 return PLUGIN_USB_CONNECTED
;
1535 rb
->splash(HZ
, "Saving high scores...");
1536 blackjack_savescores(&bj
);
1546 rb
->lcd_setfont(FONT_UI
);