Reverting parts of r19760 that was mistakenly committed.
[kugel-rb.git] / apps / plugins / blackjack.c
blob2aed40fd9e162c43f1b65b03f5078bf259ec1b6b
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id: $
10 * Copyright (C) 2006 Tom Ross
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
22 #include "plugin.h"
23 #include "pluginbitmaps/card_deck.h"
24 #include "pluginbitmaps/card_back.h"
26 PLUGIN_HEADER
28 /* save files */
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 */
35 #define BJ_END 3
36 #define BJ_USB 2
37 #define BJ_QUIT 1
38 #define BJ_LOSE 0
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 (CONFIG_KEYPAD == SANSA_FUZE_PAD)
165 #define BJACK_START BUTTON_SELECT
166 #define BJACK_QUIT BUTTON_POWER
167 #define BJACK_MAX (BUTTON_SELECT|BUTTON_UP)
168 #define BJACK_MIN (BUTTON_SELECT|BUTTON_DOWN)
169 #define BJACK_HIT (BUTTON_SELECT|BUTTON_REL)
170 #define BJACK_STAY BUTTON_RIGHT
171 #define BJACK_DOUBLEDOWN BUTTON_LEFT
172 #define BJACK_SCORES BUTTON_DOWN
173 #define BJACK_RESUME BUTTON_UP
174 #define BJACK_UP BUTTON_SCROLL_FWD
175 #define BJACK_DOWN BUTTON_SCROLL_BACK
176 #define BJACK_RIGHT BUTTON_RIGHT
177 #define BJACK_LEFT BUTTON_LEFT
179 #elif CONFIG_KEYPAD == SANSA_C200_PAD
180 #define BJACK_START BUTTON_SELECT
181 #define BJACK_QUIT BUTTON_POWER
182 #define BJACK_MAX BUTTON_VOL_UP
183 #define BJACK_MIN BUTTON_VOL_DOWN
184 #define BJACK_HIT BUTTON_SELECT
185 #define BJACK_STAY BUTTON_RIGHT
186 #define BJACK_DOUBLEDOWN BUTTON_LEFT
187 #define BJACK_SCORES BUTTON_REC
188 #define BJACK_RESUME BUTTON_DOWN
189 #define BJACK_UP BUTTON_UP
190 #define BJACK_DOWN BUTTON_DOWN
191 #define BJACK_RIGHT BUTTON_RIGHT
192 #define BJACK_LEFT BUTTON_LEFT
194 #elif CONFIG_KEYPAD == SANSA_CLIP_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_HOME
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_M200_PAD
210 #define BJACK_START (BUTTON_SELECT | BUTTON_REL)
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 | BUTTON_REL)
215 #define BJACK_STAY BUTTON_RIGHT
216 #define BJACK_DOUBLEDOWN BUTTON_LEFT
217 #define BJACK_SCORES (BUTTON_SELECT | BUTTON_UP)
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 == ELIO_TPJ1022_PAD
225 #define BJACK_START BUTTON_MAIN
226 #define BJACK_QUIT BUTTON_POWER
227 #define BJACK_MAX (BUTTON_REC|BUTTON_UP)
228 #define BJACK_MIN (BUTTON_REC|BUTTON_DOWN)
229 #define BJACK_HIT BUTTON_MAIN
230 #define BJACK_STAY BUTTON_MENU
231 #define BJACK_DOUBLEDOWN BUTTON_DOWN
232 #define BJACK_SCORES BUTTON_UP
233 #define BJACK_RESUME BUTTON_FF
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 == GIGABEAT_S_PAD
240 #define BJACK_START BUTTON_PLAY
241 #define BJACK_QUIT BUTTON_BACK
242 #define BJACK_MAX BUTTON_VOL_UP
243 #define BJACK_MIN BUTTON_VOL_DOWN
244 #define BJACK_HIT BUTTON_VOL_UP
245 #define BJACK_STAY BUTTON_VOL_DOWN
246 #define BJACK_DOUBLEDOWN BUTTON_SELECT
247 #define BJACK_SCORES BUTTON_RIGHT
248 #define BJACK_RESUME BUTTON_MENU
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 == MROBE100_PAD
256 #define BJACK_START BUTTON_SELECT
257 #define BJACK_QUIT BUTTON_POWER
258 #define BJACK_MAX BUTTON_MENU
259 #define BJACK_MIN BUTTON_DISPLAY
260 #define BJACK_HIT BUTTON_MENU
261 #define BJACK_STAY BUTTON_DISPLAY
262 #define BJACK_DOUBLEDOWN BUTTON_DOWN
263 #define BJACK_SCORES BUTTON_RIGHT
264 #define BJACK_RESUME BUTTON_PLAY
265 #define BJACK_UP BUTTON_UP
266 #define BJACK_DOWN BUTTON_DOWN
267 #define BJACK_RIGHT BUTTON_RIGHT
268 #define BJACK_LEFT BUTTON_LEFT
270 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
272 #define BJACK_START BUTTON_RC_PLAY
273 #define BJACK_QUIT BUTTON_RC_REC
274 #define BJACK_MAX (BUTTON_RC_PLAY|BUTTON_RC_VOL_UP)
275 #define BJACK_MIN (BUTTON_RC_PLAY|BUTTON_RC_VOL_DOWN)
276 #define BJACK_HIT BUTTON_RC_PLAY
277 #define BJACK_STAY BUTTON_RC_FF
278 #define BJACK_DOUBLEDOWN BUTTON_RC_REW
279 #define BJACK_SCORES BUTTON_RC_MENU
280 #define BJACK_RESUME BUTTON_RC_MODE
281 #define BJACK_UP BUTTON_RC_VOL_UP
282 #define BJACK_DOWN BUTTON_RC_VOL_DOWN
283 #define BJACK_RIGHT BUTTON_RC_FF
284 #define BJACK_LEFT BUTTON_RC_REW
286 #elif CONFIG_KEYPAD == COWOND2_PAD
287 #define BJACK_QUIT BUTTON_POWER
288 #define BJACK_DOUBLEDOWN BUTTON_MINUS
289 #define BJACK_SCORES BUTTON_MENU
291 #elif CONFIG_KEYPAD == CREATIVEZVM_PAD
292 #define BJACK_START BUTTON_SELECT
293 #define BJACK_QUIT BUTTON_BACK
294 #define BJACK_MAX (BUTTON_CUSTOM|BUTTON_UP)
295 #define BJACK_MIN (BUTTON_CUSTOM|BUTTON_DOWN)
296 #define BJACK_HIT BUTTON_UP
297 #define BJACK_STAY BUTTON_DOWN
298 #define BJACK_DOUBLEDOWN BUTTON_CUSTOM
299 #define BJACK_SCORES BUTTON_RIGHT
300 #define BJACK_RESUME BUTTON_MENU
301 #define BJACK_UP BUTTON_UP
302 #define BJACK_DOWN BUTTON_DOWN
303 #define BJACK_RIGHT BUTTON_RIGHT
304 #define BJACK_LEFT BUTTON_LEFT
306 #else
307 #error No keymap defined!
308 #endif
310 #ifdef HAVE_TOUCHSCREEN
311 #ifndef BJACK_START
312 #define BJACK_START BUTTON_CENTER
313 #endif
314 #ifndef BJACK_HIT
315 #define BJACK_HIT BUTTON_CENTER
316 #endif
317 #ifndef BJACK_MAX
318 #define BJACK_MAX BUTTON_TOPRIGHT
319 #endif
320 #ifndef BJACK_MIN
321 #define BJACK_MIN BUTTON_TOPLEFT
322 #endif
323 #ifndef BJACK_RESUME
324 #define BJACK_RESUME BUTTON_BOTTOMRIGHT
325 #endif
326 #ifndef BJACK_STAY
327 #define BJACK_STAY BUTTON_BOTTOMLEFT
328 #endif
329 #ifndef BJACK_UP
330 #define BJACK_UP BUTTON_TOPMIDDLE
331 #endif
332 #ifndef BJACK_DOWN
333 #define BJACK_DOWN BUTTON_BOTTOMMIDDLE
334 #endif
335 #ifndef BJACK_RIGHT
336 #define BJACK_RIGHT BUTTON_MIDRIGHT
337 #endif
338 #ifndef BJACK_LEFT
339 #define BJACK_LEFT BUTTON_MIDLEFT
340 #endif
342 #endif
344 #ifdef HAVE_LCD_COLOR
345 #define BG_COLOR LCD_RGBPACK(0,157,0)
346 #define FG_COLOR LCD_WHITE
347 #elif LCD_DEPTH > 1
348 #define BG_COLOR LCD_WHITE
349 #define FG_COLOR LCD_BLACK
350 #endif
352 #define CARD_WIDTH BMPWIDTH_card_back
353 #define CARD_HEIGHT BMPHEIGHT_card_back
355 /* This is the max amount of cards onscreen before condensing */
356 #define MAX_CARDS LCD_WIDTH/(CARD_WIDTH+4)
358 extern const fb_data card_deck[];
359 extern const fb_data card_back[];
361 #define NEXT_CARD bj->player_cards[done][bj->num_player_cards[done]]
363 /* global rockbox api */
364 static const struct plugin_api* rb;
366 MEM_FUNCTION_WRAPPERS(rb);
368 /* dealer and player card positions */
369 unsigned int dealer_x, dealer_y, player_x, player_y;
371 typedef struct card {
372 unsigned int value; /* Card's value in Blackjack */
373 unsigned int num; /* Value on card face 0-12 (0=Ace, 1=2, 11=Q) */
374 unsigned int suit; /* 0:Spades, 1:Hearts, 2: Clubs; 3: Diamonds */
375 bool is_soft_ace;
376 } card;
378 typedef struct game_context {
379 struct card player_cards[2][22]; /* 22 Cards means the deal was all aces */
380 struct card dealer_cards[22]; /* That is the worst-case scenario */
381 unsigned int player_total;
382 unsigned int dealer_total;
383 signed int player_money;
384 unsigned int num_player_cards[2];
385 unsigned int num_dealer_cards;
386 unsigned int current_bet;
387 unsigned int split_status; /* 0 = split hasn't been asked, *
388 * 1 = split did not occur *
389 * 2 = split occurred *
390 * 3 = split occurred and 1st hand done */
391 bool is_blackjack;
392 bool end_hand;
393 bool asked_insurance;
394 signed short highscores[NUM_SCORES];
395 bool resume;
396 bool dirty;
397 } game_context;
399 /*****************************************************************************
400 * blackjack_init() initializes blackjack data structures.
401 ******************************************************************************/
402 static void blackjack_init(struct game_context* bj) {
403 /* seed the rand generator */
404 rb->srand(*rb->current_tick);
406 /* reset card positions */
407 dealer_x = 4;
408 dealer_y = LCD_HEIGHT/4 - CARD_HEIGHT/2;
409 player_x = 4;
410 player_y = LCD_HEIGHT - LCD_HEIGHT/4 - CARD_HEIGHT/2;
412 /* check for resumed game */
413 if(bj->resume) return;
415 /* reset scoring */
416 bj->player_total = 0;
417 bj->dealer_total = 0;
418 bj->num_player_cards[0] = 2;
419 bj->num_player_cards[1] = 0;
420 bj->num_dealer_cards = 2;
421 bj->end_hand = false;
422 bj->split_status = 0;
423 bj->is_blackjack = false;
424 bj->asked_insurance = false;
427 /*****************************************************************************
428 * blackjack_drawtable() draws the table and some text.
429 ******************************************************************************/
430 static void blackjack_drawtable(struct game_context* bj) {
431 unsigned int w, h, y_loc;
432 char str[10];
434 #if LCD_HEIGHT <= 64
435 rb->lcd_getstringsize("Bet", &w, &h);
436 rb->lcd_putsxy(LCD_WIDTH - w, 2*h + 1, "Bet");
437 rb->snprintf(str, 9, "$%d", bj->current_bet);
438 rb->lcd_getstringsize(str, &w, &h);
439 rb->lcd_putsxy(LCD_WIDTH - w, 3*h + 1, str);
440 y_loc = LCD_HEIGHT/2;
441 #else
442 rb->lcd_getstringsize("Bet", &w, &h);
443 rb->lcd_putsxy(LCD_WIDTH - w, 5*h / 2, "Bet");
444 rb->snprintf(str, 9, "$%d", bj->current_bet);
445 rb->lcd_getstringsize(str, &w, &h);
446 rb->lcd_putsxy(LCD_WIDTH - w, 7*h / 2, str);
447 rb->lcd_hline(0, LCD_WIDTH, LCD_HEIGHT/2);
448 y_loc = LCD_HEIGHT/2 + h;
449 #endif
451 rb->lcd_putsxy(0,0, "Dealer");
452 rb->lcd_getstringsize("Player", &w, &h);
453 rb->lcd_putsxy(0, y_loc, "Player");
454 rb->lcd_getstringsize("Total", &w, &h);
455 rb->lcd_putsxy(LCD_WIDTH - w, y_loc, "Total");
456 rb->lcd_getstringsize("Money", &w, &h);
457 rb->lcd_putsxy(LCD_WIDTH - w, 0, "Money");
458 rb->snprintf(str, 9, "$%d", bj->player_money - bj->current_bet);
459 rb->lcd_getstringsize(str, &w, &h);
460 rb->lcd_putsxy(LCD_WIDTH - w, h + 1, str);
461 rb->snprintf(str, 3, "%d", bj->player_total);
462 rb->lcd_getstringsize(str, &w, &h);
463 rb->lcd_putsxy(LCD_WIDTH - w, y_loc + h, str);
466 /*****************************************************************************
467 * find_value() is passed a card and returns its blackjack value.
468 ******************************************************************************/
469 static unsigned int find_value(unsigned int number) {
470 unsigned int thisValue;
471 if (number == 0)
472 thisValue = 11; /* Aces get a value of 11 at first */
473 else if (number < 10)
474 thisValue = number + 1;
475 else
476 thisValue = 10; /* Anything 10 or higher gets a value of 10 */
478 return thisValue;
481 /*****************************************************************************
482 * draw_card() draws a card to the screen.
483 ******************************************************************************/
484 static void draw_card(struct card temp_card, bool shown, unsigned int x,
485 unsigned int y) {
486 if(shown)
487 rb->lcd_bitmap_part(card_deck, CARD_WIDTH*temp_card.num,
488 CARD_HEIGHT*temp_card.suit, BMPWIDTH_card_deck,
489 x+1, y+1, CARD_WIDTH, CARD_HEIGHT);
490 else
491 rb->lcd_bitmap(card_back, x+1, y+1,CARD_WIDTH, CARD_HEIGHT);
492 #if LCD_DEPTH > 1
493 rb->lcd_set_foreground(LCD_BLACK);
494 #endif
496 /* Print outlines */
497 #if CARD_WIDTH >= 26
498 rb->lcd_hline(x+2, x+CARD_WIDTH-1, y);
499 rb->lcd_hline(x+2, x+CARD_WIDTH-1, y+CARD_HEIGHT+1);
500 rb->lcd_vline(x, y+2, y+CARD_HEIGHT-3);
501 rb->lcd_vline(x+CARD_WIDTH+1, y+2, y+CARD_HEIGHT-1);
502 rb->lcd_drawpixel(x+1, y+1);
503 rb->lcd_drawpixel(x+1, y+CARD_HEIGHT);
504 rb->lcd_drawpixel(x+CARD_WIDTH, y+1);
505 rb->lcd_drawpixel(x+CARD_WIDTH, y+CARD_HEIGHT);
506 #else
507 rb->lcd_hline(x+1, x+CARD_WIDTH, y);
508 rb->lcd_hline(x+1, x+CARD_WIDTH, y+CARD_HEIGHT+1);
509 rb->lcd_vline(x, y+1, y+CARD_HEIGHT);
510 rb->lcd_vline(x+CARD_WIDTH+1, y+1, y+CARD_HEIGHT);
511 #endif
513 #if LCD_DEPTH > 1
514 rb->lcd_set_foreground(FG_COLOR);
515 #endif
518 /*****************************************************************************
519 * new_card() initializes a new card and gives it values.
520 ******************************************************************************/
521 static struct card new_card(void) {
522 struct card new_card;
523 new_card.suit = rb->rand()%4; /* Random number 0-3 */
524 new_card.num = rb->rand()%13; /* Random number 0-12 */
525 new_card.value = find_value(new_card.num);
526 new_card.is_soft_ace = new_card.num == 0 ? true : false;
527 return new_card;
530 /*****************************************************************************
531 * deal_init_card() deals and draws to the screen the player's and dealer's
532 * initial cards.
533 ******************************************************************************/
534 static void deal_init_cards(struct game_context* bj) {
535 bj->dealer_cards[0] = new_card();
536 bj->dealer_total += bj->dealer_cards[0].value;
538 draw_card(bj->dealer_cards[0], false, dealer_x, dealer_y);
540 bj->dealer_cards[1] = new_card();
541 bj->dealer_total += bj->dealer_cards[1].value;
542 draw_card(bj->dealer_cards[1], true, dealer_x + CARD_WIDTH + 4, dealer_y);
544 bj->player_cards[0][0] = new_card();
545 bj->player_total += bj->player_cards[0][0].value;
546 draw_card(bj->player_cards[0][0], true, player_x, player_y);
547 player_x += CARD_WIDTH + 4;
549 bj->player_cards[0][1] = new_card();
550 bj->player_total += bj->player_cards[0][1].value;
551 draw_card(bj->player_cards[0][1], true, player_x, player_y);
552 player_x += CARD_WIDTH + 4;
555 /*****************************************************************************
556 * redraw_board() redraws all the cards and the board
557 ******************************************************************************/
558 static void redraw_board(struct game_context* bj) {
559 unsigned int i, n, upper_bound;
560 rb->lcd_clear_display();
562 blackjack_drawtable(bj);
563 player_x = 4;
564 dealer_x = 4;
565 upper_bound = bj->split_status > 1 ? 2 : 1;
567 for (i = 0; i < bj->num_dealer_cards; i++) {
568 if (!bj->end_hand) {
569 draw_card(bj->dealer_cards[0], false, dealer_x, dealer_y);
571 /* increment i so the dealer's first card isn't displayed */
572 i++;
573 dealer_x += CARD_WIDTH + 4;
575 draw_card(bj->dealer_cards[i], true, dealer_x, dealer_y);
577 if (bj->num_dealer_cards > MAX_CARDS-1)
578 dealer_x += 10;
579 else
580 dealer_x += CARD_WIDTH + 4;
583 for (n = 0; n < upper_bound; n++) {
584 for (i = 0; i < bj->num_player_cards[n]; i++) {
585 draw_card(bj->player_cards[n][i], true, player_x, player_y);
586 if (bj->split_status>1 || bj->num_player_cards[n]>MAX_CARDS)
587 player_x += 10;
588 else
589 player_x += CARD_WIDTH + 4;
591 if (bj->split_status > 1)
592 player_x = LCD_WIDTH/2 + 4;
596 /*****************************************************************************
597 * update_total updates the player's total
598 ******************************************************************************/
599 static void update_total(struct game_context* bj) {
600 char total[3];
601 unsigned int w, h;
602 rb->snprintf(total, 3, "%d", bj->player_total);
603 rb->lcd_getstringsize(total, &w, &h);
604 #if LCD_HEIGHT > 64
605 h *= 2;
606 #endif
607 rb->lcd_putsxy(LCD_WIDTH - w, LCD_HEIGHT/2 + h, total);
608 rb->lcd_update_rect(LCD_WIDTH - w, LCD_HEIGHT/2 + h, w, h);
612 /*****************************************************************************
613 * check_for_aces() is passed an array of cards and returns where an ace is
614 * located. Otherwise, returns -1.
615 ******************************************************************************/
616 static signed int check_for_aces(struct card temp_cards[],
617 unsigned int size) {
618 unsigned int i;
619 for(i = 0; i < size; i++) {
620 if (temp_cards[i].is_soft_ace == true)
621 return i;
623 return -1;
626 /*****************************************************************************
627 * check_totals() compares player and dealer totals.
628 * 0: bust 1: loss, 2: push, 3: win, 4: blackjack, 5: something's not right...
629 ******************************************************************************/
630 static unsigned int check_totals(struct game_context* bj)
632 unsigned int temp;
633 if (bj->player_total > 21)
634 temp = 0;
635 else if (bj->player_total == 21 && bj->is_blackjack)
636 if (bj->dealer_total == 21 && bj->num_dealer_cards == 2)
637 temp = 2;
638 else
639 temp = 4;
640 else if (bj->player_total == bj->dealer_total)
641 temp = 2;
642 else if (bj->dealer_total > 21 && bj->player_total < 22)
643 temp = 3;
644 else if (bj->dealer_total > bj->player_total)
645 temp = 1;
646 else if (bj->player_total > bj->dealer_total)
647 temp = 3;
648 else
649 temp = 5;
651 return temp;
654 /*****************************************************************************
655 * finish_dealer() draws cards for the dealer until he has 17 or more.
656 ******************************************************************************/
657 static void finish_dealer(struct game_context* bj) {
658 signed int temp = 0;
660 if (bj->dealer_total > 16 && bj->dealer_total < 22)
661 return;
663 while (bj->dealer_total < 17) {
664 bj->dealer_cards[bj->num_dealer_cards] = new_card();
665 bj->dealer_total += bj->dealer_cards[bj->num_dealer_cards].value;
666 bj->num_dealer_cards++;
669 while (bj->dealer_total > 21) {
670 temp = check_for_aces(bj->dealer_cards, bj->num_dealer_cards);
671 if(temp != -1) {
672 bj->dealer_cards[temp].is_soft_ace = false;
673 bj->dealer_total -= 10;
675 else
676 return;
680 /*****************************************************************************
681 * finish_game() completes the game once player's turn is over.
682 ******************************************************************************/
683 static void finish_game(struct game_context* bj) {
684 unsigned int rValue, w, h;
685 char str[19];
687 do {
688 finish_dealer(bj);
689 } while (bj->dealer_total < 17);
691 redraw_board(bj);
692 rValue = check_totals(bj);
694 if (rValue == 0) {
695 rb->snprintf(str, sizeof(str), " Bust! ");
696 bj->player_money -= bj->current_bet;
698 else if (rValue == 1) {
699 rb->snprintf(str, sizeof(str), " Sorry, you lost. ");
700 bj->player_money -= bj->current_bet;
702 else if (rValue == 2) {
703 rb->snprintf(str, sizeof(str), " Push ");
705 else if (rValue == 3) {
706 rb->snprintf(str, sizeof(str), " You won! ");
707 bj->player_money+= bj->current_bet;
709 else {
710 rb->snprintf(str, sizeof(str), " Blackjack! ");
711 bj->player_money += bj->current_bet * 3 / 2;
713 rb->lcd_getstringsize(str, &w, &h);
715 #if LCD_HEIGHT <= 64
716 rb->lcd_set_drawmode(DRMODE_BG+DRMODE_INVERSEVID);
717 rb->lcd_fillrect(0, LCD_HEIGHT/2, LCD_WIDTH, LCD_HEIGHT/2);
718 rb->lcd_set_drawmode(DRMODE_SOLID);
719 rb->lcd_putsxy(LCD_WIDTH/2 - w/2, LCD_HEIGHT/2 + h, str);
720 rb->snprintf(str, 12, "You have %d", bj->player_total);
721 rb->lcd_getstringsize(str, &w, &h);
722 rb->lcd_putsxy(LCD_WIDTH/2 - w/2, LCD_HEIGHT/2, str);
723 #else
724 rb->lcd_putsxy(LCD_WIDTH/2 - w/2, LCD_HEIGHT/2 - h/2, str);
725 #endif
726 rb->lcd_update();
729 /*****************************************************************************
730 * blackjack_recordscore() inserts a high score into the high scores list and
731 * returns the high score position.
732 ******************************************************************************/
733 static unsigned int blackjack_recordscore(struct game_context* bj) {
734 unsigned int i;
735 unsigned int position = 0;
736 signed short current, temp;
738 /* calculate total score */
739 current = bj->player_money;
740 if(current <= 10) return 0;
742 /* insert the current score into the high scores */
743 for(i=0; i<NUM_SCORES; i++) {
744 if(current >= bj->highscores[i]) {
745 if(!position) {
746 position = i+1;
747 bj->dirty = true;
749 temp = bj->highscores[i];
750 bj->highscores[i] = current;
751 current = temp;
755 return position;
758 /*****************************************************************************
759 * blackjack_loadscores() loads the high scores saved file.
760 ******************************************************************************/
761 static void blackjack_loadscores(struct game_context* bj) {
762 signed int fd;
764 bj->dirty = false;
766 /* clear high scores */
767 rb->memset(bj->highscores, 0, sizeof(bj->highscores));
769 /* open scores file */
770 fd = rb->open(SCORE_FILE, O_RDONLY);
771 if(fd < 0) return;
773 /* read in high scores */
774 if(rb->read(fd, bj->highscores, sizeof(bj->highscores)) <= 0) {
775 /* scores are bad, reset */
776 rb->memset(bj->highscores, 0, sizeof(bj->highscores));
779 rb->close(fd);
782 /*****************************************************************************
783 * blackjack_savescores() saves the high scores saved file.
784 ******************************************************************************/
785 static void blackjack_savescores(struct game_context* bj) {
786 unsigned int fd;
788 /* write out the high scores to the save file */
789 fd = rb->open(SCORE_FILE, O_WRONLY|O_CREAT);
790 rb->write(fd, bj->highscores, sizeof(bj->highscores));
791 rb->close(fd);
792 bj->dirty = false;
795 /*****************************************************************************
796 * blackjack_loadgame() loads the saved game and returns load success.
797 ******************************************************************************/
798 static bool blackjack_loadgame(struct game_context* bj) {
799 signed int fd;
800 bool loaded = false;
802 /* open game file */
803 fd = rb->open(SAVE_FILE, O_RDONLY);
804 if(fd < 0) return loaded;
806 /* read in saved game */
807 while(true) {
808 if(rb->read(fd, &bj->player_money, sizeof(bj->player_money)) <= 0) break;
809 if(rb->read(fd, &bj->player_total, sizeof(bj->player_total)) <= 0) break;
810 if(rb->read(fd, &bj->dealer_total, sizeof(bj->dealer_total)) <= 0) break;
811 if(rb->read(fd, &bj->num_player_cards, sizeof(bj->num_player_cards))<=0)
812 break;
813 if(rb->read(fd, &bj->num_dealer_cards, sizeof(bj->num_dealer_cards))<=0)
814 break;
815 if(rb->read(fd, &bj->current_bet, sizeof(bj->current_bet)) <= 0) break;
816 if(rb->read(fd, &bj->is_blackjack, sizeof(bj->is_blackjack)) <= 0) break;
817 if(rb->read(fd, &bj->split_status, sizeof(bj->split_status)) <= 0) break;
818 if(rb->read(fd, &bj->asked_insurance, sizeof(bj->asked_insurance)) <= 0)
819 break;
820 if(rb->read(fd, &bj->end_hand, sizeof(bj->end_hand)) <= 0) break;
821 if(rb->read(fd, &bj->player_cards, sizeof(bj->player_cards)) <= 0) break;
822 if(rb->read(fd, &bj->dealer_cards, sizeof(bj->dealer_cards)) <= 0) break;
823 bj->resume = true;
824 loaded = true;
825 break;
828 rb->close(fd);
830 /* delete saved file */
831 rb->remove(SAVE_FILE);
832 return loaded;
835 /*****************************************************************************
836 * blackjack_savegame() saves the current game state.
837 ******************************************************************************/
838 static void blackjack_savegame(struct game_context* bj) {
839 unsigned int fd;
841 /* write out the game state to the save file */
842 fd = rb->open(SAVE_FILE, O_WRONLY|O_CREAT);
843 rb->write(fd, &bj->player_money, sizeof(bj->player_money));
844 rb->write(fd, &bj->player_total, sizeof(bj->player_total));
845 rb->write(fd, &bj->dealer_total, sizeof(bj->dealer_total));
846 rb->write(fd, &bj->num_player_cards, sizeof(bj->num_player_cards));
847 rb->write(fd, &bj->num_dealer_cards, sizeof(bj->num_dealer_cards));
848 rb->write(fd, &bj->current_bet, sizeof(bj->current_bet));
849 rb->write(fd, &bj->is_blackjack, sizeof(bj->is_blackjack));
850 rb->write(fd, &bj->split_status, sizeof(bj->split_status));
851 rb->write(fd, &bj->asked_insurance, sizeof(bj->asked_insurance));
852 rb->write(fd, &bj->end_hand, sizeof(bj->end_hand));
853 rb->write(fd, &bj->player_cards, sizeof(bj->player_cards));
854 rb->write(fd, &bj->dealer_cards, sizeof(bj->dealer_cards));
855 rb->close(fd);
857 bj->resume = true;
860 /*****************************************************************************
861 * blackjack_callback() is the default event handler callback which is called
862 * on usb connect and shutdown.
863 ******************************************************************************/
864 static void blackjack_callback(void* param) {
865 struct game_context* bj = (struct game_context*) param;
866 if(bj->dirty) {
867 rb->splash(HZ, "Saving high scores...");
868 blackjack_savescores(bj);
872 /*****************************************************************************
873 * blackjack_get_yes_no() gets a yes/no answer from the user
874 ******************************************************************************/
875 static unsigned int blackjack_get_yes_no(char message[20]) {
876 int button;
877 unsigned int w, h, b, choice = 0;
878 bool breakout = false;
879 char message_yes[24], message_no[24];
881 rb->strcpy(message_yes, message);
882 rb->strcpy(message_no, message);
883 rb->strcat(message_yes, " Yes");
884 rb->strcat(message_no, " No");
885 rb->lcd_getstringsize(message_yes, &w, &h);
886 const char *stg[] = {message_yes, message_no};
888 #if LCD_HEIGHT <= 64
889 b = 2*h+1;
890 #else
891 b = h-1;
892 #endif
894 #ifdef HAVE_LCD_COLOR
895 rb->lcd_fillrect(LCD_WIDTH/2 - w/2, LCD_HEIGHT/2 + b, w+1, h+3);
896 rb->lcd_set_foreground(LCD_BLACK);
897 rb->lcd_set_background(LCD_WHITE);
898 #else
899 rb->lcd_set_drawmode(DRMODE_BG+DRMODE_INVERSEVID);
900 rb->lcd_fillrect(LCD_WIDTH/2 - w/2, LCD_HEIGHT/2 + b, w+1, h+3);
901 rb->lcd_set_drawmode(DRMODE_SOLID);
902 #endif
903 rb->lcd_drawrect(LCD_WIDTH/2 - w/2 - 1, LCD_HEIGHT/2 + b - 1, w+3, h+4);
905 while(!breakout) {
906 rb->lcd_putsxy(LCD_WIDTH/2 - w/2, LCD_HEIGHT/2 + b +1, stg[choice]);
907 rb->lcd_update_rect(LCD_WIDTH/2 - w/2 - 1, LCD_HEIGHT/2 + b -1,
908 w+3, h+4);
909 button = rb->button_get(true);
911 switch(button) {
912 case BJACK_LEFT:
913 case (BJACK_LEFT|BUTTON_REPEAT):
914 case BJACK_RIGHT:
915 case (BJACK_RIGHT|BUTTON_REPEAT):
916 choice ^= 1;
917 break;
918 case BJACK_START: breakout = true;
919 break;
920 case BJACK_QUIT: breakout = true;
921 choice = BJ_QUIT;
922 break;
926 #if LCD_DEPTH > 1
927 rb->lcd_set_foreground(FG_COLOR);
928 rb->lcd_set_background(BG_COLOR);
929 #endif
930 return choice;
933 /*****************************************************************************
934 * blackjack_get_amount() gets an amount from the player to be used
935 ******************************************************************************/
936 static signed int blackjack_get_amount(char message[20], signed int lower_limit,
937 signed int upper_limit,
938 signed int start) {
939 int button;
940 char str[6];
941 bool changed = false;
942 unsigned int w, h;
943 signed int amount;
945 rb->lcd_getstringsize("A", &w, &h); /* find the size of one character */
947 if (start > upper_limit)
948 amount = upper_limit;
949 else if (start < lower_limit)
950 amount = lower_limit;
951 else
952 amount = start;
954 #if LCD_DEPTH > 1
955 rb->lcd_set_background(LCD_WHITE);
956 rb->lcd_set_foreground(LCD_BLACK);
957 #endif
959 #if LCD_HEIGHT <= 64
960 rb->lcd_clear_display();
961 rb->lcd_puts(0, 1, message);
962 rb->snprintf(str, 9, "$%d", amount);
963 rb->lcd_puts(0, 2, str);
964 rb->lcd_puts(0, 3, "RIGHT: +1");
965 rb->lcd_puts(0, 4, "LEFT: -1");
966 rb->lcd_puts(0, 5, "UP: +10");
967 rb->lcd_puts(0, 6, "DOWN: -10");
968 rb->lcd_update();
969 #else
970 rb->lcd_set_drawmode(DRMODE_BG+DRMODE_INVERSEVID);
971 rb->lcd_fillrect(LCD_WIDTH/2 - 9*w - 1, LCD_HEIGHT/2 - 4*h - 3, 37*w / 2,
972 8*h -3);
973 rb->lcd_set_drawmode(DRMODE_SOLID);
974 rb->lcd_drawrect(LCD_WIDTH/2 - 9*w - 1, LCD_HEIGHT/2 - 4*h - 3, 37*w / 2,
975 8*h -3);
976 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 4*h - 1, message);
977 rb->snprintf(str, 9, "$%d", amount);
978 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 3*h, str);
979 #if (CONFIG_KEYPAD == IPOD_4G_PAD) || \
980 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
981 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
982 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - h-2, " >>|: +1");
983 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 1, " |<<: -1");
984 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 + h, "SCROLL+: +10");
985 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 + 2*h + 1, "SCROLL-: -10");
986 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
987 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - h-2, "RIGHT: +1");
988 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 1, "LEFT: -1");
989 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 + h, "SCROLL+: +10");
990 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 + 2*h + 1, "SCROLL-: -10");
991 #else
992 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - h-2, "RIGHT: +1");
993 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 1, "LEFT: -1");
994 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 + h, "UP: +10");
995 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 + 2*h + 1, "DOWN: -10");
996 #endif
997 rb->lcd_update_rect(LCD_WIDTH/2 - 9*w - 2, LCD_HEIGHT/2 - 9*h/2, 37*w/2 + 1,
998 8*h-2);
999 #endif
1001 while(true) {
1002 button = rb->button_get(true);
1004 switch(button) {
1005 case BJACK_UP:
1006 case (BJACK_UP|BUTTON_REPEAT):
1007 if (amount + 10 < upper_limit + 1) {
1008 amount += 10;
1009 changed = true;
1011 break;
1012 case BJACK_DOWN:
1013 case (BJACK_DOWN|BUTTON_REPEAT):
1014 if (amount - 10 > lower_limit - 1) {
1015 amount -= 10;
1016 changed = true;
1018 break;
1019 case BJACK_RIGHT:
1020 case (BJACK_RIGHT|BUTTON_REPEAT):
1021 if (amount + 1 < upper_limit + 1) {
1022 amount++;
1023 changed = true;
1025 break;
1026 case BJACK_LEFT:
1027 case (BJACK_LEFT|BUTTON_REPEAT):
1028 if (amount - 1 > lower_limit - 1) {
1029 amount--;
1030 changed = true;
1032 break;
1033 case BJACK_MAX :
1034 amount = upper_limit;
1035 changed = true;
1036 break;
1037 case BJACK_MIN :
1038 amount = lower_limit;
1039 changed = true;
1040 break;
1041 case BJACK_QUIT:
1042 return 0;
1043 case BJACK_START:
1044 #if LCD_DEPTH > 1
1045 rb->lcd_set_foreground(FG_COLOR);
1046 rb->lcd_set_background(BG_COLOR);
1047 #endif
1048 rb->lcd_clear_display();
1049 return amount;
1052 if(changed) {
1053 rb->snprintf(str, 9, "$%d", amount);
1054 #if LCD_HEIGHT <= 64
1055 rb->lcd_puts(0, 2, str);
1056 rb->lcd_update();
1057 #else
1058 rb->lcd_set_drawmode(DRMODE_BG+DRMODE_INVERSEVID);
1059 rb->lcd_fillrect(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 3*h, 5*w, h);
1060 rb->lcd_set_drawmode(DRMODE_SOLID);
1061 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 3*h, str);
1062 rb->lcd_update_rect(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 3*h, 5*w, h);
1063 #endif
1064 changed = false;
1069 /*****************************************************************************
1070 * blackjack_get_bet() gets the player's bet.
1071 ******************************************************************************/
1072 static void blackjack_get_bet(struct game_context* bj) {
1073 bj->current_bet = blackjack_get_amount("Please enter a bet", 10,
1074 bj->player_money, bj->current_bet);
1077 /*****************************************************************************
1078 * double_down() returns one final card then finishes the game
1079 ******************************************************************************/
1080 static void double_down(struct game_context* bj) {
1081 bj->current_bet *= 2;
1082 bj->player_cards[0][bj->num_player_cards[0]] = new_card();
1083 bj->player_total += bj->player_cards[0][bj->num_player_cards[0]].value;
1084 bj->num_player_cards[0]++;
1087 /*****************************************************************************
1088 * split() checks if the player wants to split and acts accordingly.
1089 * When bj->split_status is 1, no split occurred. 2 means the player split and 3
1090 * means a split has already occurred and the first hand is done.
1091 ******************************************************************************/
1092 static void split(struct game_context* bj) {
1093 if (blackjack_get_yes_no("Split?") == 1)
1094 bj->split_status = 1;
1095 else {
1096 bj->split_status = 2;
1097 bj->current_bet *= 2;
1098 bj->num_player_cards[0] = 1;
1099 bj->num_player_cards[1] = 1;
1100 bj->player_cards[1][0] = bj->player_cards[0][1];
1101 bj->player_total = bj->player_cards[0][0].value;
1105 /*****************************************************************************
1106 * insurance() see if the player wants to buy insurance and how much.
1107 ******************************************************************************/
1108 static unsigned int insurance(struct game_context* bj) {
1109 unsigned int insurance, max_amount;
1111 insurance = blackjack_get_yes_no("Buy Insurance?");
1112 bj->asked_insurance = true;
1113 max_amount = bj->current_bet < (unsigned int)bj->player_money ?
1114 bj->current_bet/2 : (unsigned int)bj->player_money;
1115 if (insurance == 1) return 0;
1117 insurance = blackjack_get_amount("How much?", 0, max_amount, 0);
1118 redraw_board(bj);
1119 return insurance;
1122 /*****************************************************************************
1123 * play_again() checks to see if the player wants to keep playing.
1124 ******************************************************************************/
1125 static unsigned int play_again(void) {
1126 return blackjack_get_yes_no("Play Again?");
1129 /*****************************************************************************
1130 * blackjack_menu() is the initial menu at the start of the game.
1131 ******************************************************************************/
1132 static unsigned int blackjack_menu(struct game_context* bj) {
1133 int button;
1134 char *title = "Blackjack";
1135 char str[18];
1136 unsigned int i, w, h;
1137 bool breakout = false;
1138 bool showscores = false;
1140 while(true){
1141 #if LCD_DEPTH > 1
1142 rb->lcd_set_background(BG_COLOR);
1143 rb->lcd_set_foreground(FG_COLOR);
1144 #endif
1145 rb->lcd_clear_display();
1147 if(!showscores) {
1148 /* welcome screen to display key bindings */
1149 rb->lcd_getstringsize(title, &w, &h);
1150 rb->lcd_putsxy((LCD_WIDTH-w)/2, 0, title);
1152 #if CONFIG_KEYPAD == RECORDER_PAD
1153 rb->lcd_puts(0, 1, "ON: start");
1154 rb->lcd_puts(0, 2, "OFF: exit");
1155 rb->lcd_puts(0, 3, "F1: hit");
1156 rb->lcd_puts(0, 4, "F2: stay");
1157 rb->lcd_puts(0, 5, "F3: double down");
1158 rb->lcd_puts(0, 6, "PLAY: save/resume");
1159 rb->snprintf(str, 21, "High Score: $%d", bj->highscores[0]);
1160 rb->lcd_puts(0, 7, str);
1161 #elif CONFIG_KEYPAD == ONDIO_PAD
1162 rb->lcd_puts(0, 1, "MENU: start");
1163 rb->lcd_puts(0, 2, "OFF: exit");
1164 rb->lcd_puts(0, 3, "LEFT: hit");
1165 rb->lcd_puts(0, 4, "RIGHT: stay");
1166 rb->lcd_puts(0, 5, "UP: double down");
1167 rb->lcd_puts(0, 6, "DOWN: save/resume");
1168 rb->snprintf(str, 21, "High Score: $%d", bj->highscores[0]);
1169 rb->lcd_puts(0, 7, str);
1170 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || (CONFIG_KEYPAD == IRIVER_H300_PAD)
1171 rb->lcd_puts(0, 2, "PLAY to start & to hit");
1172 rb->lcd_puts(0, 3, "STOP to exit");
1173 rb->lcd_puts(0, 4, "REC to stay");
1174 rb->lcd_puts(0, 5, "NAVI to double down ");
1175 rb->lcd_puts(0, 6, " & to view highscores");
1176 rb->lcd_puts(0, 7, "AB to save/resume");
1177 rb->snprintf(str, 21, "High Score: $%d", bj->highscores[0]);
1178 rb->lcd_puts(0, 8, str);
1179 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
1180 rb->lcd_puts(0, 2, "PLAY to start & hit");
1181 rb->lcd_puts(0, 3, "POWER to exit");
1182 rb->lcd_puts(0, 4, ">>| to stay");
1183 rb->lcd_puts(0, 5, "|<< to double down");
1184 rb->lcd_puts(0, 6, "LEFT to view scores");
1185 rb->lcd_puts(0, 7, "RIGHT to save/resume");
1186 rb->snprintf(str, 21, "High Score: $%d", bj->highscores[0]);
1187 rb->lcd_puts(0, 8, str);
1189 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \
1190 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
1191 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
1192 #if LCD_WIDTH >=176
1193 rb->lcd_puts(0, 2, "SELECT to start & to hit");
1194 rb->lcd_puts(0, 3, "MENU to exit");
1195 rb->lcd_puts(0, 4, ">>| to stay & to view highscores");
1196 rb->lcd_puts(0, 5, "|<< to double down");
1197 rb->lcd_puts(0, 6, "PLAY to save/resume");
1198 rb->snprintf(str, 21, "High Score: $%d", bj->highscores[0]);
1199 rb->lcd_puts(0, 7, str);
1200 #else
1201 rb->lcd_puts(0, 2, "SELECT to start & to ");
1202 rb->lcd_puts(0, 3, " hit");
1203 rb->lcd_puts(0, 4, "MENU to exit");
1204 rb->lcd_puts(0, 5, ">>| to stay & to view ");
1205 rb->lcd_puts(0, 6, " highscores");
1206 rb->lcd_puts(0, 7, "|<< to double down");
1207 rb->lcd_puts(0, 8, "PLAY to save/resume");
1208 rb->snprintf(str, 21, "High Score: $%d", bj->highscores[0]);
1209 rb->lcd_puts(0, 9, str);
1210 #endif
1211 #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD
1212 rb->lcd_puts(0, 2, "PLAY to start to hit");
1213 rb->lcd_puts(0, 3, "POWER to exit");
1214 rb->lcd_puts(0, 4, "SELECT to hit");
1215 rb->lcd_puts(0, 5, "REC to stay");
1216 rb->lcd_puts(0, 6, "PLAY to double down");
1217 rb->lcd_puts(0, 7, "RIGHT to view highscores ");
1218 rb->lcd_puts(0, 8, "DOWN to save/resume");
1219 rb->snprintf(str, 21, "High Score: $%d", bj->highscores[0]);
1220 rb->lcd_puts(0, 9, str);
1221 #elif CONFIG_KEYPAD == IRIVER_IFP7XX_PAD
1222 rb->lcd_puts(0, 2, "AB to start & to");
1223 rb->lcd_puts(0, 3, " stay");
1224 rb->lcd_puts(0, 4, "EQ to hit");
1225 rb->lcd_puts(0, 5, "PLAY to exit");
1226 rb->lcd_puts(0, 6, "CLICK to double down");
1227 rb->lcd_puts(0, 7, "& to view highscores");
1228 rb->lcd_puts(0, 8, "AB+EQ to save/resume");
1229 rb->snprintf(str, 21, "High Score: $%d", bj->highscores[0]);
1230 rb->lcd_puts(0, 9, str);
1231 #elif CONFIG_KEYPAD == GIGABEAT_PAD
1232 rb->lcd_puts(0, 2, "A to start");
1233 rb->lcd_puts(0, 3, "POWER to exit");
1234 rb->lcd_puts(0, 4, "VOL+ to hit");
1235 rb->lcd_puts(0, 5, "VOL- to stay");
1236 rb->lcd_puts(0, 6, "CENTER to double down");
1237 rb->lcd_puts(0, 6, "RIGHT to view highscores ");
1238 rb->lcd_puts(0, 8, "MENU to save/resume");
1239 rb->snprintf(str, 21, "High Score: $%d", bj->highscores[0]);
1240 rb->lcd_puts(0, 9, str);
1241 #elif CONFIG_KEYPAD == MROBE100_PAD
1242 rb->lcd_puts(0, 2, "CENTER to start");
1243 rb->lcd_puts(0, 3, "POWER to exit");
1244 rb->lcd_puts(0, 4, "MENU to hit");
1245 rb->lcd_puts(0, 5, "DISPLAY to stay");
1246 rb->lcd_puts(0, 6, "DOWN to double down");
1247 rb->lcd_puts(0, 6, "RIGHT to view highscores ");
1248 rb->lcd_puts(0, 8, "PLAY to save/resume");
1249 rb->snprintf(str, 21, "High Score: $%d", bj->highscores[0]);
1250 rb->lcd_puts(0, 9, str);
1251 #elif (CONFIG_KEYPAD == SANSA_E200_PAD)
1252 rb->lcd_puts(0, 2, "SELECT to start & to hit");
1253 rb->lcd_puts(0, 3, "POWER to exit");
1254 rb->lcd_puts(0, 4, "RIGHT to stay");
1255 rb->lcd_puts(0, 5, "LEFT to double down");
1256 rb->lcd_puts(0, 6, "REC to save/resume");
1257 rb->lcd_puts(0, 7, "UP to view scores");
1258 rb->snprintf(str, 21, "High Score: $%d", bj->highscores[0]);
1259 rb->lcd_puts(0, 8, str);
1260 #elif (CONFIG_KEYPAD == SANSA_C200_PAD)
1261 rb->lcd_puts(0, 2, "SELECT to start & to hit");
1262 rb->lcd_puts(0, 3, "POWER to exit");
1263 rb->lcd_puts(0, 4, "RIGHT to stay");
1264 rb->lcd_puts(0, 5, "LEFT to double down");
1265 rb->lcd_puts(0, 6, "DOWN to save/resume");
1266 rb->lcd_puts(0, 7, "REC to view scores");
1267 rb->snprintf(str, 21, "High Score: $%d", bj->highscores[0]);
1268 rb->lcd_puts(0, 9, str);
1269 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
1270 rb->lcd_puts(0, 2, "PLAY to start & to");
1271 rb->lcd_puts(0, 3, " hit");
1272 rb->lcd_puts(0, 4, "REC to exit");
1273 rb->lcd_puts(0, 5, "FF to stay");
1274 rb->lcd_puts(0, 6, "REW to double down");
1275 rb->lcd_puts(0, 7, "MODE to save/resume");
1276 rb->lcd_puts(0, 8, "MENU to view scores");
1277 rb->snprintf(str, 21, "High Score: $%d", bj->highscores[0]);
1278 rb->lcd_puts(0, 10, str);
1279 #elif CONFIG_KEYPAD == COWOND2_PAD
1280 rb->lcd_puts(0, 6, "POWER to exit");
1281 rb->lcd_puts(0, 7, "MINUS to double down");
1282 rb->lcd_puts(0, 8, "MENU to view scores");
1283 rb->snprintf(str, 21, "High Score: $%d", bj->highscores[0]);
1284 rb->lcd_puts(0, 10, str);
1285 #endif
1287 #ifdef HAVE_TOUCHSCREEN
1288 rb->lcd_puts(0, 2, "LCD CENTRE to start & to hit");
1289 rb->lcd_puts(0, 3, "LCD BOTTOMLEFT to stay");
1290 rb->lcd_puts(0, 4, "LCD BOTTOMRIGHT to save/resume");
1291 #endif
1292 } else {
1293 rb->snprintf(str, 12, "%s", "High Scores");
1294 rb->lcd_getstringsize(str, &w, &h);
1295 rb->lcd_putsxy((LCD_WIDTH-w)/2, 0, str);
1297 /* print high scores */
1298 for(i=0; i<NUM_SCORES; i++) {
1299 rb->snprintf(str, 14, "#%02d: $%d", i+1, bj->highscores[i]);
1300 rb->lcd_puts(0, i+1, str);
1304 rb->lcd_update();
1306 /* handle menu button presses */
1307 button = rb->button_get(true);
1309 switch(button) {
1310 case BJACK_START: /* start playing */
1311 breakout = true;
1312 break;
1314 case BJACK_QUIT: /* quit program */
1315 if(showscores) {
1316 showscores = 0;
1317 break;
1319 return BJ_QUIT;
1321 case BJACK_RESUME:/* resume game */
1322 if(!blackjack_loadgame(bj)) {
1323 rb->splash(HZ*2, "Nothing to resume");
1324 } else {
1325 rb->splash(HZ*2, "Loading...");
1326 breakout = true;
1328 break;
1330 case BJACK_SCORES:/* toggle high scores */
1331 showscores = !showscores;
1332 break;
1334 default:
1335 if(rb->default_event_handler_ex(button, blackjack_callback,
1336 (void*) bj) == SYS_USB_CONNECTED)
1337 return BJ_USB;
1338 break;
1341 if(breakout) break;
1344 return(0);
1347 /*****************************************************************************
1348 * blackjack() is the main game subroutine, it returns the final game status.
1349 ******************************************************************************/
1350 static int blackjack(struct game_context* bj) {
1351 int button;
1352 unsigned int w, h, temp_var, done = 0, todo = 1;
1353 signed int temp;
1354 bool breakout = false;
1355 bool dbl_down = false;
1357 /* don't resume by default */
1358 bj->resume = false;
1360 /********************
1361 * menu *
1362 ********************/
1363 temp_var = blackjack_menu(bj);
1364 if (temp_var == BJ_QUIT || temp_var == BJ_USB)
1365 return temp_var;
1368 /********************
1369 * init *
1370 ********************/
1371 blackjack_init(bj);
1372 bj->current_bet=10;
1374 /********************
1375 * play *
1376 ********************/
1378 /* check for resumed game */
1379 if(bj->resume) {
1380 bj->resume = false;
1381 redraw_board(bj);
1382 if (bj->split_status == 2) {
1383 todo=2;
1384 player_x = bj->num_player_cards[0] * 10 + 4;
1386 else if (bj->split_status == 3) {
1387 player_x = bj->num_player_cards[1] * 10 + LCD_WIDTH/2 + 4;
1388 todo=2;
1389 done=1;
1393 else {
1394 bj->player_money = 1000;
1395 blackjack_get_bet(bj);
1396 if (bj->current_bet == 0)
1397 return BJ_QUIT;
1398 rb->lcd_clear_display();
1399 deal_init_cards(bj);
1400 blackjack_drawtable(bj);
1403 rb->lcd_update();
1405 breakout = false;
1407 while(true){
1408 if(bj->player_total == 21 && bj->num_player_cards[0] == 2) {
1409 bj->is_blackjack = true;
1410 bj->end_hand = true;
1411 finish_game(bj);
1413 else if(bj->dealer_cards[1].is_soft_ace && !breakout &&
1414 !bj->asked_insurance) {
1415 temp_var = insurance(bj);
1416 if (bj->dealer_total == 21) {
1417 rb->splash(HZ, "Dealer has blackjack");
1418 bj->player_money += temp_var;
1419 bj->end_hand = true;
1420 breakout = true;
1421 redraw_board(bj);
1422 finish_game(bj);
1424 else {
1425 rb->splash(HZ, "Dealer does not have blackjack");
1426 bj->player_money -= temp_var;
1427 breakout = true;
1428 redraw_board(bj);
1429 rb->lcd_update();
1432 if(!bj->end_hand && bj->split_status == 0 &&
1433 bj->player_cards[0][0].num == bj->player_cards[0][1].num) {
1434 split(bj);
1435 redraw_board(bj);
1436 rb->lcd_update_rect(0, LCD_HEIGHT/2, LCD_WIDTH, LCD_HEIGHT/2);
1437 if (bj->split_status == 2) {
1438 todo++;
1439 player_x = bj->num_player_cards[0] * 10 + 4;
1443 while(!bj->end_hand && done < todo) {
1444 button = rb->button_get(true);
1446 switch(button) {
1447 case BJACK_HIT:
1448 NEXT_CARD = new_card();
1449 bj->player_total += NEXT_CARD.value;
1450 draw_card(NEXT_CARD, true, player_x, player_y);
1451 bj->num_player_cards[done]++;
1452 if (bj->num_player_cards[done] == MAX_CARDS + 1) {
1453 redraw_board(bj);
1454 rb->lcd_update_rect(0, LCD_HEIGHT/2, LCD_WIDTH,
1455 LCD_HEIGHT/2);
1457 else if (bj->num_player_cards[done]>MAX_CARDS || todo > 1) {
1458 rb->lcd_update_rect(player_x, player_y, CARD_WIDTH+2,
1459 CARD_HEIGHT+2);
1460 player_x += 10;
1462 else {
1463 rb->lcd_update_rect(player_x, player_y, CARD_WIDTH+2,
1464 CARD_HEIGHT+2);
1465 player_x += CARD_WIDTH + 4;
1467 update_total(bj);
1469 break;
1470 case BJACK_STAY:
1471 bj->end_hand = true;
1472 break;
1473 case BJACK_DOUBLEDOWN:
1474 if ((signed int)bj->current_bet * 2 < bj->player_money + 1 &&
1475 bj->num_player_cards[0]==2 && todo==1) {
1476 double_down(bj);
1477 dbl_down = true;
1478 if (bj->player_total < 22) {
1479 bj->end_hand = true;
1480 finish_game(bj);
1483 else if((signed int)bj->current_bet * 2 > bj->player_money) {
1484 rb->splash(HZ, "Not enough money to double down.");
1485 redraw_board(bj);
1486 rb->lcd_update();
1488 break;
1489 case BJACK_RESUME: /* save and end game */
1490 rb->splash(HZ, "Saving game...");
1491 blackjack_savegame(bj);
1492 /* fall through to BJACK_QUIT */
1494 case BJACK_QUIT:
1495 return BJ_END;
1498 while (bj->player_total > 21 && !bj->end_hand) {
1499 temp = check_for_aces(bj->player_cards[done],
1500 bj->num_player_cards[done]);
1501 if(temp != -1) {
1502 bj->player_cards[done][temp].is_soft_ace = false;
1503 bj->player_total -= 10;
1504 update_total(bj);
1505 if (dbl_down) {
1506 bj->end_hand = true;
1507 finish_game(bj);
1510 else
1511 bj->end_hand = true;
1514 if (bj->end_hand) {
1515 done++;
1516 if(todo > 1) {
1517 if (done == 2) {
1518 temp = bj->player_total;
1519 bj->player_total = temp_var;
1520 temp_var = temp;
1521 finish_game(bj);
1522 rb->lcd_getstringsize(" Split 1 ", &w, &h);
1523 rb->lcd_putsxy(LCD_WIDTH/2-w/2, LCD_HEIGHT/2-3*h/2,
1524 " Split 1 ");
1525 rb->lcd_update_rect(LCD_WIDTH/2-w/2, LCD_HEIGHT/2-3*h/2,
1526 w,h);
1527 bj->current_bet /= 2;
1528 rb->lcd_update_rect(LCD_WIDTH/2-w/2, LCD_HEIGHT/2-3*h/2,
1529 w,h);
1530 rb->sleep(HZ*2);
1531 bj->player_total = temp_var;
1532 finish_game(bj);
1533 rb->lcd_getstringsize(" Split 2 ", &w, &h);
1534 rb->lcd_putsxy(LCD_WIDTH/2-w/2, LCD_HEIGHT/2-3*h/2,
1535 " Split 2 ");
1536 rb->lcd_update_rect(LCD_WIDTH/2-w/2, LCD_HEIGHT/2-3*h/2,
1537 w,h);
1538 rb->sleep(HZ*2);
1540 else {
1541 bj->end_hand = false;
1542 bj->split_status = 3;
1543 temp_var = bj->player_total;
1544 bj->player_total = bj->player_cards[1][0].value;
1545 update_total(bj);
1546 redraw_board(bj);
1547 player_x += 10;
1548 rb->lcd_update();
1551 else
1552 finish_game(bj);
1556 if (bj->player_money < 10) {
1557 rb->sleep(HZ);
1558 return BJ_LOSE;
1561 if (bj->end_hand) { /* If hand is over */
1562 if (play_again() != 0) /* User wants to quit */
1563 return BJ_END;
1564 else { /* User keeps playing */
1565 breakout = false;
1566 redraw_board(bj);
1567 if(dbl_down) {
1568 bj->current_bet /= 2;
1569 dbl_down = false;
1571 done = 0;
1572 todo = 1;
1573 blackjack_init(bj);
1574 blackjack_get_bet(bj);
1575 if (bj->current_bet == 0)
1576 return BJ_END;
1577 deal_init_cards(bj);
1578 blackjack_drawtable(bj);
1579 rb->lcd_update();
1583 /* Never reached */
1584 return PLUGIN_OK;
1587 /*****************************************************************************
1588 * plugin entry point.
1589 ******************************************************************************/
1590 enum plugin_status plugin_start(const struct plugin_api* api, const void* parameter)
1592 struct game_context bj;
1593 bool exit = false;
1594 unsigned int position;
1595 char str[19];
1597 (void)parameter;
1598 rb = api;
1600 #if LCD_DEPTH > 1
1601 rb->lcd_set_backdrop(NULL);
1602 #endif
1604 /* load high scores */
1605 blackjack_loadscores(&bj);
1607 rb->lcd_setfont(FONT_SYSFIXED);
1609 while(!exit) {
1610 switch(blackjack(&bj)){
1611 case BJ_LOSE:
1612 rb->splash(HZ, "Not enough money to continue");
1613 /* fall through to BJ_END */
1615 case BJ_END:
1616 if(!bj.resume) {
1617 if((position = blackjack_recordscore(&bj))) {
1618 rb->snprintf(str, 19, "New high score #%d!", position);
1619 rb->splash(HZ*2, str);
1622 break;
1624 case BJ_USB:
1625 rb->lcd_setfont(FONT_UI);
1626 return PLUGIN_USB_CONNECTED;
1628 case BJ_QUIT:
1629 if(bj.dirty) {
1630 rb->splash(HZ, "Saving high scores...");
1631 blackjack_savescores(&bj);
1633 exit = true;
1634 break;
1636 default:
1637 break;
1641 rb->lcd_setfont(FONT_UI);
1642 return PLUGIN_OK;