Fix wpsbuild.pl so that rockbox_default wps is built
[kugel-rb.git] / apps / plugins / blackjack.c
bloba7876c6e12ba8ae2868277c48eaf21098fe0ce3d
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2006 Tom Ross
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
22 #include "plugin.h"
23 #include "pluginbitmaps/card_deck.h"
24 #include "pluginbitmaps/card_back.h"
25 #include "lib/display_text.h"
26 #include "lib/highscore.h"
27 #include "lib/playback_control.h"
29 PLUGIN_HEADER
31 /* save files */
32 #define HIGH_SCORE PLUGIN_GAMES_DIR "/blackjack.score"
33 #define SAVE_FILE PLUGIN_GAMES_DIR "/blackjack.save"
34 #define NUM_SCORES 5
36 /* final game return status */
37 enum {
38 BJ_LOSE,
39 BJ_QUIT_WITHOUT_SAVING,
40 BJ_QUIT,
41 BJ_USB,
42 BJ_END,
45 #if CONFIG_KEYPAD == RECORDER_PAD
46 #define BJACK_SELECT_NAME "PLAY"
47 #define BJACK_STAY_NAME "F1"
48 #define BJACK_QUIT_NAME "OFF"
49 #define BJACK_DOUBLE_NAME "F2"
50 #define BJACK_SELECT BUTTON_PLAY
51 #define BJACK_QUIT BUTTON_OFF
52 #define BJACK_MAX (BUTTON_ON|BUTTON_UP)
53 #define BJACK_MIN (BUTTON_ON|BUTTON_DOWN)
54 #define BJACK_STAY BUTTON_F1
55 #define BJACK_DOUBLEDOWN BUTTON_F2
56 #define BJACK_UP BUTTON_UP
57 #define BJACK_DOWN BUTTON_DOWN
58 #define BJACK_RIGHT BUTTON_RIGHT
59 #define BJACK_LEFT BUTTON_LEFT
61 #elif CONFIG_KEYPAD == ONDIO_PAD
62 #define BJACK_SELECT_NAME "MENU"
63 #define BJACK_STAY_NAME "RIGHT"
64 #define BJACK_QUIT_NAME "OFF"
65 #define BJACK_DOUBLE_NAME "UP"
66 #define BJACK_SELECT BUTTON_MENU
67 #define BJACK_QUIT BUTTON_OFF
68 #define BJACK_STAY BUTTON_RIGHT
69 #define BJACK_DOUBLEDOWN BUTTON_UP
70 #define BJACK_UP BUTTON_UP
71 #define BJACK_DOWN BUTTON_DOWN
72 #define BJACK_RIGHT BUTTON_RIGHT
73 #define BJACK_LEFT BUTTON_LEFT
75 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
76 #define BJACK_SELECT_NAME "PLAY"
77 #define BJACK_STAY_NAME ">>|"
78 #define BJACK_QUIT_NAME "POWER"
79 #define BJACK_DOUBLE_NAME "|<<"
80 #define BJACK_SELECT BUTTON_PLAY
81 #define BJACK_QUIT BUTTON_POWER
82 #define BJACK_STAY BUTTON_FF
83 #define BJACK_DOUBLEDOWN BUTTON_REW
84 #define BJACK_UP BUTTON_SCROLL_UP
85 #define BJACK_DOWN BUTTON_SCROLL_DOWN
86 #define BJACK_RIGHT BUTTON_RIGHT
87 #define BJACK_LEFT BUTTON_LEFT
89 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
90 (CONFIG_KEYPAD == IRIVER_H300_PAD)
91 #define BJACK_SELECT_NAME "ON"
92 #define BJACK_STAY_NAME "REC"
93 #define BJACK_QUIT_NAME "OFF"
94 #define BJACK_DOUBLE_NAME "SELECT"
95 #define BJACK_SELECT BUTTON_ON
96 #define BJACK_QUIT BUTTON_OFF
97 #define BJACK_STAY BUTTON_REC
98 #define BJACK_DOUBLEDOWN BUTTON_SELECT
99 #define BJACK_UP BUTTON_UP
100 #define BJACK_DOWN BUTTON_DOWN
101 #define BJACK_RIGHT BUTTON_RIGHT
102 #define BJACK_LEFT BUTTON_LEFT
104 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \
105 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
106 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
107 #define BJACK_SELECT_NAME "SELECT"
108 #define BJACK_STAY_NAME "RIGHT"
109 #define BJACK_RESUME_NAME "PLAY"
110 #define BJACK_QUIT_NAME "MENU"
111 #define BJACK_DOUBLE_NAME "LEFT"
112 #define BJACK_SELECT BUTTON_SELECT
113 #define BJACK_QUIT BUTTON_MENU
114 #define BJACK_STAY BUTTON_RIGHT
115 #define BJACK_DOUBLEDOWN BUTTON_LEFT
116 #define BJACK_UP BUTTON_SCROLL_FWD
117 #define BJACK_DOWN BUTTON_SCROLL_BACK
118 #define BJACK_RIGHT BUTTON_RIGHT
119 #define BJACK_LEFT BUTTON_LEFT
121 #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD
122 #define BJACK_SELECT_NAME "SELECT"
123 #define BJACK_STAY_NAME "REC"
124 #define BJACK_QUIT_NAME "POWER"
125 #define BJACK_DOUBLE_NAME "PLAY"
126 #define BJACK_SELECT BUTTON_SELECT
127 #define BJACK_QUIT BUTTON_POWER
128 #define BJACK_MAX (BUTTON_PLAY|BUTTON_UP)
129 #define BJACK_MIN (BUTTON_PLAY|BUTTON_DOWN)
130 #define BJACK_STAY BUTTON_REC
131 #define BJACK_DOUBLEDOWN BUTTON_PLAY
132 #define BJACK_UP BUTTON_UP
133 #define BJACK_DOWN BUTTON_DOWN
134 #define BJACK_RIGHT BUTTON_RIGHT
135 #define BJACK_LEFT BUTTON_LEFT
137 #elif CONFIG_KEYPAD == IRIVER_IFP7XX_PAD
138 #define BJACK_SELECT_NAME "MODE"
139 #define BJACK_STAY_NAME "MODE"
140 #define BJACK_QUIT_NAME "PLAY"
141 #define BJACK_DOUBLE_NAME "SELECT"
142 #define BJACK_SELECT BUTTON_MODE
143 #define BJACK_QUIT BUTTON_PLAY
144 #define BJACK_MAX (BUTTON_EQ|BUTTON_UP)
145 #define BJACK_MIN (BUTTON_EQ|BUTTON_DOWN)
146 #define BJACK_STAY BUTTON_MODE
147 #define BJACK_DOUBLEDOWN BUTTON_SELECT
148 #define BJACK_UP BUTTON_UP
149 #define BJACK_DOWN BUTTON_DOWN
150 #define BJACK_RIGHT BUTTON_RIGHT
151 #define BJACK_LEFT BUTTON_LEFT
153 #elif CONFIG_KEYPAD == GIGABEAT_PAD
154 #define BJACK_SELECT_NAME "SELECT"
155 #define BJACK_STAY_NAME "VOL-"
156 #define BJACK_QUIT_NAME "POWER"
157 #define BJACK_DOUBLE_NAME "A"
158 #define BJACK_SELECT BUTTON_SELECT
159 #define BJACK_QUIT BUTTON_POWER
160 #define BJACK_MAX BUTTON_VOL_UP
161 #define BJACK_MIN BUTTON_VOL_DOWN
162 #define BJACK_STAY BUTTON_VOL_DOWN
163 #define BJACK_DOUBLEDOWN BUTTON_A
164 #define BJACK_UP BUTTON_UP
165 #define BJACK_DOWN BUTTON_DOWN
166 #define BJACK_RIGHT BUTTON_RIGHT
167 #define BJACK_LEFT BUTTON_LEFT
169 #elif CONFIG_KEYPAD == SANSA_E200_PAD
170 #define BJACK_SELECT_NAME "SELECT"
171 #define BJACK_STAY_NAME "RIGHT"
172 #define BJACK_QUIT_NAME "POWER"
173 #define BJACK_DOUBLE_NAME "LEFT"
174 #define BJACK_SELECT BUTTON_SELECT
175 #define BJACK_QUIT BUTTON_POWER
176 #define BJACK_MAX BUTTON_UP
177 #define BJACK_MIN BUTTON_DOWN
178 #define BJACK_STAY BUTTON_RIGHT
179 #define BJACK_DOUBLEDOWN BUTTON_LEFT
180 #define BJACK_UP BUTTON_SCROLL_FWD
181 #define BJACK_DOWN BUTTON_SCROLL_BACK
182 #define BJACK_RIGHT BUTTON_RIGHT
183 #define BJACK_LEFT BUTTON_LEFT
185 #elif CONFIG_KEYPAD == SANSA_FUZE_PAD
186 #define BJACK_SELECT_NAME "SELECT"
187 #define BJACK_STAY_NAME "RIGHT"
188 #define BJACK_QUIT_NAME "HOME"
189 #define BJACK_DOUBLE_NAME "LEFT"
190 #define BJACK_SELECT BUTTON_SELECT
191 #define BJACK_QUIT (BUTTON_HOME|BUTTON_REPEAT)
192 #define BJACK_MAX BUTTON_UP
193 #define BJACK_MIN BUTTON_DOWN
194 #define BJACK_STAY BUTTON_RIGHT
195 #define BJACK_DOUBLEDOWN BUTTON_LEFT
196 #define BJACK_UP BUTTON_SCROLL_FWD
197 #define BJACK_DOWN BUTTON_SCROLL_BACK
198 #define BJACK_RIGHT BUTTON_RIGHT
199 #define BJACK_LEFT BUTTON_LEFT
201 #elif CONFIG_KEYPAD == SANSA_C200_PAD
202 #define BJACK_SELECT_NAME "SELECT"
203 #define BJACK_STAY_NAME "RIGHT"
204 #define BJACK_QUIT_NAME "POWER"
205 #define BJACK_DOUBLE_NAME "LEFT"
206 #define BJACK_SELECT BUTTON_SELECT
207 #define BJACK_QUIT BUTTON_POWER
208 #define BJACK_MAX BUTTON_VOL_UP
209 #define BJACK_MIN BUTTON_VOL_DOWN
210 #define BJACK_STAY BUTTON_RIGHT
211 #define BJACK_DOUBLEDOWN BUTTON_LEFT
212 #define BJACK_UP BUTTON_UP
213 #define BJACK_DOWN BUTTON_DOWN
214 #define BJACK_RIGHT BUTTON_RIGHT
215 #define BJACK_LEFT BUTTON_LEFT
217 #elif CONFIG_KEYPAD == SANSA_CLIP_PAD
218 #define BJACK_SELECT_NAME "SELECT"
219 #define BJACK_STAY_NAME "RIGHT"
220 #define BJACK_QUIT_NAME "POWER"
221 #define BJACK_DOUBLE_NAME "LEFT"
222 #define BJACK_SELECT BUTTON_SELECT
223 #define BJACK_QUIT BUTTON_POWER
224 #define BJACK_MAX BUTTON_VOL_UP
225 #define BJACK_MIN BUTTON_VOL_DOWN
226 #define BJACK_STAY BUTTON_RIGHT
227 #define BJACK_DOUBLEDOWN BUTTON_LEFT
228 #define BJACK_UP BUTTON_UP
229 #define BJACK_DOWN BUTTON_DOWN
230 #define BJACK_RIGHT BUTTON_RIGHT
231 #define BJACK_LEFT BUTTON_LEFT
233 #elif CONFIG_KEYPAD == SANSA_M200_PAD
234 #define BJACK_SELECT_NAME "SELECT"
235 #define BJACK_STAY_NAME "RIGHT"
236 #define BJACK_QUIT_NAME "POWER"
237 #define BJACK_DOUBLE_NAME "LEFT"
238 #define BJACK_SELECT (BUTTON_SELECT | BUTTON_REL)
239 #define BJACK_QUIT BUTTON_POWER
240 #define BJACK_MAX BUTTON_VOL_UP
241 #define BJACK_MIN BUTTON_VOL_DOWN
242 #define BJACK_STAY BUTTON_RIGHT
243 #define BJACK_DOUBLEDOWN BUTTON_LEFT
244 #define BJACK_UP BUTTON_UP
245 #define BJACK_DOWN BUTTON_DOWN
246 #define BJACK_RIGHT BUTTON_RIGHT
247 #define BJACK_LEFT BUTTON_LEFT
249 #elif CONFIG_KEYPAD == TATUNG_TPJ1022_PAD
250 #define BJACK_SELECT_NAME "MAIN"
251 #define BJACK_STAY_NAME "MENU"
252 #define BJACK_QUIT_NAME "POWER"
253 #define BJACK_DOUBLE_NAME "DOWN"
254 #define BJACK_SELECT BUTTON_MAIN
255 #define BJACK_QUIT BUTTON_POWER
256 #define BJACK_MAX (BUTTON_REC|BUTTON_UP)
257 #define BJACK_MIN (BUTTON_REC|BUTTON_DOWN)
258 #define BJACK_STAY BUTTON_MENU
259 #define BJACK_DOUBLEDOWN BUTTON_DOWN
260 #define BJACK_UP BUTTON_UP
261 #define BJACK_DOWN BUTTON_DOWN
262 #define BJACK_RIGHT BUTTON_RIGHT
263 #define BJACK_LEFT BUTTON_LEFT
265 #elif CONFIG_KEYPAD == GIGABEAT_S_PAD
266 #define BJACK_SELECT_NAME "PLAY"
267 #define BJACK_STAY_NAME "VOL-"
268 #define BJACK_QUIT_NAME "BACK"
269 #define BJACK_DOUBLE_NAME "SELECT"
270 #define BJACK_SELECT BUTTON_PLAY
271 #define BJACK_QUIT BUTTON_BACK
272 #define BJACK_MAX BUTTON_VOL_UP
273 #define BJACK_MIN BUTTON_VOL_DOWN
274 #define BJACK_STAY BUTTON_VOL_DOWN
275 #define BJACK_DOUBLEDOWN BUTTON_SELECT
276 #define BJACK_UP BUTTON_UP
277 #define BJACK_DOWN BUTTON_DOWN
278 #define BJACK_RIGHT BUTTON_RIGHT
279 #define BJACK_LEFT BUTTON_LEFT
281 #elif CONFIG_KEYPAD == MROBE100_PAD
282 #define BJACK_SELECT_NAME "SELECT"
283 #define BJACK_STAY_NAME "DISPLAY"
284 #define BJACK_QUIT_NAME "POWER"
285 #define BJACK_DOUBLE_NAME "DOWN"
286 #define BJACK_SELECT BUTTON_SELECT
287 #define BJACK_QUIT BUTTON_POWER
288 #define BJACK_MAX BUTTON_MENU
289 #define BJACK_MIN BUTTON_DISPLAY
290 #define BJACK_STAY BUTTON_DISPLAY
291 #define BJACK_DOUBLEDOWN BUTTON_DOWN
292 #define BJACK_UP BUTTON_UP
293 #define BJACK_DOWN BUTTON_DOWN
294 #define BJACK_RIGHT BUTTON_RIGHT
295 #define BJACK_LEFT BUTTON_LEFT
297 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
298 #define BJACK_SELECT_NAME "RC","PLAY"
299 #define BJACK_STAY_NAME "RC", ">>|"
300 #define BJACK_QUIT_NAME "RC_REC"
301 #define BJACK_DOUBLE_NAME "RC_REW"
302 #define BJACK_SELECT BUTTON_RC_PLAY
303 #define BJACK_QUIT BUTTON_RC_REC
304 #define BJACK_STAY BUTTON_RC_FF
305 #define BJACK_DOUBLEDOWN BUTTON_RC_REW
306 #define BJACK_UP BUTTON_RC_VOL_UP
307 #define BJACK_DOWN BUTTON_RC_VOL_DOWN
308 #define BJACK_RIGHT BUTTON_RC_FF
309 #define BJACK_LEFT BUTTON_RC_REW
311 #elif CONFIG_KEYPAD == COWON_D2_PAD
312 #define BJACK_QUIT_NAME "POWER"
313 #define BJACK_DOUBLE_NAME "-"
314 #define BJACK_QUIT BUTTON_POWER
315 #define BJACK_DOUBLEDOWN BUTTON_MINUS
317 #elif CONFIG_KEYPAD == CREATIVEZVM_PAD
318 #define BJACK_SELECT_NAME "SELECT"
319 #define BJACK_STAY_NAME "PLAY"
320 #define BJACK_QUIT_NAME "POWER"
321 #define BJACK_DOUBLE_NAME "CUSTOM"
322 #define BJACK_SELECT BUTTON_SELECT
323 #define BJACK_QUIT BUTTON_POWER
324 #define BJACK_STAY BUTTON_PLAY
325 #define BJACK_MAX (BUTTON_CUSTOM|BUTTON_UP)
326 #define BJACK_MIN (BUTTON_CUSTOM|BUTTON_DOWN)
327 #define BJACK_DOUBLEDOWN BUTTON_CUSTOM
328 #define BJACK_UP BUTTON_UP
329 #define BJACK_DOWN BUTTON_DOWN
330 #define BJACK_RIGHT BUTTON_RIGHT
331 #define BJACK_LEFT BUTTON_LEFT
333 #elif CONFIG_KEYPAD == PHILIPS_HDD1630_PAD
334 #define BJACK_SELECT_NAME "SELECT"
335 #define BJACK_STAY_NAME "VOL-"
336 #define BJACK_QUIT_NAME "POWER"
337 #define BJACK_DOUBLE_NAME "MENU"
338 #define BJACK_SELECT BUTTON_SELECT
339 #define BJACK_QUIT BUTTON_POWER
340 #define BJACK_MAX BUTTON_VOL_UP
341 #define BJACK_MIN BUTTON_VOL_DOWN
342 #define BJACK_STAY BUTTON_VOL_DOWN
343 #define BJACK_DOUBLEDOWN BUTTON_MENU
344 #define BJACK_UP BUTTON_UP
345 #define BJACK_DOWN BUTTON_DOWN
346 #define BJACK_RIGHT BUTTON_RIGHT
347 #define BJACK_LEFT BUTTON_LEFT
349 #elif CONFIG_KEYPAD == PHILIPS_SA9200_PAD
350 #define BJACK_SELECT_NAME "MENU"
351 #define BJACK_STAY_NAME "VOL-"
352 #define BJACK_QUIT_NAME "POWER"
353 #define BJACK_DOUBLE_NAME "PLAY"
354 #define BJACK_SELECT BUTTON_MENU
355 #define BJACK_QUIT BUTTON_POWER
356 #define BJACK_MAX BUTTON_VOL_UP
357 #define BJACK_MIN BUTTON_VOL_DOWN
358 #define BJACK_STAY BUTTON_VOL_DOWN
359 #define BJACK_DOUBLEDOWN BUTTON_PLAY
360 #define BJACK_UP BUTTON_UP
361 #define BJACK_DOWN BUTTON_DOWN
362 #define BJACK_RIGHT BUTTON_NEXT
363 #define BJACK_LEFT BUTTON_PREV
365 #elif CONFIG_KEYPAD == ONDAVX747_PAD
366 #define BJACK_QUIT_NAME "POWER"
367 #define BJACK_DOUBLE_NAME "Vol-"
368 #define BJACK_QUIT BUTTON_POWER
369 #define BJACK_DOUBLEDOWN BUTTON_VOL_DOWN
371 #elif CONFIG_KEYPAD == ONDAVX777_PAD
372 #define BJACK_QUIT_NAME "POWER"
373 #define BJACK_QUIT BUTTON_POWER
375 #elif CONFIG_KEYPAD == MROBE500_PAD
376 #define BJACK_QUIT_NAME "POWER"
377 #define BJACK_QUIT BUTTON_POWER
379 #elif CONFIG_KEYPAD == SAMSUNG_YH_PAD
380 #define BJACK_SELECT_NAME "PLAY"
381 #define BJACK_STAY_NAME "RECORD"
382 #define BJACK_QUIT_NAME "REW"
383 #define BJACK_DOUBLE_NAME "FFWD"
384 #define BJACK_SELECT BUTTON_PLAY
385 #define BJACK_QUIT BUTTON_REW
386 #define BJACK_STAY BUTTON_REC
387 #define BJACK_DOUBLEDOWN BUTTON_FFWD
388 #define BJACK_UP BUTTON_UP
389 #define BJACK_DOWN BUTTON_DOWN
390 #define BJACK_RIGHT BUTTON_RIGHT
391 #define BJACK_LEFT BUTTON_LEFT
393 #else
394 #error No keymap defined!
395 #endif
397 #ifdef HAVE_TOUCHSCREEN
398 #ifndef BJACK_DOUBLEDOWN
399 #define BJACK_DOUBLEDOWN BUTTON_MIDLEFT
400 #define BJACK_DOUBLE_NAME "BUTTON_MIDLEFT"
401 #endif
402 #ifndef BJACK_SELECT
403 #define BJACK_SELECT BUTTON_CENTER
404 #define BJACK_SELECT_NAME "BUTTON_CENTER"
405 #endif
406 #ifndef BJACK_MAX
407 #define BJACK_MAX BUTTON_TOPRIGHT
408 #endif
409 #ifndef BJACK_MIN
410 #define BJACK_MIN BUTTON_TOPLEFT
411 #endif
412 #ifndef BJACK_STAY
413 #define BJACK_STAY BUTTON_BOTTOMLEFT
414 #define BJACK_STAY_NAME "BUTTON_BOTTOMLEFT"
415 #endif
416 #ifndef BJACK_UP
417 #define BJACK_UP BUTTON_TOPMIDDLE
418 #endif
419 #ifndef BJACK_DOWN
420 #define BJACK_DOWN BUTTON_BOTTOMMIDDLE
421 #endif
422 #ifndef BJACK_RIGHT
423 #define BJACK_RIGHT BUTTON_MIDRIGHT
424 #endif
425 #ifndef BJACK_LEFT
426 #define BJACK_LEFT BUTTON_MIDLEFT
427 #endif
429 #endif
431 #ifdef HAVE_LCD_COLOR
432 #define BG_COLOR LCD_RGBPACK(0,157,0)
433 #define FG_COLOR LCD_WHITE
434 #elif LCD_DEPTH > 1
435 #define BG_COLOR LCD_WHITE
436 #define FG_COLOR LCD_BLACK
437 #endif
439 #define CARD_WIDTH BMPWIDTH_card_back
440 #define CARD_HEIGHT BMPHEIGHT_card_back
442 /* This is the max amount of cards onscreen before condensing */
443 #define MAX_CARDS LCD_WIDTH/(CARD_WIDTH+4)
445 extern const fb_data card_deck[];
446 extern const fb_data card_back[];
448 #define NEXT_CARD bj->player_cards[done][bj->num_player_cards[done]]
450 /* dealer and player card positions */
451 unsigned int dealer_x, dealer_y, player_x, player_y;
453 typedef struct card {
454 unsigned int value; /* Card's value in Blackjack */
455 unsigned int num; /* Value on card face 0-12 (0=Ace, 1=2, 11=Q) */
456 unsigned int suit; /* 0:Spades, 1:Hearts, 2: Clubs; 3: Diamonds */
457 bool is_soft_ace;
458 } card;
460 typedef struct game_context {
461 struct card player_cards[2][22]; /* 22 Cards means the deal was all aces */
462 struct card dealer_cards[22]; /* That is the worst-case scenario */
463 unsigned int player_total;
464 unsigned int dealer_total;
465 signed int player_money;
466 unsigned int num_player_cards[2];
467 unsigned int num_dealer_cards;
468 unsigned int current_bet;
469 unsigned int split_status; /* 0 = split hasn't been asked, *
470 * 1 = split did not occur *
471 * 2 = split occurred *
472 * 3 = split occurred and 1st hand done */
473 bool is_blackjack;
474 bool end_hand;
475 bool asked_insurance;
476 } game_context;
478 static bool resume = false;
479 static bool resume_file = false;
480 static struct highscore highest[NUM_SCORES];
482 /*****************************************************************************
483 * blackjack_init() initializes blackjack data structures.
484 ******************************************************************************/
485 static void blackjack_init(struct game_context* bj) {
486 /* seed the rand generator */
487 rb->srand(*rb->current_tick);
489 /* reset card positions */
490 dealer_x = 4;
491 dealer_y = LCD_HEIGHT/4 - CARD_HEIGHT/2;
492 player_x = 4;
493 player_y = LCD_HEIGHT - LCD_HEIGHT/4 - CARD_HEIGHT/2;
495 /* check for resumed game */
496 if(resume) return;
498 /* reset scoring */
499 bj->player_total = 0;
500 bj->dealer_total = 0;
501 bj->num_player_cards[0] = 2;
502 bj->num_player_cards[1] = 0;
503 bj->num_dealer_cards = 2;
504 bj->end_hand = false;
505 bj->split_status = 0;
506 bj->is_blackjack = false;
507 bj->asked_insurance = false;
510 /*****************************************************************************
511 * blackjack_drawtable() draws the table and some text.
512 ******************************************************************************/
513 static void blackjack_drawtable(struct game_context* bj) {
514 unsigned int w, h, y_loc;
515 char str[10];
517 #if LCD_HEIGHT <= 64
518 rb->lcd_getstringsize("Bet", &w, &h);
519 rb->lcd_putsxy(LCD_WIDTH - w, 2*h + 1, "Bet");
520 rb->snprintf(str, 9, "$%d", bj->current_bet);
521 rb->lcd_getstringsize(str, &w, &h);
522 rb->lcd_putsxy(LCD_WIDTH - w, 3*h + 1, str);
523 y_loc = LCD_HEIGHT/2;
524 #else
525 rb->lcd_getstringsize("Bet", &w, &h);
526 rb->lcd_putsxy(LCD_WIDTH - w, 5*h / 2, "Bet");
527 rb->snprintf(str, 9, "$%d", bj->current_bet);
528 rb->lcd_getstringsize(str, &w, &h);
529 rb->lcd_putsxy(LCD_WIDTH - w, 7*h / 2, str);
530 rb->lcd_hline(0, LCD_WIDTH, LCD_HEIGHT/2);
531 y_loc = LCD_HEIGHT/2 + h;
532 #endif
534 rb->lcd_putsxy(0,0, "Dealer");
535 rb->lcd_getstringsize("Player", &w, &h);
536 rb->lcd_putsxy(0, y_loc, "Player");
537 rb->lcd_getstringsize("Total", &w, &h);
538 rb->lcd_putsxy(LCD_WIDTH - w, y_loc, "Total");
539 rb->lcd_getstringsize("Money", &w, &h);
540 rb->lcd_putsxy(LCD_WIDTH - w, 0, "Money");
541 rb->snprintf(str, 9, "$%d", bj->player_money - bj->current_bet);
542 rb->lcd_getstringsize(str, &w, &h);
543 rb->lcd_putsxy(LCD_WIDTH - w, h + 1, str);
544 rb->snprintf(str, 3, "%d", bj->player_total);
545 rb->lcd_getstringsize(str, &w, &h);
546 rb->lcd_putsxy(LCD_WIDTH - w, y_loc + h, str);
549 /*****************************************************************************
550 * find_value() is passed a card and returns its blackjack value.
551 ******************************************************************************/
552 static unsigned int find_value(unsigned int number) {
553 unsigned int thisValue;
554 if (number == 0)
555 thisValue = 11; /* Aces get a value of 11 at first */
556 else if (number < 10)
557 thisValue = number + 1;
558 else
559 thisValue = 10; /* Anything 10 or higher gets a value of 10 */
561 return thisValue;
564 /*****************************************************************************
565 * draw_card() draws a card to the screen.
566 ******************************************************************************/
567 static void draw_card(struct card temp_card, bool shown,
568 unsigned int x, unsigned int y) {
569 if(shown)
570 rb->lcd_bitmap_part(card_deck, CARD_WIDTH*temp_card.num,
571 CARD_HEIGHT*temp_card.suit,
572 STRIDE( SCREEN_MAIN, BMPWIDTH_card_deck,
573 BMPHEIGHT_card_deck),
574 x+1, y+1, CARD_WIDTH, CARD_HEIGHT);
575 else
576 rb->lcd_bitmap(card_back, x+1, y+1,CARD_WIDTH, CARD_HEIGHT);
577 #if LCD_DEPTH > 1
578 rb->lcd_set_foreground(LCD_BLACK);
579 #endif
581 /* Print outlines */
582 #if CARD_WIDTH >= 26
583 rb->lcd_hline(x+2, x+CARD_WIDTH-1, y);
584 rb->lcd_hline(x+2, x+CARD_WIDTH-1, y+CARD_HEIGHT+1);
585 rb->lcd_vline(x, y+2, y+CARD_HEIGHT-3);
586 rb->lcd_vline(x+CARD_WIDTH+1, y+2, y+CARD_HEIGHT-1);
587 rb->lcd_drawpixel(x+1, y+1);
588 rb->lcd_drawpixel(x+1, y+CARD_HEIGHT);
589 rb->lcd_drawpixel(x+CARD_WIDTH, y+1);
590 rb->lcd_drawpixel(x+CARD_WIDTH, y+CARD_HEIGHT);
591 #else
592 rb->lcd_hline(x+1, x+CARD_WIDTH, y);
593 rb->lcd_hline(x+1, x+CARD_WIDTH, y+CARD_HEIGHT+1);
594 rb->lcd_vline(x, y+1, y+CARD_HEIGHT);
595 rb->lcd_vline(x+CARD_WIDTH+1, y+1, y+CARD_HEIGHT);
596 #endif
598 #if LCD_DEPTH > 1
599 rb->lcd_set_foreground(FG_COLOR);
600 #endif
603 /*****************************************************************************
604 * new_card() initializes a new card and gives it values.
605 ******************************************************************************/
606 static struct card new_card(void) {
607 struct card new_card;
608 new_card.suit = rb->rand()%4; /* Random number 0-3 */
609 new_card.num = rb->rand()%13; /* Random number 0-12 */
610 new_card.value = find_value(new_card.num);
611 new_card.is_soft_ace = (new_card.num == 0);
612 return new_card;
615 /*****************************************************************************
616 * deal_init_card() deals and draws to the screen the player's and dealer's
617 * initial cards.
618 ******************************************************************************/
619 static void deal_init_cards(struct game_context* bj) {
620 bj->dealer_cards[0] = new_card();
621 bj->dealer_total += bj->dealer_cards[0].value;
623 draw_card(bj->dealer_cards[0], false, dealer_x, dealer_y);
625 bj->dealer_cards[1] = new_card();
626 bj->dealer_total += bj->dealer_cards[1].value;
627 draw_card(bj->dealer_cards[1], true, dealer_x + CARD_WIDTH + 4, dealer_y);
629 bj->player_cards[0][0] = new_card();
630 bj->player_total += bj->player_cards[0][0].value;
631 draw_card(bj->player_cards[0][0], true, player_x, player_y);
632 player_x += CARD_WIDTH + 4;
634 bj->player_cards[0][1] = new_card();
635 bj->player_total += bj->player_cards[0][1].value;
636 draw_card(bj->player_cards[0][1], true, player_x, player_y);
637 player_x += CARD_WIDTH + 4;
640 /*****************************************************************************
641 * redraw_board() redraws all the cards and the board
642 ******************************************************************************/
643 static void redraw_board(struct game_context* bj) {
644 unsigned int i, n, upper_bound;
645 rb->lcd_clear_display();
647 blackjack_drawtable(bj);
648 player_x = 4;
649 dealer_x = 4;
650 upper_bound = bj->split_status > 1 ? 2 : 1;
652 for (i = 0; i < bj->num_dealer_cards; i++) {
653 if (!bj->end_hand) {
654 draw_card(bj->dealer_cards[0], false, dealer_x, dealer_y);
656 /* increment i so the dealer's first card isn't displayed */
657 i++;
658 dealer_x += CARD_WIDTH + 4;
660 draw_card(bj->dealer_cards[i], true, dealer_x, dealer_y);
662 if (bj->num_dealer_cards > MAX_CARDS-1)
663 dealer_x += 10;
664 else
665 dealer_x += CARD_WIDTH + 4;
668 for (n = 0; n < upper_bound; n++) {
669 for (i = 0; i < bj->num_player_cards[n]; i++) {
670 draw_card(bj->player_cards[n][i], true, player_x, player_y);
671 if (bj->split_status>1 || bj->num_player_cards[n]>MAX_CARDS)
672 player_x += 10;
673 else
674 player_x += CARD_WIDTH + 4;
676 if (bj->split_status > 1)
677 player_x = LCD_WIDTH/2 + 4;
681 /*****************************************************************************
682 * update_total updates the player's total
683 ******************************************************************************/
684 static void update_total(struct game_context* bj) {
685 char total[3];
686 unsigned int w, h;
687 rb->snprintf(total, 3, "%d", bj->player_total);
688 rb->lcd_getstringsize(total, &w, &h);
689 #if LCD_HEIGHT > 64
690 h *= 2;
691 #endif
692 rb->lcd_putsxy(LCD_WIDTH - w, LCD_HEIGHT/2 + h, total);
693 rb->lcd_update_rect(LCD_WIDTH - w, LCD_HEIGHT/2 + h, w, h);
697 /*****************************************************************************
698 * check_for_aces() is passed an array of cards and returns where an ace is
699 * located. Otherwise, returns -1.
700 ******************************************************************************/
701 static signed int check_for_aces(struct card temp_cards[], unsigned int size) {
702 unsigned int i;
703 for(i = 0; i < size; i++) {
704 if (temp_cards[i].is_soft_ace)
705 return i;
707 return -1;
710 /*****************************************************************************
711 * check_totals() compares player and dealer totals.
712 * 0: bust 1: loss, 2: push, 3: win, 4: blackjack, 5: something's not right...
713 ******************************************************************************/
714 static unsigned int check_totals(struct game_context* bj) {
715 unsigned int temp;
716 if (bj->player_total > 21)
717 temp = 0;
718 else if (bj->player_total == 21 && bj->is_blackjack) {
719 if (bj->dealer_total == 21 && bj->num_dealer_cards == 2)
720 temp = 2;
721 else
722 temp = 4;
724 else if (bj->player_total == bj->dealer_total)
725 temp = 2;
726 else if (bj->dealer_total > 21 && bj->player_total < 22)
727 temp = 3;
728 else if (bj->dealer_total > bj->player_total)
729 temp = 1;
730 else if (bj->player_total > bj->dealer_total)
731 temp = 3;
732 else
733 temp = 5;
735 return temp;
738 /*****************************************************************************
739 * finish_dealer() draws cards for the dealer until he has 17 or more.
740 ******************************************************************************/
741 static void finish_dealer(struct game_context* bj) {
742 signed int temp = 0;
744 if (bj->dealer_total > 16 && bj->dealer_total < 22)
745 return;
747 while (bj->dealer_total < 17) {
748 bj->dealer_cards[bj->num_dealer_cards] = new_card();
749 bj->dealer_total += bj->dealer_cards[bj->num_dealer_cards].value;
750 bj->num_dealer_cards++;
753 while (bj->dealer_total > 21) {
754 temp = check_for_aces(bj->dealer_cards, bj->num_dealer_cards);
755 if(temp != -1) {
756 bj->dealer_cards[temp].is_soft_ace = false;
757 bj->dealer_total -= 10;
759 else
760 return;
764 /*****************************************************************************
765 * finish_game() completes the game once player's turn is over.
766 ******************************************************************************/
767 static void finish_game(struct game_context* bj) {
768 unsigned int rValue, w, h;
769 char str[19];
771 do {
772 finish_dealer(bj);
773 } while (bj->dealer_total < 17);
775 redraw_board(bj);
776 rValue = check_totals(bj);
778 if (rValue == 0) {
779 rb->snprintf(str, sizeof(str), " Bust! ");
780 bj->player_money -= bj->current_bet;
782 else if (rValue == 1) {
783 rb->snprintf(str, sizeof(str), " Sorry, you lost. ");
784 bj->player_money -= bj->current_bet;
786 else if (rValue == 2) {
787 rb->snprintf(str, sizeof(str), " Push ");
789 else if (rValue == 3) {
790 rb->snprintf(str, sizeof(str), " You won! ");
791 bj->player_money+= bj->current_bet;
793 else {
794 rb->snprintf(str, sizeof(str), " Blackjack! ");
795 bj->player_money += bj->current_bet * 3 / 2;
797 rb->lcd_getstringsize(str, &w, &h);
799 #if LCD_HEIGHT <= 64
800 rb->lcd_set_drawmode(DRMODE_BG+DRMODE_INVERSEVID);
801 rb->lcd_fillrect(0, LCD_HEIGHT/2, LCD_WIDTH, LCD_HEIGHT/2);
802 rb->lcd_set_drawmode(DRMODE_SOLID);
803 rb->lcd_putsxy(LCD_WIDTH/2 - w/2, LCD_HEIGHT/2 + h, str);
804 rb->snprintf(str, 12, "You have %d", bj->player_total);
805 rb->lcd_getstringsize(str, &w, &h);
806 rb->lcd_putsxy(LCD_WIDTH/2 - w/2, LCD_HEIGHT/2, str);
807 #else
808 rb->lcd_putsxy(LCD_WIDTH/2 - w/2, LCD_HEIGHT/2 - h/2, str);
809 #endif
810 rb->lcd_update();
813 /*****************************************************************************
814 * blackjack_loadgame() loads the saved game and returns load success.
815 ******************************************************************************/
816 static bool blackjack_loadgame(struct game_context* bj) {
817 signed int fd;
818 bool loaded = false;
820 /* open game file */
821 fd = rb->open(SAVE_FILE, O_RDONLY);
822 if(fd < 0) return false;
824 /* read in saved game */
825 if(rb->read(fd, bj, sizeof(struct game_context))
826 == (long)sizeof(struct game_context))
828 loaded = true;
831 rb->close(fd);
833 return loaded;
836 /*****************************************************************************
837 * blackjack_savegame() saves the current game state.
838 ******************************************************************************/
839 static void blackjack_savegame(struct game_context* bj) {
840 int fd;
842 if(!resume)
843 return;
844 /* write out the game state to the save file */
845 fd = rb->open(SAVE_FILE, O_WRONLY|O_CREAT);
846 if(fd < 0)
847 return;
848 rb->write(fd, bj, sizeof(struct game_context));
849 rb->close(fd);
852 /*****************************************************************************
853 * blackjack_get_yes_no() gets a yes/no answer from the user
854 ******************************************************************************/
855 static unsigned int blackjack_get_yes_no(char message[20]) {
856 int button;
857 unsigned int w, h, b, choice = 0;
858 bool breakout = false;
859 char message_yes[24], message_no[24];
861 rb->strcpy(message_yes, message);
862 rb->strcpy(message_no, message);
863 rb->strcat(message_yes, " Yes");
864 rb->strcat(message_no, " No");
865 rb->lcd_getstringsize(message_yes, &w, &h);
866 const char *stg[] = {message_yes, message_no};
868 #if LCD_HEIGHT <= 64
869 b = 2*h+1;
870 #else
871 b = h-1;
872 #endif
874 #ifdef HAVE_LCD_COLOR
875 rb->lcd_fillrect(LCD_WIDTH/2 - w/2, LCD_HEIGHT/2 + b, w+1, h+3);
876 rb->lcd_set_foreground(LCD_BLACK);
877 rb->lcd_set_background(LCD_WHITE);
878 #else
879 rb->lcd_set_drawmode(DRMODE_BG+DRMODE_INVERSEVID);
880 rb->lcd_fillrect(LCD_WIDTH/2 - w/2, LCD_HEIGHT/2 + b, w+1, h+3);
881 rb->lcd_set_drawmode(DRMODE_SOLID);
882 #endif
883 rb->lcd_drawrect(LCD_WIDTH/2 - w/2 - 1, LCD_HEIGHT/2 + b - 1, w+3, h+4);
885 while(!breakout) {
886 rb->lcd_putsxy(LCD_WIDTH/2 - w/2, LCD_HEIGHT/2 + b +1, stg[choice]);
887 rb->lcd_update_rect(LCD_WIDTH/2 - w/2 - 1, LCD_HEIGHT/2 + b -1,
888 w+3, h+4);
889 button = rb->button_get(true);
891 switch(button) {
892 case BJACK_LEFT:
893 case (BJACK_LEFT|BUTTON_REPEAT):
894 case BJACK_RIGHT:
895 case (BJACK_RIGHT|BUTTON_REPEAT):
896 choice ^= 1;
897 break;
898 case BJACK_SELECT: breakout = true;
899 break;
900 case BJACK_QUIT: breakout = true;
901 choice = 1;
902 break;
906 #if LCD_DEPTH > 1
907 rb->lcd_set_foreground(FG_COLOR);
908 rb->lcd_set_background(BG_COLOR);
909 #endif
910 return choice;
913 /*****************************************************************************
914 * blackjack_get_amount() gets an amount from the player to be used
915 ******************************************************************************/
916 static signed int blackjack_get_amount(char message[20], signed int lower_limit,
917 signed int upper_limit,
918 signed int start) {
919 int button;
920 char str[9];
921 bool breakout = false, changed = false;
922 unsigned int w, h;
923 signed int amount;
925 rb->lcd_getstringsize("A", &w, &h); /* find the size of one character */
927 if (start > upper_limit)
928 amount = upper_limit;
929 else if (start < lower_limit)
930 amount = lower_limit;
931 else
932 amount = start;
934 #if LCD_DEPTH > 1
935 rb->lcd_set_background(LCD_WHITE);
936 rb->lcd_set_foreground(LCD_BLACK);
937 #endif
939 #if LCD_HEIGHT <= 64
940 rb->lcd_clear_display();
941 rb->lcd_puts(0, 1, message);
942 rb->snprintf(str, 9, "$%d", amount);
943 rb->lcd_puts(0, 2, str);
944 rb->lcd_puts(0, 3, "RIGHT: +1");
945 rb->lcd_puts(0, 4, "LEFT: -1");
946 rb->lcd_puts(0, 5, "UP: +10");
947 rb->lcd_puts(0, 6, "DOWN: -10");
948 rb->lcd_update();
949 #else
950 rb->lcd_set_drawmode(DRMODE_BG+DRMODE_INVERSEVID);
951 rb->lcd_fillrect(LCD_WIDTH/2 - 9*w - 1, LCD_HEIGHT/2 - 4*h - 3,
952 37*w / 2, 8*h -3);
953 rb->lcd_set_drawmode(DRMODE_SOLID);
954 rb->lcd_drawrect(LCD_WIDTH/2 - 9*w - 1, LCD_HEIGHT/2 - 4*h - 3,
955 37*w / 2, 8*h -3);
956 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 4*h - 1, message);
957 rb->snprintf(str, 9, "$%d", amount);
958 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 3*h, str);
959 #if (CONFIG_KEYPAD == IPOD_4G_PAD) || \
960 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
961 (CONFIG_KEYPAD == IPOD_1G2G_PAD) || \
962 (CONFIG_KEYPAD == SANSA_E200_PAD) || \
963 (CONFIG_KEYPAD == SANSA_FUZE_PAD)
964 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - h-2, " >>|: +1");
965 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 1, " |<<: -1");
966 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 + h, "SCROLL+: +10");
967 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 + 2*h + 1, "SCROLL-: -10");
968 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
969 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - h-2, "RIGHT: +1");
970 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 1, "LEFT: -1");
971 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 + h, "SCROLL+: +10");
972 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 + 2*h + 1, "SCROLL-: -10");
973 #else
974 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - h-2, "RIGHT: +1");
975 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 1, "LEFT: -1");
976 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 + h, "UP: +10");
977 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 + 2*h + 1, "DOWN: -10");
978 #endif
979 rb->lcd_update_rect(LCD_WIDTH/2 - 9*w - 1, LCD_HEIGHT/2 - 4*h - 3,
980 37*w / 2, 8*h -3);
981 #endif
983 while(!breakout) {
984 button = rb->button_get(true);
986 switch(button) {
987 case BJACK_UP:
988 case (BJACK_UP|BUTTON_REPEAT):
989 if (amount + 10 < upper_limit + 1) {
990 amount += 10;
991 changed = true;
993 break;
994 case BJACK_DOWN:
995 case (BJACK_DOWN|BUTTON_REPEAT):
996 if (amount - 10 > lower_limit - 1) {
997 amount -= 10;
998 changed = true;
1000 break;
1001 case BJACK_RIGHT:
1002 case (BJACK_RIGHT|BUTTON_REPEAT):
1003 if (amount + 1 < upper_limit + 1) {
1004 amount++;
1005 changed = true;
1007 break;
1008 case BJACK_LEFT:
1009 case (BJACK_LEFT|BUTTON_REPEAT):
1010 if (amount - 1 > lower_limit - 1) {
1011 amount--;
1012 changed = true;
1014 break;
1015 #ifdef BJACK_MAX
1016 case BJACK_MAX :
1017 amount = upper_limit;
1018 changed = true;
1019 break;
1020 #endif
1021 #ifdef BJACK_MIN
1022 case BJACK_MIN :
1023 amount = lower_limit;
1024 changed = true;
1025 break;
1026 #endif
1027 case BJACK_QUIT:
1028 breakout = true;
1029 amount = 0;
1030 break;
1031 case BJACK_SELECT:
1032 breakout = true;
1033 break;
1036 if(changed) {
1037 rb->snprintf(str, 9, "$%d", amount);
1038 #if LCD_HEIGHT <= 64
1039 rb->lcd_puts(0, 2, str);
1040 rb->lcd_update();
1041 #else
1042 rb->lcd_set_drawmode(DRMODE_BG+DRMODE_INVERSEVID);
1043 rb->lcd_fillrect(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 3*h, 5*w, h);
1044 rb->lcd_set_drawmode(DRMODE_SOLID);
1045 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 3*h, str);
1046 rb->lcd_update_rect(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 3*h, 5*w, h);
1047 #endif
1048 changed = false;
1052 #if LCD_DEPTH > 1
1053 rb->lcd_set_foreground(FG_COLOR);
1054 rb->lcd_set_background(BG_COLOR);
1055 #endif
1056 rb->lcd_clear_display();
1057 return amount;
1060 /*****************************************************************************
1061 * blackjack_get_bet() gets the player's bet.
1062 ******************************************************************************/
1063 static void blackjack_get_bet(struct game_context* bj) {
1064 bj->current_bet = blackjack_get_amount("Please enter a bet", 10,
1065 bj->player_money, bj->current_bet);
1068 /*****************************************************************************
1069 * double_down() returns one final card then finishes the game
1070 ******************************************************************************/
1071 static void double_down(struct game_context* bj) {
1072 bj->current_bet *= 2;
1073 bj->player_cards[0][bj->num_player_cards[0]] = new_card();
1074 bj->player_total += bj->player_cards[0][bj->num_player_cards[0]].value;
1075 bj->num_player_cards[0]++;
1078 /*****************************************************************************
1079 * split() checks if the player wants to split and acts accordingly.
1080 * When bj->split_status is 1, no split occurred. 2 means the player split and 3
1081 * means a split has already occurred and the first hand is done.
1082 ******************************************************************************/
1083 static void split(struct game_context* bj) {
1084 if (blackjack_get_yes_no("Split?") != 0)
1085 bj->split_status = 1;
1086 else {
1087 bj->split_status = 2;
1088 bj->current_bet *= 2;
1089 bj->num_player_cards[0] = 1;
1090 bj->num_player_cards[1] = 1;
1091 bj->player_cards[1][0] = bj->player_cards[0][1];
1092 bj->player_total = bj->player_cards[0][0].value;
1096 /*****************************************************************************
1097 * insurance() see if the player wants to buy insurance and how much.
1098 ******************************************************************************/
1099 static unsigned int insurance(struct game_context* bj) {
1100 unsigned int insurance, max_amount;
1102 insurance = blackjack_get_yes_no("Buy Insurance?");
1103 bj->asked_insurance = true;
1104 max_amount = bj->current_bet < (unsigned int)bj->player_money ?
1105 bj->current_bet/2 : (unsigned int)bj->player_money;
1106 if (insurance != 0) return 0;
1108 insurance = blackjack_get_amount("How much?", 0, max_amount, 0);
1109 redraw_board(bj);
1110 return insurance;
1113 /*****************************************************************************
1114 * play_again() checks to see if the player wants to keep playing.
1115 ******************************************************************************/
1116 static unsigned int play_again(void) {
1117 return blackjack_get_yes_no("Play Again?");
1120 /*****************************************************************************
1121 * blackjack_help() displays help text.
1122 ******************************************************************************/
1123 static bool blackjack_help(void) {
1124 #define WORDS (sizeof help_text / sizeof (char*))
1125 static char *help_text[] = {
1126 "Blackjack", "", "Aim", "",
1127 "Try", "to", "get", "as", "close", "to", "21", "without", "going",
1128 "over", "or", "simply", "beat", "out", "the", "dealer", "for", "the",
1129 "best", "hand.", "", "",
1130 "Controls", "",
1131 BJACK_SELECT_NAME, ":", "hit", "/", "select", "",
1132 BJACK_STAY_NAME, ":", "stay", "",
1133 BJACK_DOUBLE_NAME, ":", "double", "down", "",
1134 BJACK_QUIT_NAME, ":", "go", "to", "menu", "",
1136 static struct style_text formation[]={
1137 { 0, TEXT_CENTER|TEXT_UNDERLINE },
1138 { 2, C_RED },
1139 { 26, C_RED },
1140 { -1, 0 }
1142 int button;
1144 rb->lcd_setfont(FONT_UI);
1145 #ifdef HAVE_LCD_COLOR
1146 rb->lcd_set_background(LCD_BLACK);
1147 rb->lcd_set_foreground(LCD_WHITE);
1148 #endif
1150 if (display_text(WORDS, help_text, formation, NULL))
1151 return true;
1152 do {
1153 button = rb->button_get(true);
1154 if (rb->default_event_handler(button) == SYS_USB_CONNECTED) {
1155 return true;
1157 } while( ( button == BUTTON_NONE )
1158 || ( button & (BUTTON_REL|BUTTON_REPEAT) ) );
1159 rb->lcd_setfont(FONT_SYSFIXED);
1160 return false;
1163 static int blackjack_menu_cb(int action, const struct menu_item_ex *this_item)
1165 int i = ((intptr_t)this_item);
1166 if(action == ACTION_REQUEST_MENUITEM
1167 && !resume && (i==0 || i==5))
1168 return ACTION_EXIT_MENUITEM;
1169 return action;
1172 /*****************************************************************************
1173 * blackjack_menu() is the initial menu at the start of the game.
1174 ******************************************************************************/
1175 static unsigned int blackjack_menu(void) {
1176 int selection = 0;
1177 bool breakout = false;
1179 MENUITEM_STRINGLIST(menu, "BlackJack Menu", blackjack_menu_cb,
1180 "Resume Game", "Start New Game",
1181 "High Scores", "Help",
1182 "Playback Control",
1183 "Quit without Saving", "Quit");
1185 while(!breakout) {
1186 switch(rb->do_menu(&menu, &selection, NULL, false)) {
1187 case 0:
1188 breakout = true;
1189 if(resume_file)
1190 rb->remove(SAVE_FILE);
1191 resume_file = false;
1192 break;
1193 case 1:
1194 breakout = true;
1195 resume = false;
1196 break;
1197 case 2:
1198 highscore_show(NUM_SCORES, highest, NUM_SCORES, false);
1199 break;
1200 case 3:
1201 if(blackjack_help())
1202 return BJ_USB;
1203 break;
1204 case 4:
1205 if (playback_control(NULL))
1206 return BJ_USB;
1207 break;
1208 case 5:
1209 return BJ_QUIT_WITHOUT_SAVING;
1210 case 6:
1211 if (resume)
1212 return BJ_QUIT;
1213 else
1214 return BJ_QUIT_WITHOUT_SAVING;
1216 case MENU_ATTACHED_USB:
1217 return BJ_USB;
1219 default:
1220 break;
1224 return 0;
1227 /*****************************************************************************
1228 * blackjack() is the main game subroutine, it returns the final game status.
1229 ******************************************************************************/
1230 static int blackjack(struct game_context* bj) {
1231 int button;
1232 unsigned int w, h, temp_var, done = 0, todo = 1;
1233 signed int temp;
1234 bool breakout = false;
1235 bool dbl_down = false;
1237 /********************
1238 * menu *
1239 ********************/
1240 temp_var = blackjack_menu();
1241 if (temp_var != 0)
1242 return temp_var;
1244 #if LCD_DEPTH > 1
1245 rb->lcd_set_background(BG_COLOR);
1246 rb->lcd_set_foreground(FG_COLOR);
1247 #endif
1249 /********************
1250 * init *
1251 ********************/
1252 blackjack_init(bj);
1254 /********************
1255 * play *
1256 ********************/
1258 resume_file = false;
1259 /* check for resumed game */
1260 if(resume) {
1261 resume = false;
1262 redraw_board(bj);
1263 if (bj->split_status == 2) {
1264 todo=2;
1265 player_x = bj->num_player_cards[0] * 10 + 4;
1267 else if (bj->split_status == 3) {
1268 player_x = bj->num_player_cards[1] * 10 + LCD_WIDTH/2 + 4;
1269 todo=2;
1270 done=1;
1273 else {
1274 bj->player_money = 1000;
1275 bj->current_bet = 10;
1276 blackjack_get_bet(bj);
1277 if (bj->current_bet == 0)
1278 return -1;
1279 rb->lcd_clear_display();
1280 deal_init_cards(bj);
1281 blackjack_drawtable(bj);
1284 rb->lcd_update();
1286 breakout = false;
1288 while(true){
1289 if(bj->player_total == 21 && bj->num_player_cards[0] == 2) {
1290 bj->is_blackjack = true;
1291 bj->end_hand = true;
1292 finish_game(bj);
1294 else if(bj->dealer_cards[1].is_soft_ace && !breakout &&
1295 !bj->asked_insurance) {
1296 temp_var = insurance(bj);
1297 if (bj->dealer_total == 21) {
1298 rb->splash(HZ, "Dealer has blackjack");
1299 bj->player_money += temp_var;
1300 bj->end_hand = true;
1301 breakout = true;
1302 redraw_board(bj);
1303 finish_game(bj);
1305 else {
1306 rb->splash(HZ, "Dealer does not have blackjack");
1307 bj->player_money -= temp_var;
1308 breakout = true;
1309 redraw_board(bj);
1310 rb->lcd_update();
1313 if(!bj->end_hand && bj->split_status == 0 &&
1314 bj->player_cards[0][0].num == bj->player_cards[0][1].num) {
1315 split(bj);
1316 redraw_board(bj);
1317 rb->lcd_update_rect(0, LCD_HEIGHT/2, LCD_WIDTH, LCD_HEIGHT/2);
1318 if (bj->split_status == 2) {
1319 todo++;
1320 player_x = bj->num_player_cards[0] * 10 + 4;
1324 while(!bj->end_hand && done < todo) {
1325 button = rb->button_get(true);
1327 switch(button) {
1328 case BJACK_SELECT:
1329 NEXT_CARD = new_card();
1330 bj->player_total += NEXT_CARD.value;
1331 draw_card(NEXT_CARD, true, player_x, player_y);
1332 bj->num_player_cards[done]++;
1333 if (bj->num_player_cards[done] == MAX_CARDS + 1) {
1334 redraw_board(bj);
1335 rb->lcd_update_rect(0, LCD_HEIGHT/2, LCD_WIDTH,
1336 LCD_HEIGHT/2);
1338 else if (bj->num_player_cards[done]>MAX_CARDS || todo > 1) {
1339 rb->lcd_update_rect(player_x, player_y, CARD_WIDTH+2,
1340 CARD_HEIGHT+2);
1341 player_x += 10;
1343 else {
1344 rb->lcd_update_rect(player_x, player_y, CARD_WIDTH+2,
1345 CARD_HEIGHT+2);
1346 player_x += CARD_WIDTH + 4;
1348 update_total(bj);
1350 break;
1351 case BJACK_STAY:
1352 bj->end_hand = true;
1353 break;
1354 case BJACK_DOUBLEDOWN:
1355 if ((signed int)bj->current_bet * 2 <
1356 bj->player_money + 1 &&
1357 bj->num_player_cards[0]==2 && todo==1) {
1358 double_down(bj);
1359 dbl_down = true;
1360 if (bj->player_total < 22) {
1361 bj->end_hand = true;
1362 finish_game(bj);
1365 else if((signed int)bj->current_bet * 2 >
1366 bj->player_money){
1367 rb->splash(HZ, "Not enough money to double down.");
1368 redraw_board(bj);
1369 rb->lcd_update();
1371 break;
1373 case BJACK_QUIT:
1374 resume = true;
1375 return BJ_END;
1378 while (bj->player_total > 21 && !bj->end_hand) {
1379 temp = check_for_aces(bj->player_cards[done],
1380 bj->num_player_cards[done]);
1381 if(temp != -1) {
1382 bj->player_cards[done][temp].is_soft_ace = false;
1383 bj->player_total -= 10;
1384 update_total(bj);
1385 if (dbl_down) {
1386 bj->end_hand = true;
1387 finish_game(bj);
1390 else
1391 bj->end_hand = true;
1394 if (bj->end_hand) {
1395 done++;
1396 if(todo > 1) {
1397 if (done == 2) {
1398 temp = bj->player_total;
1399 bj->player_total = temp_var;
1400 temp_var = temp;
1401 finish_game(bj);
1402 rb->lcd_getstringsize(" Split 1 ", &w, &h);
1403 rb->lcd_putsxy(LCD_WIDTH/2-w/2, LCD_HEIGHT/2-3*h/2,
1404 " Split 1 ");
1405 rb->lcd_update_rect(LCD_WIDTH/2-w/2, LCD_HEIGHT/2-3*h/2,
1406 w,h);
1407 bj->current_bet /= 2;
1408 rb->lcd_update_rect(LCD_WIDTH/2-w/2, LCD_HEIGHT/2-3*h/2,
1409 w,h);
1410 rb->sleep(HZ*2);
1411 bj->player_total = temp_var;
1412 finish_game(bj);
1413 rb->lcd_getstringsize(" Split 2 ", &w, &h);
1414 rb->lcd_putsxy(LCD_WIDTH/2-w/2, LCD_HEIGHT/2-3*h/2,
1415 " Split 2 ");
1416 rb->lcd_update_rect(LCD_WIDTH/2-w/2, LCD_HEIGHT/2-3*h/2,
1417 w,h);
1418 rb->sleep(HZ*2);
1420 else {
1421 bj->end_hand = false;
1422 bj->split_status = 3;
1423 temp_var = bj->player_total;
1424 bj->player_total = bj->player_cards[1][0].value;
1425 update_total(bj);
1426 redraw_board(bj);
1427 player_x += 10;
1428 rb->lcd_update();
1431 else
1432 finish_game(bj);
1436 if (bj->player_money < 10) {
1437 rb->sleep(HZ);
1438 return BJ_LOSE;
1441 if (bj->end_hand) { /* If hand is over */
1442 if (play_again() != 0) /* User wants to quit */
1443 return BJ_END;
1444 else { /* User keeps playing */
1445 breakout = false;
1446 temp = bj->current_bet;
1447 bj->current_bet = 0;
1448 redraw_board(bj);
1449 rb->lcd_update();
1450 bj->current_bet = temp;
1451 if(dbl_down) {
1452 bj->current_bet /= 2;
1453 dbl_down = false;
1455 done = 0;
1456 todo = 1;
1457 blackjack_init(bj);
1458 blackjack_get_bet(bj);
1459 if (bj->current_bet == 0)
1460 return BJ_END;
1461 deal_init_cards(bj);
1462 blackjack_drawtable(bj);
1463 rb->lcd_update();
1467 /* Never reached */
1468 return PLUGIN_OK;
1471 /*****************************************************************************
1472 * plugin entry point.
1473 ******************************************************************************/
1474 enum plugin_status plugin_start(const void* parameter)
1476 struct game_context bj;
1477 bool exit = false;
1479 (void)parameter;
1481 #if LCD_DEPTH > 1
1482 rb->lcd_set_backdrop(NULL);
1483 #endif
1485 /* load high scores */
1486 highscore_load(HIGH_SCORE,highest,NUM_SCORES);
1487 resume = blackjack_loadgame(&bj);
1488 resume_file = resume;
1490 rb->lcd_setfont(FONT_SYSFIXED);
1492 while(!exit) {
1493 switch(blackjack(&bj)){
1494 case BJ_LOSE:
1495 rb->splash(HZ, "Not enough money to continue");
1496 /* fall through to BJ_END */
1498 case BJ_END:
1499 if(!resume && bj.player_money > 10) {
1500 /* There is no level, so store -1 to blank column */
1501 int position = highscore_update(bj.player_money, -1, "",
1502 highest, NUM_SCORES);
1503 if (position==0)
1504 rb->splash(HZ*2, "New High Score");
1505 if (position != -1)
1506 highscore_show(position, highest, NUM_SCORES, false);
1508 break;
1510 case BJ_USB:
1511 highscore_save(HIGH_SCORE,highest,NUM_SCORES);
1512 return PLUGIN_USB_CONNECTED;
1514 case BJ_QUIT:
1515 rb->splash(HZ*1, "Saving game...");
1516 blackjack_savegame(&bj);
1517 /* fall through */
1519 case BJ_QUIT_WITHOUT_SAVING:
1520 exit = true;
1521 break;
1523 default:
1524 break;
1527 highscore_save(HIGH_SCORE,highest,NUM_SCORES);
1528 return PLUGIN_OK;