Packard Bell Vibe 500: More plugin keymaps (second portion).
[kugel-rb.git] / apps / plugins / blackjack.c
blob897a40bd19b3c51685d9cf4c2b52dac4402bc8b0
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 #elif CONFIG_KEYPAD == PBELL_VIBE500_PAD
394 #define BJACK_SELECT_NAME "OK"
395 #define BJACK_STAY_NAME "CANCEL"
396 #define BJACK_QUIT_NAME "REC"
397 #define BJACK_DOUBLE_NAME "MENU"
398 #define BJACK_SELECT BUTTON_OK
399 #define BJACK_QUIT BUTTON_REC
400 #define BJACK_STAY BUTTON_CANCEL
401 #define BJACK_DOUBLEDOWN BUTTON_MENU
402 #define BJACK_UP BUTTON_UP
403 #define BJACK_DOWN BUTTON_DOWN
404 #define BJACK_RIGHT BUTTON_NEXT
405 #define BJACK_LEFT BUTTON_PREV
407 #else
408 #error No keymap defined!
409 #endif
411 #ifdef HAVE_TOUCHSCREEN
412 #ifndef BJACK_DOUBLEDOWN
413 #define BJACK_DOUBLEDOWN BUTTON_MIDLEFT
414 #define BJACK_DOUBLE_NAME "BUTTON_MIDLEFT"
415 #endif
416 #ifndef BJACK_SELECT
417 #define BJACK_SELECT BUTTON_CENTER
418 #define BJACK_SELECT_NAME "BUTTON_CENTER"
419 #endif
420 #ifndef BJACK_MAX
421 #define BJACK_MAX BUTTON_TOPRIGHT
422 #endif
423 #ifndef BJACK_MIN
424 #define BJACK_MIN BUTTON_TOPLEFT
425 #endif
426 #ifndef BJACK_STAY
427 #define BJACK_STAY BUTTON_BOTTOMLEFT
428 #define BJACK_STAY_NAME "BUTTON_BOTTOMLEFT"
429 #endif
430 #ifndef BJACK_UP
431 #define BJACK_UP BUTTON_TOPMIDDLE
432 #endif
433 #ifndef BJACK_DOWN
434 #define BJACK_DOWN BUTTON_BOTTOMMIDDLE
435 #endif
436 #ifndef BJACK_RIGHT
437 #define BJACK_RIGHT BUTTON_MIDRIGHT
438 #endif
439 #ifndef BJACK_LEFT
440 #define BJACK_LEFT BUTTON_MIDLEFT
441 #endif
443 #endif
445 #ifdef HAVE_LCD_COLOR
446 #define BG_COLOR LCD_RGBPACK(0,157,0)
447 #define FG_COLOR LCD_WHITE
448 #elif LCD_DEPTH > 1
449 #define BG_COLOR LCD_WHITE
450 #define FG_COLOR LCD_BLACK
451 #endif
453 #define CARD_WIDTH BMPWIDTH_card_back
454 #define CARD_HEIGHT BMPHEIGHT_card_back
456 /* This is the max amount of cards onscreen before condensing */
457 #define MAX_CARDS LCD_WIDTH/(CARD_WIDTH+4)
459 extern const fb_data card_deck[];
460 extern const fb_data card_back[];
462 #define NEXT_CARD bj->player_cards[done][bj->num_player_cards[done]]
464 /* dealer and player card positions */
465 unsigned int dealer_x, dealer_y, player_x, player_y;
467 typedef struct card {
468 unsigned int value; /* Card's value in Blackjack */
469 unsigned int num; /* Value on card face 0-12 (0=Ace, 1=2, 11=Q) */
470 unsigned int suit; /* 0:Spades, 1:Hearts, 2: Clubs; 3: Diamonds */
471 bool is_soft_ace;
472 } card;
474 typedef struct game_context {
475 struct card player_cards[2][22]; /* 22 Cards means the deal was all aces */
476 struct card dealer_cards[22]; /* That is the worst-case scenario */
477 unsigned int player_total;
478 unsigned int dealer_total;
479 signed int player_money;
480 unsigned int num_player_cards[2];
481 unsigned int num_dealer_cards;
482 unsigned int current_bet;
483 unsigned int split_status; /* 0 = split hasn't been asked, *
484 * 1 = split did not occur *
485 * 2 = split occurred *
486 * 3 = split occurred and 1st hand done */
487 bool is_blackjack;
488 bool end_hand;
489 bool asked_insurance;
490 } game_context;
492 static bool resume = false;
493 static bool resume_file = false;
494 static struct highscore highest[NUM_SCORES];
496 /*****************************************************************************
497 * blackjack_init() initializes blackjack data structures.
498 ******************************************************************************/
499 static void blackjack_init(struct game_context* bj) {
500 /* seed the rand generator */
501 rb->srand(*rb->current_tick);
503 /* reset card positions */
504 dealer_x = 4;
505 dealer_y = LCD_HEIGHT/4 - CARD_HEIGHT/2;
506 player_x = 4;
507 player_y = LCD_HEIGHT - LCD_HEIGHT/4 - CARD_HEIGHT/2;
509 /* check for resumed game */
510 if(resume) return;
512 /* reset scoring */
513 bj->player_total = 0;
514 bj->dealer_total = 0;
515 bj->num_player_cards[0] = 2;
516 bj->num_player_cards[1] = 0;
517 bj->num_dealer_cards = 2;
518 bj->end_hand = false;
519 bj->split_status = 0;
520 bj->is_blackjack = false;
521 bj->asked_insurance = false;
524 /*****************************************************************************
525 * blackjack_drawtable() draws the table and some text.
526 ******************************************************************************/
527 static void blackjack_drawtable(struct game_context* bj) {
528 unsigned int w, h, y_loc;
529 char str[10];
531 #if LCD_HEIGHT <= 64
532 rb->lcd_getstringsize("Bet", &w, &h);
533 rb->lcd_putsxy(LCD_WIDTH - w, 2*h + 1, "Bet");
534 rb->snprintf(str, 9, "$%d", bj->current_bet);
535 rb->lcd_getstringsize(str, &w, &h);
536 rb->lcd_putsxy(LCD_WIDTH - w, 3*h + 1, str);
537 y_loc = LCD_HEIGHT/2;
538 #else
539 rb->lcd_getstringsize("Bet", &w, &h);
540 rb->lcd_putsxy(LCD_WIDTH - w, 5*h / 2, "Bet");
541 rb->snprintf(str, 9, "$%d", bj->current_bet);
542 rb->lcd_getstringsize(str, &w, &h);
543 rb->lcd_putsxy(LCD_WIDTH - w, 7*h / 2, str);
544 rb->lcd_hline(0, LCD_WIDTH, LCD_HEIGHT/2);
545 y_loc = LCD_HEIGHT/2 + h;
546 #endif
548 rb->lcd_putsxy(0,0, "Dealer");
549 rb->lcd_getstringsize("Player", &w, &h);
550 rb->lcd_putsxy(0, y_loc, "Player");
551 rb->lcd_getstringsize("Total", &w, &h);
552 rb->lcd_putsxy(LCD_WIDTH - w, y_loc, "Total");
553 rb->lcd_getstringsize("Money", &w, &h);
554 rb->lcd_putsxy(LCD_WIDTH - w, 0, "Money");
555 rb->snprintf(str, 9, "$%d", bj->player_money - bj->current_bet);
556 rb->lcd_getstringsize(str, &w, &h);
557 rb->lcd_putsxy(LCD_WIDTH - w, h + 1, str);
558 rb->snprintf(str, 3, "%d", bj->player_total);
559 rb->lcd_getstringsize(str, &w, &h);
560 rb->lcd_putsxy(LCD_WIDTH - w, y_loc + h, str);
563 /*****************************************************************************
564 * find_value() is passed a card and returns its blackjack value.
565 ******************************************************************************/
566 static unsigned int find_value(unsigned int number) {
567 unsigned int thisValue;
568 if (number == 0)
569 thisValue = 11; /* Aces get a value of 11 at first */
570 else if (number < 10)
571 thisValue = number + 1;
572 else
573 thisValue = 10; /* Anything 10 or higher gets a value of 10 */
575 return thisValue;
578 /*****************************************************************************
579 * draw_card() draws a card to the screen.
580 ******************************************************************************/
581 static void draw_card(struct card temp_card, bool shown,
582 unsigned int x, unsigned int y) {
583 if(shown)
584 rb->lcd_bitmap_part(card_deck, CARD_WIDTH*temp_card.num,
585 CARD_HEIGHT*temp_card.suit,
586 STRIDE( SCREEN_MAIN, BMPWIDTH_card_deck,
587 BMPHEIGHT_card_deck),
588 x+1, y+1, CARD_WIDTH, CARD_HEIGHT);
589 else
590 rb->lcd_bitmap(card_back, x+1, y+1,CARD_WIDTH, CARD_HEIGHT);
591 #if LCD_DEPTH > 1
592 rb->lcd_set_foreground(LCD_BLACK);
593 #endif
595 /* Print outlines */
596 #if CARD_WIDTH >= 26
597 rb->lcd_hline(x+2, x+CARD_WIDTH-1, y);
598 rb->lcd_hline(x+2, x+CARD_WIDTH-1, y+CARD_HEIGHT+1);
599 rb->lcd_vline(x, y+2, y+CARD_HEIGHT-3);
600 rb->lcd_vline(x+CARD_WIDTH+1, y+2, y+CARD_HEIGHT-1);
601 rb->lcd_drawpixel(x+1, y+1);
602 rb->lcd_drawpixel(x+1, y+CARD_HEIGHT);
603 rb->lcd_drawpixel(x+CARD_WIDTH, y+1);
604 rb->lcd_drawpixel(x+CARD_WIDTH, y+CARD_HEIGHT);
605 #else
606 rb->lcd_hline(x+1, x+CARD_WIDTH, y);
607 rb->lcd_hline(x+1, x+CARD_WIDTH, y+CARD_HEIGHT+1);
608 rb->lcd_vline(x, y+1, y+CARD_HEIGHT);
609 rb->lcd_vline(x+CARD_WIDTH+1, y+1, y+CARD_HEIGHT);
610 #endif
612 #if LCD_DEPTH > 1
613 rb->lcd_set_foreground(FG_COLOR);
614 #endif
617 /*****************************************************************************
618 * new_card() initializes a new card and gives it values.
619 ******************************************************************************/
620 static struct card new_card(void) {
621 struct card new_card;
622 new_card.suit = rb->rand()%4; /* Random number 0-3 */
623 new_card.num = rb->rand()%13; /* Random number 0-12 */
624 new_card.value = find_value(new_card.num);
625 new_card.is_soft_ace = (new_card.num == 0);
626 return new_card;
629 /*****************************************************************************
630 * deal_init_card() deals and draws to the screen the player's and dealer's
631 * initial cards.
632 ******************************************************************************/
633 static void deal_init_cards(struct game_context* bj) {
634 bj->dealer_cards[0] = new_card();
635 bj->dealer_total += bj->dealer_cards[0].value;
637 draw_card(bj->dealer_cards[0], false, dealer_x, dealer_y);
639 bj->dealer_cards[1] = new_card();
640 bj->dealer_total += bj->dealer_cards[1].value;
641 draw_card(bj->dealer_cards[1], true, dealer_x + CARD_WIDTH + 4, dealer_y);
643 bj->player_cards[0][0] = new_card();
644 bj->player_total += bj->player_cards[0][0].value;
645 draw_card(bj->player_cards[0][0], true, player_x, player_y);
646 player_x += CARD_WIDTH + 4;
648 bj->player_cards[0][1] = new_card();
649 bj->player_total += bj->player_cards[0][1].value;
650 draw_card(bj->player_cards[0][1], true, player_x, player_y);
651 player_x += CARD_WIDTH + 4;
654 /*****************************************************************************
655 * redraw_board() redraws all the cards and the board
656 ******************************************************************************/
657 static void redraw_board(struct game_context* bj) {
658 unsigned int i, n, upper_bound;
659 rb->lcd_clear_display();
661 blackjack_drawtable(bj);
662 player_x = 4;
663 dealer_x = 4;
664 upper_bound = bj->split_status > 1 ? 2 : 1;
666 for (i = 0; i < bj->num_dealer_cards; i++) {
667 if (!bj->end_hand) {
668 draw_card(bj->dealer_cards[0], false, dealer_x, dealer_y);
670 /* increment i so the dealer's first card isn't displayed */
671 i++;
672 dealer_x += CARD_WIDTH + 4;
674 draw_card(bj->dealer_cards[i], true, dealer_x, dealer_y);
676 if (bj->num_dealer_cards > MAX_CARDS-1)
677 dealer_x += 10;
678 else
679 dealer_x += CARD_WIDTH + 4;
682 for (n = 0; n < upper_bound; n++) {
683 for (i = 0; i < bj->num_player_cards[n]; i++) {
684 draw_card(bj->player_cards[n][i], true, player_x, player_y);
685 if (bj->split_status>1 || bj->num_player_cards[n]>MAX_CARDS)
686 player_x += 10;
687 else
688 player_x += CARD_WIDTH + 4;
690 if (bj->split_status > 1)
691 player_x = LCD_WIDTH/2 + 4;
695 /*****************************************************************************
696 * update_total updates the player's total
697 ******************************************************************************/
698 static void update_total(struct game_context* bj) {
699 char total[3];
700 unsigned int w, h;
701 rb->snprintf(total, 3, "%d", bj->player_total);
702 rb->lcd_getstringsize(total, &w, &h);
703 #if LCD_HEIGHT > 64
704 h *= 2;
705 #endif
706 rb->lcd_putsxy(LCD_WIDTH - w, LCD_HEIGHT/2 + h, total);
707 rb->lcd_update_rect(LCD_WIDTH - w, LCD_HEIGHT/2 + h, w, h);
711 /*****************************************************************************
712 * check_for_aces() is passed an array of cards and returns where an ace is
713 * located. Otherwise, returns -1.
714 ******************************************************************************/
715 static signed int check_for_aces(struct card temp_cards[], unsigned int size) {
716 unsigned int i;
717 for(i = 0; i < size; i++) {
718 if (temp_cards[i].is_soft_ace)
719 return i;
721 return -1;
724 /*****************************************************************************
725 * check_totals() compares player and dealer totals.
726 * 0: bust 1: loss, 2: push, 3: win, 4: blackjack, 5: something's not right...
727 ******************************************************************************/
728 static unsigned int check_totals(struct game_context* bj) {
729 unsigned int temp;
730 if (bj->player_total > 21)
731 temp = 0;
732 else if (bj->player_total == 21 && bj->is_blackjack) {
733 if (bj->dealer_total == 21 && bj->num_dealer_cards == 2)
734 temp = 2;
735 else
736 temp = 4;
738 else if (bj->player_total == bj->dealer_total)
739 temp = 2;
740 else if (bj->dealer_total > 21 && bj->player_total < 22)
741 temp = 3;
742 else if (bj->dealer_total > bj->player_total)
743 temp = 1;
744 else if (bj->player_total > bj->dealer_total)
745 temp = 3;
746 else
747 temp = 5;
749 return temp;
752 /*****************************************************************************
753 * finish_dealer() draws cards for the dealer until he has 17 or more.
754 ******************************************************************************/
755 static void finish_dealer(struct game_context* bj) {
756 signed int temp = 0;
758 if (bj->dealer_total > 16 && bj->dealer_total < 22)
759 return;
761 while (bj->dealer_total < 17) {
762 bj->dealer_cards[bj->num_dealer_cards] = new_card();
763 bj->dealer_total += bj->dealer_cards[bj->num_dealer_cards].value;
764 bj->num_dealer_cards++;
767 while (bj->dealer_total > 21) {
768 temp = check_for_aces(bj->dealer_cards, bj->num_dealer_cards);
769 if(temp != -1) {
770 bj->dealer_cards[temp].is_soft_ace = false;
771 bj->dealer_total -= 10;
773 else
774 return;
778 /*****************************************************************************
779 * finish_game() completes the game once player's turn is over.
780 ******************************************************************************/
781 static void finish_game(struct game_context* bj) {
782 unsigned int rValue, w, h;
783 char str[19];
785 do {
786 finish_dealer(bj);
787 } while (bj->dealer_total < 17);
789 redraw_board(bj);
790 rValue = check_totals(bj);
792 if (rValue == 0) {
793 rb->snprintf(str, sizeof(str), " Bust! ");
794 bj->player_money -= bj->current_bet;
796 else if (rValue == 1) {
797 rb->snprintf(str, sizeof(str), " Sorry, you lost. ");
798 bj->player_money -= bj->current_bet;
800 else if (rValue == 2) {
801 rb->snprintf(str, sizeof(str), " Push ");
803 else if (rValue == 3) {
804 rb->snprintf(str, sizeof(str), " You won! ");
805 bj->player_money+= bj->current_bet;
807 else {
808 rb->snprintf(str, sizeof(str), " Blackjack! ");
809 bj->player_money += bj->current_bet * 3 / 2;
811 rb->lcd_getstringsize(str, &w, &h);
813 #if LCD_HEIGHT <= 64
814 rb->lcd_set_drawmode(DRMODE_BG+DRMODE_INVERSEVID);
815 rb->lcd_fillrect(0, LCD_HEIGHT/2, LCD_WIDTH, LCD_HEIGHT/2);
816 rb->lcd_set_drawmode(DRMODE_SOLID);
817 rb->lcd_putsxy(LCD_WIDTH/2 - w/2, LCD_HEIGHT/2 + h, str);
818 rb->snprintf(str, 12, "You have %d", bj->player_total);
819 rb->lcd_getstringsize(str, &w, &h);
820 rb->lcd_putsxy(LCD_WIDTH/2 - w/2, LCD_HEIGHT/2, str);
821 #else
822 rb->lcd_putsxy(LCD_WIDTH/2 - w/2, LCD_HEIGHT/2 - h/2, str);
823 #endif
824 rb->lcd_update();
827 /*****************************************************************************
828 * blackjack_loadgame() loads the saved game and returns load success.
829 ******************************************************************************/
830 static bool blackjack_loadgame(struct game_context* bj) {
831 signed int fd;
832 bool loaded = false;
834 /* open game file */
835 fd = rb->open(SAVE_FILE, O_RDONLY);
836 if(fd < 0) return false;
838 /* read in saved game */
839 if(rb->read(fd, bj, sizeof(struct game_context))
840 == (long)sizeof(struct game_context))
842 loaded = true;
845 rb->close(fd);
847 return loaded;
850 /*****************************************************************************
851 * blackjack_savegame() saves the current game state.
852 ******************************************************************************/
853 static void blackjack_savegame(struct game_context* bj) {
854 int fd;
856 if(!resume)
857 return;
858 /* write out the game state to the save file */
859 fd = rb->open(SAVE_FILE, O_WRONLY|O_CREAT);
860 if(fd < 0)
861 return;
862 rb->write(fd, bj, sizeof(struct game_context));
863 rb->close(fd);
866 /*****************************************************************************
867 * blackjack_get_yes_no() gets a yes/no answer from the user
868 ******************************************************************************/
869 static unsigned int blackjack_get_yes_no(char message[20]) {
870 int button;
871 unsigned int w, h, b, choice = 0;
872 bool breakout = false;
873 char message_yes[24], message_no[24];
875 rb->strcpy(message_yes, message);
876 rb->strcpy(message_no, message);
877 rb->strcat(message_yes, " Yes");
878 rb->strcat(message_no, " No");
879 rb->lcd_getstringsize(message_yes, &w, &h);
880 const char *stg[] = {message_yes, message_no};
882 #if LCD_HEIGHT <= 64
883 b = 2*h+1;
884 #else
885 b = h-1;
886 #endif
888 #ifdef HAVE_LCD_COLOR
889 rb->lcd_fillrect(LCD_WIDTH/2 - w/2, LCD_HEIGHT/2 + b, w+1, h+3);
890 rb->lcd_set_foreground(LCD_BLACK);
891 rb->lcd_set_background(LCD_WHITE);
892 #else
893 rb->lcd_set_drawmode(DRMODE_BG+DRMODE_INVERSEVID);
894 rb->lcd_fillrect(LCD_WIDTH/2 - w/2, LCD_HEIGHT/2 + b, w+1, h+3);
895 rb->lcd_set_drawmode(DRMODE_SOLID);
896 #endif
897 rb->lcd_drawrect(LCD_WIDTH/2 - w/2 - 1, LCD_HEIGHT/2 + b - 1, w+3, h+4);
899 while(!breakout) {
900 rb->lcd_putsxy(LCD_WIDTH/2 - w/2, LCD_HEIGHT/2 + b +1, stg[choice]);
901 rb->lcd_update_rect(LCD_WIDTH/2 - w/2 - 1, LCD_HEIGHT/2 + b -1,
902 w+3, h+4);
903 button = rb->button_get(true);
905 switch(button) {
906 case BJACK_LEFT:
907 case (BJACK_LEFT|BUTTON_REPEAT):
908 case BJACK_RIGHT:
909 case (BJACK_RIGHT|BUTTON_REPEAT):
910 choice ^= 1;
911 break;
912 case BJACK_SELECT: breakout = true;
913 break;
914 case BJACK_QUIT: breakout = true;
915 choice = 1;
916 break;
920 #if LCD_DEPTH > 1
921 rb->lcd_set_foreground(FG_COLOR);
922 rb->lcd_set_background(BG_COLOR);
923 #endif
924 return choice;
927 /*****************************************************************************
928 * blackjack_get_amount() gets an amount from the player to be used
929 ******************************************************************************/
930 static signed int blackjack_get_amount(char message[20], signed int lower_limit,
931 signed int upper_limit,
932 signed int start) {
933 int button;
934 char str[9];
935 bool breakout = false, changed = false;
936 unsigned int w, h;
937 signed int amount;
939 rb->lcd_getstringsize("A", &w, &h); /* find the size of one character */
941 if (start > upper_limit)
942 amount = upper_limit;
943 else if (start < lower_limit)
944 amount = lower_limit;
945 else
946 amount = start;
948 #if LCD_DEPTH > 1
949 rb->lcd_set_background(LCD_WHITE);
950 rb->lcd_set_foreground(LCD_BLACK);
951 #endif
953 #if LCD_HEIGHT <= 64
954 rb->lcd_clear_display();
955 rb->lcd_puts(0, 1, message);
956 rb->snprintf(str, 9, "$%d", amount);
957 rb->lcd_puts(0, 2, str);
958 rb->lcd_puts(0, 3, "RIGHT: +1");
959 rb->lcd_puts(0, 4, "LEFT: -1");
960 rb->lcd_puts(0, 5, "UP: +10");
961 rb->lcd_puts(0, 6, "DOWN: -10");
962 rb->lcd_update();
963 #else
964 rb->lcd_set_drawmode(DRMODE_BG+DRMODE_INVERSEVID);
965 rb->lcd_fillrect(LCD_WIDTH/2 - 9*w - 1, LCD_HEIGHT/2 - 4*h - 3,
966 37*w / 2, 8*h -3);
967 rb->lcd_set_drawmode(DRMODE_SOLID);
968 rb->lcd_drawrect(LCD_WIDTH/2 - 9*w - 1, LCD_HEIGHT/2 - 4*h - 3,
969 37*w / 2, 8*h -3);
970 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 4*h - 1, message);
971 rb->snprintf(str, 9, "$%d", amount);
972 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 3*h, str);
973 #if (CONFIG_KEYPAD == IPOD_4G_PAD) || \
974 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
975 (CONFIG_KEYPAD == IPOD_1G2G_PAD) || \
976 (CONFIG_KEYPAD == SANSA_E200_PAD) || \
977 (CONFIG_KEYPAD == SANSA_FUZE_PAD)
978 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - h-2, " >>|: +1");
979 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 1, " |<<: -1");
980 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 + h, "SCROLL+: +10");
981 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 + 2*h + 1, "SCROLL-: -10");
982 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
983 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - h-2, "RIGHT: +1");
984 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 1, "LEFT: -1");
985 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 + h, "SCROLL+: +10");
986 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 + 2*h + 1, "SCROLL-: -10");
987 #else
988 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - h-2, "RIGHT: +1");
989 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 1, "LEFT: -1");
990 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 + h, "UP: +10");
991 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 + 2*h + 1, "DOWN: -10");
992 #endif
993 rb->lcd_update_rect(LCD_WIDTH/2 - 9*w - 1, LCD_HEIGHT/2 - 4*h - 3,
994 37*w / 2, 8*h -3);
995 #endif
997 while(!breakout) {
998 button = rb->button_get(true);
1000 switch(button) {
1001 case BJACK_UP:
1002 case (BJACK_UP|BUTTON_REPEAT):
1003 if (amount + 10 < upper_limit + 1) {
1004 amount += 10;
1005 changed = true;
1007 break;
1008 case BJACK_DOWN:
1009 case (BJACK_DOWN|BUTTON_REPEAT):
1010 if (amount - 10 > lower_limit - 1) {
1011 amount -= 10;
1012 changed = true;
1014 break;
1015 case BJACK_RIGHT:
1016 case (BJACK_RIGHT|BUTTON_REPEAT):
1017 if (amount + 1 < upper_limit + 1) {
1018 amount++;
1019 changed = true;
1021 break;
1022 case BJACK_LEFT:
1023 case (BJACK_LEFT|BUTTON_REPEAT):
1024 if (amount - 1 > lower_limit - 1) {
1025 amount--;
1026 changed = true;
1028 break;
1029 #ifdef BJACK_MAX
1030 case BJACK_MAX :
1031 amount = upper_limit;
1032 changed = true;
1033 break;
1034 #endif
1035 #ifdef BJACK_MIN
1036 case BJACK_MIN :
1037 amount = lower_limit;
1038 changed = true;
1039 break;
1040 #endif
1041 case BJACK_QUIT:
1042 breakout = true;
1043 amount = 0;
1044 break;
1045 case BJACK_SELECT:
1046 breakout = true;
1047 break;
1050 if(changed) {
1051 rb->snprintf(str, 9, "$%d", amount);
1052 #if LCD_HEIGHT <= 64
1053 rb->lcd_puts(0, 2, str);
1054 rb->lcd_update();
1055 #else
1056 rb->lcd_set_drawmode(DRMODE_BG+DRMODE_INVERSEVID);
1057 rb->lcd_fillrect(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 3*h, 5*w, h);
1058 rb->lcd_set_drawmode(DRMODE_SOLID);
1059 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 3*h, str);
1060 rb->lcd_update_rect(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 3*h, 5*w, h);
1061 #endif
1062 changed = false;
1066 #if LCD_DEPTH > 1
1067 rb->lcd_set_foreground(FG_COLOR);
1068 rb->lcd_set_background(BG_COLOR);
1069 #endif
1070 rb->lcd_clear_display();
1071 return amount;
1074 /*****************************************************************************
1075 * blackjack_get_bet() gets the player's bet.
1076 ******************************************************************************/
1077 static void blackjack_get_bet(struct game_context* bj) {
1078 bj->current_bet = blackjack_get_amount("Please enter a bet", 10,
1079 bj->player_money, bj->current_bet);
1082 /*****************************************************************************
1083 * double_down() returns one final card then finishes the game
1084 ******************************************************************************/
1085 static void double_down(struct game_context* bj) {
1086 bj->current_bet *= 2;
1087 bj->player_cards[0][bj->num_player_cards[0]] = new_card();
1088 bj->player_total += bj->player_cards[0][bj->num_player_cards[0]].value;
1089 bj->num_player_cards[0]++;
1092 /*****************************************************************************
1093 * split() checks if the player wants to split and acts accordingly.
1094 * When bj->split_status is 1, no split occurred. 2 means the player split and 3
1095 * means a split has already occurred and the first hand is done.
1096 ******************************************************************************/
1097 static void split(struct game_context* bj) {
1098 if (blackjack_get_yes_no("Split?") != 0)
1099 bj->split_status = 1;
1100 else {
1101 bj->split_status = 2;
1102 bj->current_bet *= 2;
1103 bj->num_player_cards[0] = 1;
1104 bj->num_player_cards[1] = 1;
1105 bj->player_cards[1][0] = bj->player_cards[0][1];
1106 bj->player_total = bj->player_cards[0][0].value;
1110 /*****************************************************************************
1111 * insurance() see if the player wants to buy insurance and how much.
1112 ******************************************************************************/
1113 static unsigned int insurance(struct game_context* bj) {
1114 unsigned int insurance, max_amount;
1116 insurance = blackjack_get_yes_no("Buy Insurance?");
1117 bj->asked_insurance = true;
1118 max_amount = bj->current_bet < (unsigned int)bj->player_money ?
1119 bj->current_bet/2 : (unsigned int)bj->player_money;
1120 if (insurance != 0) return 0;
1122 insurance = blackjack_get_amount("How much?", 0, max_amount, 0);
1123 redraw_board(bj);
1124 return insurance;
1127 /*****************************************************************************
1128 * play_again() checks to see if the player wants to keep playing.
1129 ******************************************************************************/
1130 static unsigned int play_again(void) {
1131 return blackjack_get_yes_no("Play Again?");
1134 /*****************************************************************************
1135 * blackjack_help() displays help text.
1136 ******************************************************************************/
1137 static bool blackjack_help(void) {
1138 #define WORDS (sizeof help_text / sizeof (char*))
1139 static char *help_text[] = {
1140 "Blackjack", "", "Aim", "",
1141 "Try", "to", "get", "as", "close", "to", "21", "without", "going",
1142 "over", "or", "simply", "beat", "out", "the", "dealer", "for", "the",
1143 "best", "hand.", "", "",
1144 "Controls", "",
1145 BJACK_SELECT_NAME, ":", "hit", "/", "select", "",
1146 BJACK_STAY_NAME, ":", "stay", "",
1147 BJACK_DOUBLE_NAME, ":", "double", "down", "",
1148 BJACK_QUIT_NAME, ":", "go", "to", "menu", "",
1150 static struct style_text formation[]={
1151 { 0, TEXT_CENTER|TEXT_UNDERLINE },
1152 { 2, C_RED },
1153 { 26, C_RED },
1154 { -1, 0 }
1156 int button;
1158 rb->lcd_setfont(FONT_UI);
1159 #ifdef HAVE_LCD_COLOR
1160 rb->lcd_set_background(LCD_BLACK);
1161 rb->lcd_set_foreground(LCD_WHITE);
1162 #endif
1164 if (display_text(WORDS, help_text, formation, NULL))
1165 return true;
1166 do {
1167 button = rb->button_get(true);
1168 if (rb->default_event_handler(button) == SYS_USB_CONNECTED) {
1169 return true;
1171 } while( ( button == BUTTON_NONE )
1172 || ( button & (BUTTON_REL|BUTTON_REPEAT) ) );
1173 rb->lcd_setfont(FONT_SYSFIXED);
1174 return false;
1177 static int blackjack_menu_cb(int action, const struct menu_item_ex *this_item)
1179 int i = ((intptr_t)this_item);
1180 if(action == ACTION_REQUEST_MENUITEM
1181 && !resume && (i==0 || i==5))
1182 return ACTION_EXIT_MENUITEM;
1183 return action;
1186 /*****************************************************************************
1187 * blackjack_menu() is the initial menu at the start of the game.
1188 ******************************************************************************/
1189 static unsigned int blackjack_menu(void) {
1190 int selection = 0;
1191 bool breakout = false;
1193 MENUITEM_STRINGLIST(menu, "BlackJack Menu", blackjack_menu_cb,
1194 "Resume Game", "Start New Game",
1195 "High Scores", "Help",
1196 "Playback Control",
1197 "Quit without Saving", "Quit");
1199 while(!breakout) {
1200 switch(rb->do_menu(&menu, &selection, NULL, false)) {
1201 case 0:
1202 breakout = true;
1203 if(resume_file)
1204 rb->remove(SAVE_FILE);
1205 resume_file = false;
1206 break;
1207 case 1:
1208 breakout = true;
1209 resume = false;
1210 break;
1211 case 2:
1212 highscore_show(NUM_SCORES, highest, NUM_SCORES, false);
1213 break;
1214 case 3:
1215 if(blackjack_help())
1216 return BJ_USB;
1217 break;
1218 case 4:
1219 if (playback_control(NULL))
1220 return BJ_USB;
1221 break;
1222 case 5:
1223 return BJ_QUIT_WITHOUT_SAVING;
1224 case 6:
1225 if (resume)
1226 return BJ_QUIT;
1227 else
1228 return BJ_QUIT_WITHOUT_SAVING;
1230 case MENU_ATTACHED_USB:
1231 return BJ_USB;
1233 default:
1234 break;
1238 return 0;
1241 /*****************************************************************************
1242 * blackjack() is the main game subroutine, it returns the final game status.
1243 ******************************************************************************/
1244 static int blackjack(struct game_context* bj) {
1245 int button;
1246 unsigned int w, h, temp_var, done = 0, todo = 1;
1247 signed int temp;
1248 bool breakout = false;
1249 bool dbl_down = false;
1251 /********************
1252 * menu *
1253 ********************/
1254 temp_var = blackjack_menu();
1255 if (temp_var != 0)
1256 return temp_var;
1258 #if LCD_DEPTH > 1
1259 rb->lcd_set_background(BG_COLOR);
1260 rb->lcd_set_foreground(FG_COLOR);
1261 #endif
1263 /********************
1264 * init *
1265 ********************/
1266 blackjack_init(bj);
1268 /********************
1269 * play *
1270 ********************/
1272 resume_file = false;
1273 /* check for resumed game */
1274 if(resume) {
1275 resume = false;
1276 redraw_board(bj);
1277 if (bj->split_status == 2) {
1278 todo=2;
1279 player_x = bj->num_player_cards[0] * 10 + 4;
1281 else if (bj->split_status == 3) {
1282 player_x = bj->num_player_cards[1] * 10 + LCD_WIDTH/2 + 4;
1283 todo=2;
1284 done=1;
1287 else {
1288 bj->player_money = 1000;
1289 bj->current_bet = 10;
1290 blackjack_get_bet(bj);
1291 if (bj->current_bet == 0)
1292 return -1;
1293 rb->lcd_clear_display();
1294 deal_init_cards(bj);
1295 blackjack_drawtable(bj);
1298 rb->lcd_update();
1300 breakout = false;
1302 while(true){
1303 if(bj->player_total == 21 && bj->num_player_cards[0] == 2) {
1304 bj->is_blackjack = true;
1305 bj->end_hand = true;
1306 finish_game(bj);
1308 else if(bj->dealer_cards[1].is_soft_ace && !breakout &&
1309 !bj->asked_insurance) {
1310 temp_var = insurance(bj);
1311 if (bj->dealer_total == 21) {
1312 rb->splash(HZ, "Dealer has blackjack");
1313 bj->player_money += temp_var;
1314 bj->end_hand = true;
1315 breakout = true;
1316 redraw_board(bj);
1317 finish_game(bj);
1319 else {
1320 rb->splash(HZ, "Dealer does not have blackjack");
1321 bj->player_money -= temp_var;
1322 breakout = true;
1323 redraw_board(bj);
1324 rb->lcd_update();
1327 if(!bj->end_hand && bj->split_status == 0 &&
1328 bj->player_cards[0][0].num == bj->player_cards[0][1].num) {
1329 split(bj);
1330 redraw_board(bj);
1331 rb->lcd_update_rect(0, LCD_HEIGHT/2, LCD_WIDTH, LCD_HEIGHT/2);
1332 if (bj->split_status == 2) {
1333 todo++;
1334 player_x = bj->num_player_cards[0] * 10 + 4;
1338 while(!bj->end_hand && done < todo) {
1339 button = rb->button_get(true);
1341 switch(button) {
1342 case BJACK_SELECT:
1343 NEXT_CARD = new_card();
1344 bj->player_total += NEXT_CARD.value;
1345 draw_card(NEXT_CARD, true, player_x, player_y);
1346 bj->num_player_cards[done]++;
1347 if (bj->num_player_cards[done] == MAX_CARDS + 1) {
1348 redraw_board(bj);
1349 rb->lcd_update_rect(0, LCD_HEIGHT/2, LCD_WIDTH,
1350 LCD_HEIGHT/2);
1352 else if (bj->num_player_cards[done]>MAX_CARDS || todo > 1) {
1353 rb->lcd_update_rect(player_x, player_y, CARD_WIDTH+2,
1354 CARD_HEIGHT+2);
1355 player_x += 10;
1357 else {
1358 rb->lcd_update_rect(player_x, player_y, CARD_WIDTH+2,
1359 CARD_HEIGHT+2);
1360 player_x += CARD_WIDTH + 4;
1362 update_total(bj);
1364 break;
1365 case BJACK_STAY:
1366 bj->end_hand = true;
1367 break;
1368 case BJACK_DOUBLEDOWN:
1369 if ((signed int)bj->current_bet * 2 <
1370 bj->player_money + 1 &&
1371 bj->num_player_cards[0]==2 && todo==1) {
1372 double_down(bj);
1373 dbl_down = true;
1374 if (bj->player_total < 22) {
1375 bj->end_hand = true;
1376 finish_game(bj);
1379 else if((signed int)bj->current_bet * 2 >
1380 bj->player_money){
1381 rb->splash(HZ, "Not enough money to double down.");
1382 redraw_board(bj);
1383 rb->lcd_update();
1385 break;
1387 case BJACK_QUIT:
1388 resume = true;
1389 return BJ_END;
1392 while (bj->player_total > 21 && !bj->end_hand) {
1393 temp = check_for_aces(bj->player_cards[done],
1394 bj->num_player_cards[done]);
1395 if(temp != -1) {
1396 bj->player_cards[done][temp].is_soft_ace = false;
1397 bj->player_total -= 10;
1398 update_total(bj);
1399 if (dbl_down) {
1400 bj->end_hand = true;
1401 finish_game(bj);
1404 else
1405 bj->end_hand = true;
1408 if (bj->end_hand) {
1409 done++;
1410 if(todo > 1) {
1411 if (done == 2) {
1412 temp = bj->player_total;
1413 bj->player_total = temp_var;
1414 temp_var = temp;
1415 finish_game(bj);
1416 rb->lcd_getstringsize(" Split 1 ", &w, &h);
1417 rb->lcd_putsxy(LCD_WIDTH/2-w/2, LCD_HEIGHT/2-3*h/2,
1418 " Split 1 ");
1419 rb->lcd_update_rect(LCD_WIDTH/2-w/2, LCD_HEIGHT/2-3*h/2,
1420 w,h);
1421 bj->current_bet /= 2;
1422 rb->lcd_update_rect(LCD_WIDTH/2-w/2, LCD_HEIGHT/2-3*h/2,
1423 w,h);
1424 rb->sleep(HZ*2);
1425 bj->player_total = temp_var;
1426 finish_game(bj);
1427 rb->lcd_getstringsize(" Split 2 ", &w, &h);
1428 rb->lcd_putsxy(LCD_WIDTH/2-w/2, LCD_HEIGHT/2-3*h/2,
1429 " Split 2 ");
1430 rb->lcd_update_rect(LCD_WIDTH/2-w/2, LCD_HEIGHT/2-3*h/2,
1431 w,h);
1432 rb->sleep(HZ*2);
1434 else {
1435 bj->end_hand = false;
1436 bj->split_status = 3;
1437 temp_var = bj->player_total;
1438 bj->player_total = bj->player_cards[1][0].value;
1439 update_total(bj);
1440 redraw_board(bj);
1441 player_x += 10;
1442 rb->lcd_update();
1445 else
1446 finish_game(bj);
1450 if (bj->player_money < 10) {
1451 rb->sleep(HZ);
1452 return BJ_LOSE;
1455 if (bj->end_hand) { /* If hand is over */
1456 if (play_again() != 0) /* User wants to quit */
1457 return BJ_END;
1458 else { /* User keeps playing */
1459 breakout = false;
1460 temp = bj->current_bet;
1461 bj->current_bet = 0;
1462 redraw_board(bj);
1463 rb->lcd_update();
1464 bj->current_bet = temp;
1465 if(dbl_down) {
1466 bj->current_bet /= 2;
1467 dbl_down = false;
1469 done = 0;
1470 todo = 1;
1471 blackjack_init(bj);
1472 blackjack_get_bet(bj);
1473 if (bj->current_bet == 0)
1474 return BJ_END;
1475 deal_init_cards(bj);
1476 blackjack_drawtable(bj);
1477 rb->lcd_update();
1481 /* Never reached */
1482 return PLUGIN_OK;
1485 /*****************************************************************************
1486 * plugin entry point.
1487 ******************************************************************************/
1488 enum plugin_status plugin_start(const void* parameter)
1490 struct game_context bj;
1491 bool exit = false;
1493 (void)parameter;
1495 #if LCD_DEPTH > 1
1496 rb->lcd_set_backdrop(NULL);
1497 #endif
1499 /* load high scores */
1500 highscore_load(HIGH_SCORE,highest,NUM_SCORES);
1501 resume = blackjack_loadgame(&bj);
1502 resume_file = resume;
1504 rb->lcd_setfont(FONT_SYSFIXED);
1506 while(!exit) {
1507 switch(blackjack(&bj)){
1508 case BJ_LOSE:
1509 rb->splash(HZ, "Not enough money to continue");
1510 /* fall through to BJ_END */
1512 case BJ_END:
1513 if(!resume && bj.player_money > 10) {
1514 /* There is no level, so store -1 to blank column */
1515 int position = highscore_update(bj.player_money, -1, "",
1516 highest, NUM_SCORES);
1517 if (position==0)
1518 rb->splash(HZ*2, "New High Score");
1519 if (position != -1)
1520 highscore_show(position, highest, NUM_SCORES, false);
1522 break;
1524 case BJ_USB:
1525 highscore_save(HIGH_SCORE,highest,NUM_SCORES);
1526 return PLUGIN_USB_CONNECTED;
1528 case BJ_QUIT:
1529 rb->splash(HZ*1, "Saving game...");
1530 blackjack_savegame(&bj);
1531 /* fall through */
1533 case BJ_QUIT_WITHOUT_SAVING:
1534 exit = true;
1535 break;
1537 default:
1538 break;
1541 highscore_save(HIGH_SCORE,highest,NUM_SCORES);
1542 return PLUGIN_OK;