fix red
[Rockbox.git] / apps / plugins / blackjack.c
bloba23a8331287d0945f7401d7c5511ae8c9df579d8
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id: $
10 * Copyright (C) 2006 Tom Ross
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
20 #include "plugin.h"
21 #include "card_deck.h"
22 #include "card_back.h"
24 PLUGIN_HEADER
26 /* save files */
27 #define SCORE_FILE PLUGIN_GAMES_DIR "/blackjack.score"
28 #define SAVE_FILE PLUGIN_GAMES_DIR "/blackjack.save"
30 #define NUM_SCORES LCD_HEIGHT/8-2
32 /* final game return status */
33 #define BJ_END 3
34 #define BJ_USB 2
35 #define BJ_QUIT 1
36 #define BJ_LOSE 0
38 #if CONFIG_KEYPAD == RECORDER_PAD
39 #define BJACK_START BUTTON_ON
40 #define BJACK_QUIT BUTTON_OFF
41 #define BJACK_MAX (BUTTON_ON|BUTTON_UP)
42 #define BJACK_MIN (BUTTON_ON|BUTTON_DOWN)
43 #define BJACK_HIT BUTTON_F1
44 #define BJACK_STAY BUTTON_F2
45 #define BJACK_DOUBLEDOWN BUTTON_F3
46 #define BJACK_SCORES BUTTON_RIGHT
47 #define BJACK_RESUME BUTTON_PLAY
48 #define BJACK_UP BUTTON_UP
49 #define BJACK_DOWN BUTTON_DOWN
50 #define BJACK_RIGHT BUTTON_RIGHT
51 #define BJACK_LEFT BUTTON_LEFT
53 #elif CONFIG_KEYPAD == ONDIO_PAD
54 #define BJACK_START BUTTON_MENU
55 #define BJACK_QUIT BUTTON_OFF
56 #define BJACK_MAX (BUTTON_MENU|BUTTON_UP)
57 #define BJACK_MIN (BUTTON_MENU|BUTTON_DOWN)
58 #define BJACK_HIT BUTTON_LEFT
59 #define BJACK_STAY BUTTON_RIGHT
60 #define BJACK_DOUBLEDOWN BUTTON_UP
61 #define BJACK_SCORES BUTTON_UP
62 #define BJACK_RESUME BUTTON_DOWN
63 #define BJACK_UP BUTTON_UP
64 #define BJACK_DOWN BUTTON_DOWN
65 #define BJACK_RIGHT BUTTON_RIGHT
66 #define BJACK_LEFT BUTTON_LEFT
68 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
69 #define BJACK_START BUTTON_PLAY
70 #define BJACK_QUIT BUTTON_POWER
71 #define BJACK_MAX (BUTTON_PLAY|BUTTON_SCROLL_UP)
72 #define BJACK_MIN (BUTTON_PLAY|BUTTON_SCROLL_DOWN)
73 #define BJACK_HIT BUTTON_PLAY
74 #define BJACK_STAY BUTTON_FF
75 #define BJACK_DOUBLEDOWN BUTTON_REW
76 #define BJACK_SCORES BUTTON_LEFT
77 #define BJACK_RESUME BUTTON_RIGHT
78 #define BJACK_UP BUTTON_SCROLL_UP
79 #define BJACK_DOWN BUTTON_SCROLL_DOWN
80 #define BJACK_RIGHT BUTTON_RIGHT
81 #define BJACK_LEFT BUTTON_LEFT
83 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
84 (CONFIG_KEYPAD == IRIVER_H300_PAD)
85 #define BJACK_START BUTTON_ON
86 #define BJACK_QUIT BUTTON_OFF
87 #define BJACK_MAX (BUTTON_ON|BUTTON_UP)
88 #define BJACK_MIN (BUTTON_ON|BUTTON_DOWN)
89 #define BJACK_HIT BUTTON_ON
90 #define BJACK_STAY BUTTON_REC
91 #define BJACK_DOUBLEDOWN BUTTON_SELECT
92 #define BJACK_SCORES BUTTON_SELECT
93 #define BJACK_RESUME BUTTON_MODE
94 #define BJACK_UP BUTTON_UP
95 #define BJACK_DOWN BUTTON_DOWN
96 #define BJACK_RIGHT BUTTON_RIGHT
97 #define BJACK_LEFT BUTTON_LEFT
99 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \
100 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
101 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
102 #define BJACK_START BUTTON_SELECT
103 #define BJACK_QUIT BUTTON_MENU
104 #define BJACK_MAX (BUTTON_SELECT|BUTTON_SCROLL_FWD)
105 #define BJACK_MIN (BUTTON_SELECT|BUTTON_SCROLL_BACK)
106 #define BJACK_HIT BUTTON_SELECT
107 #define BJACK_STAY BUTTON_RIGHT
108 #define BJACK_DOUBLEDOWN BUTTON_LEFT
109 #define BJACK_SCORES BUTTON_RIGHT
110 #define BJACK_RESUME BUTTON_PLAY
111 #define BJACK_UP BUTTON_SCROLL_FWD
112 #define BJACK_DOWN BUTTON_SCROLL_BACK
113 #define BJACK_RIGHT BUTTON_RIGHT
114 #define BJACK_LEFT BUTTON_LEFT
116 #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD
117 #define BJACK_START BUTTON_PLAY
118 #define BJACK_QUIT BUTTON_POWER
119 #define BJACK_MAX (BUTTON_PLAY|BUTTON_UP)
120 #define BJACK_MIN (BUTTON_PLAY|BUTTON_DOWN)
121 #define BJACK_HIT BUTTON_SELECT
122 #define BJACK_STAY BUTTON_REC
123 #define BJACK_DOUBLEDOWN BUTTON_PLAY
124 #define BJACK_SCORES BUTTON_RIGHT
125 #define BJACK_RESUME BUTTON_DOWN
126 #define BJACK_UP BUTTON_UP
127 #define BJACK_DOWN BUTTON_DOWN
128 #define BJACK_RIGHT BUTTON_RIGHT
129 #define BJACK_LEFT BUTTON_LEFT
131 #elif CONFIG_KEYPAD == IRIVER_IFP7XX_PAD
132 #define BJACK_START BUTTON_MODE
133 #define BJACK_QUIT BUTTON_PLAY
134 #define BJACK_MAX (BUTTON_EQ|BUTTON_UP)
135 #define BJACK_MIN (BUTTON_EQ|BUTTON_DOWN)
136 #define BJACK_HIT BUTTON_EQ
137 #define BJACK_STAY BUTTON_MODE
138 #define BJACK_DOUBLEDOWN BUTTON_SELECT
139 #define BJACK_SCORES BUTTON_SELECT
140 #define BJACK_RESUME (BUTTON_EQ|BUTTON_MODE)
141 #define BJACK_UP BUTTON_UP
142 #define BJACK_DOWN BUTTON_DOWN
143 #define BJACK_RIGHT BUTTON_RIGHT
144 #define BJACK_LEFT BUTTON_LEFT
146 #elif CONFIG_KEYPAD == GIGABEAT_PAD
147 #define BJACK_START BUTTON_POWER
148 #define BJACK_QUIT BUTTON_A
149 #define BJACK_MAX BUTTON_VOL_UP
150 #define BJACK_MIN BUTTON_VOL_DOWN
151 #define BJACK_HIT BUTTON_VOL_UP
152 #define BJACK_STAY BUTTON_VOL_DOWN
153 #define BJACK_DOUBLEDOWN BUTTON_SELECT
154 #define BJACK_SCORES BUTTON_RIGHT
155 #define BJACK_RESUME BUTTON_MENU
156 #define BJACK_UP BUTTON_UP
157 #define BJACK_DOWN BUTTON_DOWN
158 #define BJACK_RIGHT BUTTON_RIGHT
159 #define BJACK_LEFT BUTTON_LEFT
161 #elif CONFIG_KEYPAD == SANSA_E200_PAD
162 #define BJACK_START BUTTON_SELECT
163 #define BJACK_QUIT BUTTON_POWER
164 #define BJACK_MAX (BUTTON_REC|BUTTON_UP)
165 #define BJACK_MIN (BUTTON_REC|BUTTON_DOWN)
166 #define BJACK_HIT BUTTON_SELECT
167 #define BJACK_STAY BUTTON_RIGHT
168 #define BJACK_DOUBLEDOWN BUTTON_LEFT
169 #define BJACK_SCORES BUTTON_UP
170 #define BJACK_RESUME BUTTON_REC
171 #define BJACK_UP BUTTON_SCROLL_FWD
172 #define BJACK_DOWN BUTTON_SCROLL_BACK
173 #define BJACK_RIGHT BUTTON_RIGHT
174 #define BJACK_LEFT BUTTON_LEFT
176 #elif CONFIG_KEYPAD == SANSA_C200_PAD
177 #define BJACK_START BUTTON_SELECT
178 #define BJACK_QUIT BUTTON_POWER
179 #define BJACK_MAX BUTTON_VOL_UP
180 #define BJACK_MIN BUTTON_VOL_DOWN
181 #define BJACK_HIT BUTTON_SELECT
182 #define BJACK_STAY BUTTON_RIGHT
183 #define BJACK_DOUBLEDOWN BUTTON_LEFT
184 #define BJACK_SCORES BUTTON_REC
185 #define BJACK_RESUME BUTTON_DOWN
186 #define BJACK_UP BUTTON_UP
187 #define BJACK_DOWN BUTTON_DOWN
188 #define BJACK_RIGHT BUTTON_RIGHT
189 #define BJACK_LEFT BUTTON_LEFT
191 #elif CONFIG_KEYPAD == ELIO_TPJ1022_PAD
192 #define BJACK_START BUTTON_MAIN
193 #define BJACK_QUIT BUTTON_POWER
194 #define BJACK_MAX (BUTTON_REC|BUTTON_UP)
195 #define BJACK_MIN (BUTTON_REC|BUTTON_DOWN)
196 #define BJACK_HIT BUTTON_MAIN
197 #define BJACK_STAY BUTTON_MENU
198 #define BJACK_DOUBLEDOWN BUTTON_DOWN
199 #define BJACK_SCORES BUTTON_UP
200 #define BJACK_RESUME BUTTON_FF
201 #define BJACK_UP BUTTON_UP
202 #define BJACK_DOWN BUTTON_DOWN
203 #define BJACK_RIGHT BUTTON_RIGHT
204 #define BJACK_LEFT BUTTON_LEFT
206 #elif CONFIG_KEYPAD == GIGABEAT_S_PAD
207 #define BJACK_START BUTTON_PLAY
208 #define BJACK_QUIT BUTTON_BACK
209 #define BJACK_MAX BUTTON_VOL_UP
210 #define BJACK_MIN BUTTON_VOL_DOWN
211 #define BJACK_HIT BUTTON_VOL_UP
212 #define BJACK_STAY BUTTON_VOL_DOWN
213 #define BJACK_DOUBLEDOWN BUTTON_SELECT
214 #define BJACK_SCORES BUTTON_RIGHT
215 #define BJACK_RESUME BUTTON_MENU
216 #define BJACK_UP BUTTON_UP
217 #define BJACK_DOWN BUTTON_DOWN
218 #define BJACK_RIGHT BUTTON_RIGHT
219 #define BJACK_LEFT BUTTON_LEFT
221 #elif CONFIG_KEYPAD == MROBE100_PAD
223 #define BJACK_START BUTTON_SELECT
224 #define BJACK_QUIT BUTTON_POWER
225 #define BJACK_MAX BUTTON_MENU
226 #define BJACK_MIN BUTTON_DISPLAY
227 #define BJACK_HIT BUTTON_MENU
228 #define BJACK_STAY BUTTON_DISPLAY
229 #define BJACK_DOUBLEDOWN BUTTON_SELECT
230 #define BJACK_SCORES BUTTON_RIGHT
231 #define BJACK_RESUME BUTTON_PLAY
232 #define BJACK_UP BUTTON_UP
233 #define BJACK_DOWN BUTTON_DOWN
234 #define BJACK_RIGHT BUTTON_RIGHT
235 #define BJACK_LEFT BUTTON_LEFT
237 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
239 #define BJACK_START BUTTON_RC_PLAY
240 #define BJACK_QUIT BUTTON_RC_REC
241 #define BJACK_MAX (BUTTON_RC_PLAY|BUTTON_RC_VOL_UP)
242 #define BJACK_MIN (BUTTON_RC_PLAY|BUTTON_RC_VOL_DOWN)
243 #define BJACK_HIT BUTTON_RC_PLAY
244 #define BJACK_STAY BUTTON_RC_FF
245 #define BJACK_DOUBLEDOWN BUTTON_RC_REW
246 #define BJACK_SCORES BUTTON_RC_MENU
247 #define BJACK_RESUME BUTTON_RC_MODE
248 #define BJACK_UP BUTTON_RC_VOL_UP
249 #define BJACK_DOWN BUTTON_RC_VOL_DOWN
250 #define BJACK_RIGHT BUTTON_RC_FF
251 #define BJACK_LEFT BUTTON_RC_REW
253 #elif CONFIG_KEYPAD == COWOND2_PAD
254 #define BJACK_QUIT BUTTON_POWER
255 #define BJACK_DOUBLEDOWN BUTTON_MINUS
256 #define BJACK_SCORES BUTTON_MENU
258 #else
259 #error No keymap defined!
260 #endif
262 #ifdef HAVE_TOUCHPAD
263 #ifndef BJACK_START
264 #define BJACK_START BUTTON_CENTER
265 #endif
266 #ifndef BJACK_HIT
267 #define BJACK_HIT BUTTON_CENTER
268 #endif
269 #ifndef BJACK_MAX
270 #define BJACK_MAX BUTTON_TOPRIGHT
271 #endif
272 #ifndef BJACK_MIN
273 #define BJACK_MIN BUTTON_TOPLEFT
274 #endif
275 #ifndef BJACK_RESUME
276 #define BJACK_RESUME BUTTON_BOTTOMRIGHT
277 #endif
278 #ifndef BJACK_STAY
279 #define BJACK_STAY BUTTON_BOTTOMLEFT
280 #endif
281 #ifndef BJACK_UP
282 #define BJACK_UP BUTTON_TOPMIDDLE
283 #endif
284 #ifndef BJACK_DOWN
285 #define BJACK_DOWN BUTTON_BOTTOMMIDDLE
286 #endif
287 #ifndef BJACK_RIGHT
288 #define BJACK_RIGHT BUTTON_MIDRIGHT
289 #endif
290 #ifndef BJACK_LEFT
291 #define BJACK_LEFT BUTTON_MIDLEFT
292 #endif
294 #endif
296 #ifdef HAVE_LCD_COLOR
297 #define BG_COLOR LCD_RGBPACK(0,157,0)
298 #define FG_COLOR LCD_WHITE
299 #elif LCD_DEPTH > 1
300 #define BG_COLOR LCD_WHITE
301 #define FG_COLOR LCD_BLACK
302 #endif
304 #define CARD_WIDTH BMPWIDTH_card_back
305 #define CARD_HEIGHT BMPHEIGHT_card_back
307 /* This is the max amount of cards onscreen before condensing */
308 #define MAX_CARDS LCD_WIDTH/(CARD_WIDTH+4)
310 extern const fb_data card_deck[];
311 extern const fb_data card_back[];
313 #define NEXT_CARD bj->player_cards[done][bj->num_player_cards[done]]
315 /* global rockbox api */
316 static const struct plugin_api* rb;
318 MEM_FUNCTION_WRAPPERS(rb);
320 /* dealer and player card positions */
321 unsigned int dealer_x, dealer_y, player_x, player_y;
323 typedef struct card {
324 unsigned int value; /* Card's value in Blackjack */
325 unsigned int num; /* Value on card face 0-12 (0=Ace, 1=2, 11=Q) */
326 unsigned int suit; /* 0:Spades, 1:Hearts, 2: Clubs; 3: Diamonds */
327 bool is_soft_ace;
328 } card;
330 typedef struct game_context {
331 struct card player_cards[2][22]; /* 22 Cards means the deal was all aces */
332 struct card dealer_cards[22]; /* That is the worst-case scenario */
333 unsigned int player_total;
334 unsigned int dealer_total;
335 signed int player_money;
336 unsigned int num_player_cards[2];
337 unsigned int num_dealer_cards;
338 unsigned int current_bet;
339 unsigned int split_status; /* 0 = split hasn't been asked, *
340 * 1 = split did not occur *
341 * 2 = split occurred *
342 * 3 = split occurred and 1st hand done */
343 bool is_blackjack;
344 bool end_hand;
345 bool asked_insurance;
346 signed short highscores[NUM_SCORES];
347 bool resume;
348 bool dirty;
349 } game_context;
351 /*****************************************************************************
352 * blackjack_init() initializes blackjack data structures.
353 ******************************************************************************/
354 static void blackjack_init(struct game_context* bj) {
355 /* seed the rand generator */
356 rb->srand(*rb->current_tick);
358 /* reset card positions */
359 dealer_x = 4;
360 dealer_y = LCD_HEIGHT/4 - CARD_HEIGHT/2;
361 player_x = 4;
362 player_y = LCD_HEIGHT - LCD_HEIGHT/4 - CARD_HEIGHT/2;
364 /* check for resumed game */
365 if(bj->resume) return;
367 /* reset scoring */
368 bj->player_total = 0;
369 bj->dealer_total = 0;
370 bj->num_player_cards[0] = 2;
371 bj->num_player_cards[1] = 0;
372 bj->num_dealer_cards = 2;
373 bj->end_hand = false;
374 bj->split_status = 0;
375 bj->is_blackjack = false;
376 bj->asked_insurance = false;
379 /*****************************************************************************
380 * blackjack_drawtable() draws the table and some text.
381 ******************************************************************************/
382 static void blackjack_drawtable(struct game_context* bj) {
383 unsigned int w, h, y_loc;
384 char str[10];
386 #if LCD_HEIGHT <= 64
387 rb->lcd_getstringsize("Bet", &w, &h);
388 rb->lcd_putsxy(LCD_WIDTH - w, 2*h + 1, "Bet");
389 rb->snprintf(str, 9, "$%d", bj->current_bet);
390 rb->lcd_getstringsize(str, &w, &h);
391 rb->lcd_putsxy(LCD_WIDTH - w, 3*h + 1, str);
392 y_loc = LCD_HEIGHT/2;
393 #else
394 rb->lcd_getstringsize("Bet", &w, &h);
395 rb->lcd_putsxy(LCD_WIDTH - w, 5*h / 2, "Bet");
396 rb->snprintf(str, 9, "$%d", bj->current_bet);
397 rb->lcd_getstringsize(str, &w, &h);
398 rb->lcd_putsxy(LCD_WIDTH - w, 7*h / 2, str);
399 rb->lcd_hline(0, LCD_WIDTH, LCD_HEIGHT/2);
400 y_loc = LCD_HEIGHT/2 + h;
401 #endif
403 rb->lcd_putsxy(0,0, "Dealer");
404 rb->lcd_getstringsize("Player", &w, &h);
405 rb->lcd_putsxy(0, y_loc, "Player");
406 rb->lcd_getstringsize("Total", &w, &h);
407 rb->lcd_putsxy(LCD_WIDTH - w, y_loc, "Total");
408 rb->lcd_getstringsize("Money", &w, &h);
409 rb->lcd_putsxy(LCD_WIDTH - w, 0, "Money");
410 rb->snprintf(str, 9, "$%d", bj->player_money - bj->current_bet);
411 rb->lcd_getstringsize(str, &w, &h);
412 rb->lcd_putsxy(LCD_WIDTH - w, h + 1, str);
413 rb->snprintf(str, 3, "%d", bj->player_total);
414 rb->lcd_getstringsize(str, &w, &h);
415 rb->lcd_putsxy(LCD_WIDTH - w, y_loc + h, str);
418 /*****************************************************************************
419 * find_value() is passed a card and returns its blackjack value.
420 ******************************************************************************/
421 static unsigned int find_value(unsigned int number) {
422 unsigned int thisValue;
423 if (number == 0)
424 thisValue = 11; /* Aces get a value of 11 at first */
425 else if (number < 10)
426 thisValue = number + 1;
427 else
428 thisValue = 10; /* Anything 10 or higher gets a value of 10 */
430 return thisValue;
433 /*****************************************************************************
434 * draw_card() draws a card to the screen.
435 ******************************************************************************/
436 static void draw_card(struct card temp_card, bool shown, unsigned int x,
437 unsigned int y) {
438 if(shown)
439 rb->lcd_bitmap_part(card_deck, CARD_WIDTH*temp_card.num,
440 CARD_HEIGHT*temp_card.suit, BMPWIDTH_card_deck,
441 x+1, y+1, CARD_WIDTH, CARD_HEIGHT);
442 else
443 rb->lcd_bitmap(card_back, x+1, y+1,CARD_WIDTH, CARD_HEIGHT);
444 #if LCD_DEPTH > 1
445 rb->lcd_set_foreground(LCD_BLACK);
446 #endif
448 /* Print outlines */
449 #if CARD_WIDTH >= 26
450 rb->lcd_hline(x+2, x+CARD_WIDTH-1, y);
451 rb->lcd_hline(x+2, x+CARD_WIDTH-1, y+CARD_HEIGHT+1);
452 rb->lcd_vline(x, y+2, y+CARD_HEIGHT-3);
453 rb->lcd_vline(x+CARD_WIDTH+1, y+2, y+CARD_HEIGHT-1);
454 rb->lcd_drawpixel(x+1, y+1);
455 rb->lcd_drawpixel(x+1, y+CARD_HEIGHT);
456 rb->lcd_drawpixel(x+CARD_WIDTH, y+1);
457 rb->lcd_drawpixel(x+CARD_WIDTH, y+CARD_HEIGHT);
458 #else
459 rb->lcd_hline(x+1, x+CARD_WIDTH, y);
460 rb->lcd_hline(x+1, x+CARD_WIDTH, y+CARD_HEIGHT+1);
461 rb->lcd_vline(x, y+1, y+CARD_HEIGHT);
462 rb->lcd_vline(x+CARD_WIDTH+1, y+1, y+CARD_HEIGHT);
463 #endif
465 #if LCD_DEPTH > 1
466 rb->lcd_set_foreground(FG_COLOR);
467 #endif
470 /*****************************************************************************
471 * new_card() initializes a new card and gives it values.
472 ******************************************************************************/
473 static struct card new_card(void) {
474 struct card new_card;
475 new_card.suit = rb->rand()%4; /* Random number 0-3 */
476 new_card.num = rb->rand()%13; /* Random number 0-12 */
477 new_card.value = find_value(new_card.num);
478 new_card.is_soft_ace = new_card.num == 0 ? true : false;
479 return new_card;
482 /*****************************************************************************
483 * deal_init_card() deals and draws to the screen the player's and dealer's
484 * initial cards.
485 ******************************************************************************/
486 static void deal_init_cards(struct game_context* bj) {
487 bj->dealer_cards[0] = new_card();
488 bj->dealer_total += bj->dealer_cards[0].value;
490 draw_card(bj->dealer_cards[0], false, dealer_x, dealer_y);
492 bj->dealer_cards[1] = new_card();
493 bj->dealer_total += bj->dealer_cards[1].value;
494 draw_card(bj->dealer_cards[1], true, dealer_x + CARD_WIDTH + 4, dealer_y);
496 bj->player_cards[0][0] = new_card();
497 bj->player_total += bj->player_cards[0][0].value;
498 draw_card(bj->player_cards[0][0], true, player_x, player_y);
499 player_x += CARD_WIDTH + 4;
501 bj->player_cards[0][1] = new_card();
502 bj->player_total += bj->player_cards[0][1].value;
503 draw_card(bj->player_cards[0][1], true, player_x, player_y);
504 player_x += CARD_WIDTH + 4;
507 /*****************************************************************************
508 * redraw_board() redraws all the cards and the board
509 ******************************************************************************/
510 static void redraw_board(struct game_context* bj) {
511 unsigned int i, n, upper_bound;
512 rb->lcd_clear_display();
514 blackjack_drawtable(bj);
515 player_x = 4;
516 dealer_x = 4;
517 upper_bound = bj->split_status > 1 ? 2 : 1;
519 for (i = 0; i < bj->num_dealer_cards; i++) {
520 if (!bj->end_hand) {
521 draw_card(bj->dealer_cards[0], false, dealer_x, dealer_y);
523 /* increment i so the dealer's first card isn't displayed */
524 i++;
525 dealer_x += CARD_WIDTH + 4;
527 draw_card(bj->dealer_cards[i], true, dealer_x, dealer_y);
529 if (bj->num_dealer_cards > MAX_CARDS-1)
530 dealer_x += 10;
531 else
532 dealer_x += CARD_WIDTH + 4;
535 for (n = 0; n < upper_bound; n++) {
536 for (i = 0; i < bj->num_player_cards[n]; i++) {
537 draw_card(bj->player_cards[n][i], true, player_x, player_y);
538 if (bj->split_status>1 || bj->num_player_cards[n]>MAX_CARDS)
539 player_x += 10;
540 else
541 player_x += CARD_WIDTH + 4;
543 if (bj->split_status > 1)
544 player_x = LCD_WIDTH/2 + 4;
548 /*****************************************************************************
549 * update_total updates the player's total
550 ******************************************************************************/
551 static void update_total(struct game_context* bj) {
552 char total[3];
553 unsigned int w, h;
554 rb->snprintf(total, 3, "%d", bj->player_total);
555 rb->lcd_getstringsize(total, &w, &h);
556 #if LCD_HEIGHT > 64
557 h *= 2;
558 #endif
559 rb->lcd_putsxy(LCD_WIDTH - w, LCD_HEIGHT/2 + h, total);
560 rb->lcd_update_rect(LCD_WIDTH - w, LCD_HEIGHT/2 + h, w, h);
564 /*****************************************************************************
565 * check_for_aces() is passed an array of cards and returns where an ace is
566 * located. Otherwise, returns -1.
567 ******************************************************************************/
568 static signed int check_for_aces(struct card temp_cards[],
569 unsigned int size) {
570 unsigned int i;
571 for(i = 0; i < size; i++) {
572 if (temp_cards[i].is_soft_ace == true)
573 return i;
575 return -1;
578 /*****************************************************************************
579 * check_totals() compares player and dealer totals.
580 * 0: bust 1: loss, 2: push, 3: win, 4: blackjack, 5: something's not right...
581 ******************************************************************************/
582 static unsigned int check_totals(struct game_context* bj)
584 unsigned int temp;
585 if (bj->player_total > 21)
586 temp = 0;
587 else if (bj->player_total == 21 && bj->is_blackjack)
588 if (bj->dealer_total == 21 && bj->num_dealer_cards == 2)
589 temp = 2;
590 else
591 temp = 4;
592 else if (bj->player_total == bj->dealer_total)
593 temp = 2;
594 else if (bj->dealer_total > 21 && bj->player_total < 22)
595 temp = 3;
596 else if (bj->dealer_total > bj->player_total)
597 temp = 1;
598 else if (bj->player_total > bj->dealer_total)
599 temp = 3;
600 else
601 temp = 5;
603 return temp;
606 /*****************************************************************************
607 * finish_dealer() draws cards for the dealer until he has 17 or more.
608 ******************************************************************************/
609 static void finish_dealer(struct game_context* bj) {
610 signed int temp = 0;
612 if (bj->dealer_total > 16 && bj->dealer_total < 22)
613 return;
615 while (bj->dealer_total < 17) {
616 bj->dealer_cards[bj->num_dealer_cards] = new_card();
617 bj->dealer_total += bj->dealer_cards[bj->num_dealer_cards].value;
618 bj->num_dealer_cards++;
621 while (bj->dealer_total > 21) {
622 temp = check_for_aces(bj->dealer_cards, bj->num_dealer_cards);
623 if(temp != -1) {
624 bj->dealer_cards[temp].is_soft_ace = false;
625 bj->dealer_total -= 10;
627 else
628 return;
632 /*****************************************************************************
633 * finish_game() completes the game once player's turn is over.
634 ******************************************************************************/
635 static void finish_game(struct game_context* bj) {
636 unsigned int rValue, w, h;
637 char str[19];
639 do {
640 finish_dealer(bj);
641 } while (bj->dealer_total < 17);
643 redraw_board(bj);
644 rValue = check_totals(bj);
646 if (rValue == 0) {
647 rb->snprintf(str, sizeof(str), " Bust! ");
648 bj->player_money -= bj->current_bet;
650 else if (rValue == 1) {
651 rb->snprintf(str, sizeof(str), " Sorry, you lost. ");
652 bj->player_money -= bj->current_bet;
654 else if (rValue == 2) {
655 rb->snprintf(str, sizeof(str), " Push ");
657 else if (rValue == 3) {
658 rb->snprintf(str, sizeof(str), " You won! ");
659 bj->player_money+= bj->current_bet;
661 else {
662 rb->snprintf(str, sizeof(str), " Blackjack! ");
663 bj->player_money += bj->current_bet * 3 / 2;
665 rb->lcd_getstringsize(str, &w, &h);
667 #if LCD_HEIGHT <= 64
668 rb->lcd_set_drawmode(DRMODE_BG+DRMODE_INVERSEVID);
669 rb->lcd_fillrect(0, LCD_HEIGHT/2, LCD_WIDTH, LCD_HEIGHT/2);
670 rb->lcd_set_drawmode(DRMODE_SOLID);
671 rb->lcd_putsxy(LCD_WIDTH/2 - w/2, LCD_HEIGHT/2 + h, str);
672 rb->snprintf(str, 12, "You have %d", bj->player_total);
673 rb->lcd_getstringsize(str, &w, &h);
674 rb->lcd_putsxy(LCD_WIDTH/2 - w/2, LCD_HEIGHT/2, str);
675 #else
676 rb->lcd_putsxy(LCD_WIDTH/2 - w/2, LCD_HEIGHT/2 - h/2, str);
677 #endif
678 rb->lcd_update();
681 /*****************************************************************************
682 * blackjack_recordscore() inserts a high score into the high scores list and
683 * returns the high score position.
684 ******************************************************************************/
685 static unsigned int blackjack_recordscore(struct game_context* bj) {
686 unsigned int i;
687 unsigned int position = 0;
688 signed short current, temp;
690 /* calculate total score */
691 current = bj->player_money;
692 if(current <= 10) return 0;
694 /* insert the current score into the high scores */
695 for(i=0; i<NUM_SCORES; i++) {
696 if(current >= bj->highscores[i]) {
697 if(!position) {
698 position = i+1;
699 bj->dirty = true;
701 temp = bj->highscores[i];
702 bj->highscores[i] = current;
703 current = temp;
707 return position;
710 /*****************************************************************************
711 * blackjack_loadscores() loads the high scores saved file.
712 ******************************************************************************/
713 static void blackjack_loadscores(struct game_context* bj) {
714 signed int fd;
716 bj->dirty = false;
718 /* clear high scores */
719 rb->memset(bj->highscores, 0, sizeof(bj->highscores));
721 /* open scores file */
722 fd = rb->open(SCORE_FILE, O_RDONLY);
723 if(fd < 0) return;
725 /* read in high scores */
726 if(rb->read(fd, bj->highscores, sizeof(bj->highscores)) <= 0) {
727 /* scores are bad, reset */
728 rb->memset(bj->highscores, 0, sizeof(bj->highscores));
731 rb->close(fd);
734 /*****************************************************************************
735 * blackjack_savescores() saves the high scores saved file.
736 ******************************************************************************/
737 static void blackjack_savescores(struct game_context* bj) {
738 unsigned int fd;
740 /* write out the high scores to the save file */
741 fd = rb->open(SCORE_FILE, O_WRONLY|O_CREAT);
742 rb->write(fd, bj->highscores, sizeof(bj->highscores));
743 rb->close(fd);
744 bj->dirty = false;
747 /*****************************************************************************
748 * blackjack_loadgame() loads the saved game and returns load success.
749 ******************************************************************************/
750 static bool blackjack_loadgame(struct game_context* bj) {
751 signed int fd;
752 bool loaded = false;
754 /* open game file */
755 fd = rb->open(SAVE_FILE, O_RDONLY);
756 if(fd < 0) return loaded;
758 /* read in saved game */
759 while(true) {
760 if(rb->read(fd, &bj->player_money, sizeof(bj->player_money)) <= 0) break;
761 if(rb->read(fd, &bj->player_total, sizeof(bj->player_total)) <= 0) break;
762 if(rb->read(fd, &bj->dealer_total, sizeof(bj->dealer_total)) <= 0) break;
763 if(rb->read(fd, &bj->num_player_cards, sizeof(bj->num_player_cards))<=0)
764 break;
765 if(rb->read(fd, &bj->num_dealer_cards, sizeof(bj->num_dealer_cards))<=0)
766 break;
767 if(rb->read(fd, &bj->current_bet, sizeof(bj->current_bet)) <= 0) break;
768 if(rb->read(fd, &bj->is_blackjack, sizeof(bj->is_blackjack)) <= 0) break;
769 if(rb->read(fd, &bj->split_status, sizeof(bj->split_status)) <= 0) break;
770 if(rb->read(fd, &bj->asked_insurance, sizeof(bj->asked_insurance)) <= 0)
771 break;
772 if(rb->read(fd, &bj->end_hand, sizeof(bj->end_hand)) <= 0) break;
773 if(rb->read(fd, &bj->player_cards, sizeof(bj->player_cards)) <= 0) break;
774 if(rb->read(fd, &bj->dealer_cards, sizeof(bj->dealer_cards)) <= 0) break;
775 bj->resume = true;
776 loaded = true;
777 break;
780 rb->close(fd);
782 /* delete saved file */
783 rb->remove(SAVE_FILE);
784 return loaded;
787 /*****************************************************************************
788 * blackjack_savegame() saves the current game state.
789 ******************************************************************************/
790 static void blackjack_savegame(struct game_context* bj) {
791 unsigned int fd;
793 /* write out the game state to the save file */
794 fd = rb->open(SAVE_FILE, O_WRONLY|O_CREAT);
795 rb->write(fd, &bj->player_money, sizeof(bj->player_money));
796 rb->write(fd, &bj->player_total, sizeof(bj->player_total));
797 rb->write(fd, &bj->dealer_total, sizeof(bj->dealer_total));
798 rb->write(fd, &bj->num_player_cards, sizeof(bj->num_player_cards));
799 rb->write(fd, &bj->num_dealer_cards, sizeof(bj->num_dealer_cards));
800 rb->write(fd, &bj->current_bet, sizeof(bj->current_bet));
801 rb->write(fd, &bj->is_blackjack, sizeof(bj->is_blackjack));
802 rb->write(fd, &bj->split_status, sizeof(bj->split_status));
803 rb->write(fd, &bj->asked_insurance, sizeof(bj->asked_insurance));
804 rb->write(fd, &bj->end_hand, sizeof(bj->end_hand));
805 rb->write(fd, &bj->player_cards, sizeof(bj->player_cards));
806 rb->write(fd, &bj->dealer_cards, sizeof(bj->dealer_cards));
807 rb->close(fd);
809 bj->resume = true;
812 /*****************************************************************************
813 * blackjack_callback() is the default event handler callback which is called
814 * on usb connect and shutdown.
815 ******************************************************************************/
816 static void blackjack_callback(void* param) {
817 struct game_context* bj = (struct game_context*) param;
818 if(bj->dirty) {
819 rb->splash(HZ, "Saving high scores...");
820 blackjack_savescores(bj);
824 /*****************************************************************************
825 * blackjack_get_yes_no() gets a yes/no answer from the user
826 ******************************************************************************/
827 static unsigned int blackjack_get_yes_no(char message[20]) {
828 int button;
829 unsigned int w, h, b, choice = 0;
830 bool breakout = false;
831 char message_yes[24], message_no[24];
833 rb->strcpy(message_yes, message);
834 rb->strcpy(message_no, message);
835 rb->strcat(message_yes, " Yes");
836 rb->strcat(message_no, " No");
837 rb->lcd_getstringsize(message_yes, &w, &h);
838 const char *stg[] = {message_yes, message_no};
840 #if LCD_HEIGHT <= 64
841 b = 2*h+1;
842 #else
843 b = h-1;
844 #endif
846 #ifdef HAVE_LCD_COLOR
847 rb->lcd_fillrect(LCD_WIDTH/2 - w/2, LCD_HEIGHT/2 + b, w+1, h+3);
848 rb->lcd_set_foreground(LCD_BLACK);
849 rb->lcd_set_background(LCD_WHITE);
850 #else
851 rb->lcd_set_drawmode(DRMODE_BG+DRMODE_INVERSEVID);
852 rb->lcd_fillrect(LCD_WIDTH/2 - w/2, LCD_HEIGHT/2 + b, w+1, h+3);
853 rb->lcd_set_drawmode(DRMODE_SOLID);
854 #endif
855 rb->lcd_drawrect(LCD_WIDTH/2 - w/2 - 1, LCD_HEIGHT/2 + b - 1, w+3, h+4);
857 while(!breakout) {
858 rb->lcd_putsxy(LCD_WIDTH/2 - w/2, LCD_HEIGHT/2 + b +1, stg[choice]);
859 rb->lcd_update_rect(LCD_WIDTH/2 - w/2 - 1, LCD_HEIGHT/2 + b -1,
860 w+3, h+4);
861 button = rb->button_get(true);
863 switch(button) {
864 case BJACK_LEFT:
865 case (BJACK_LEFT|BUTTON_REPEAT):
866 case BJACK_RIGHT:
867 case (BJACK_RIGHT|BUTTON_REPEAT):
868 choice ^= 1;
869 break;
870 case BJACK_START: breakout = true;
871 break;
872 case BJACK_QUIT: breakout = true;
873 choice = BJ_QUIT;
874 break;
878 #if LCD_DEPTH > 1
879 rb->lcd_set_foreground(FG_COLOR);
880 rb->lcd_set_background(BG_COLOR);
881 #endif
882 return choice;
885 /*****************************************************************************
886 * blackjack_get_amount() gets an amount from the player to be used
887 ******************************************************************************/
888 static signed int blackjack_get_amount(char message[20], signed int lower_limit,
889 signed int upper_limit,
890 signed int start) {
891 int button;
892 char str[6];
893 bool changed = false;
894 unsigned int w, h;
895 signed int amount;
897 rb->lcd_getstringsize("A", &w, &h); /* find the size of one character */
899 if (start > upper_limit)
900 amount = upper_limit;
901 else if (start < lower_limit)
902 amount = lower_limit;
903 else
904 amount = start;
906 #if LCD_DEPTH > 1
907 rb->lcd_set_background(LCD_WHITE);
908 rb->lcd_set_foreground(LCD_BLACK);
909 #endif
911 #if LCD_HEIGHT <= 64
912 rb->lcd_clear_display();
913 rb->lcd_puts(0, 1, message);
914 rb->snprintf(str, 9, "$%d", amount);
915 rb->lcd_puts(0, 2, str);
916 rb->lcd_puts(0, 3, "RIGHT: +1");
917 rb->lcd_puts(0, 4, "LEFT: -1");
918 rb->lcd_puts(0, 5, "UP: +10");
919 rb->lcd_puts(0, 6, "DOWN: -10");
920 rb->lcd_update();
921 #else
922 rb->lcd_set_drawmode(DRMODE_BG+DRMODE_INVERSEVID);
923 rb->lcd_fillrect(LCD_WIDTH/2 - 9*w - 1, LCD_HEIGHT/2 - 4*h - 3, 37*w / 2,
924 8*h -3);
925 rb->lcd_set_drawmode(DRMODE_SOLID);
926 rb->lcd_drawrect(LCD_WIDTH/2 - 9*w - 1, LCD_HEIGHT/2 - 4*h - 3, 37*w / 2,
927 8*h -3);
928 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 4*h - 1, message);
929 rb->snprintf(str, 9, "$%d", amount);
930 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 3*h, str);
931 #if (CONFIG_KEYPAD == IPOD_4G_PAD) || \
932 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
933 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
934 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - h-2, " >>|: +1");
935 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 1, " |<<: -1");
936 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 + h, "SCROLL+: +10");
937 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 + 2*h + 1, "SCROLL-: -10");
938 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
939 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - h-2, "RIGHT: +1");
940 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 1, "LEFT: -1");
941 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 + h, "SCROLL+: +10");
942 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 + 2*h + 1, "SCROLL-: -10");
943 #else
944 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - h-2, "RIGHT: +1");
945 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 1, "LEFT: -1");
946 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 + h, "UP: +10");
947 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 + 2*h + 1, "DOWN: -10");
948 #endif
949 rb->lcd_update_rect(LCD_WIDTH/2 - 9*w - 2, LCD_HEIGHT/2 - 9*h/2, 37*w/2 + 1,
950 8*h-2);
951 #endif
953 while(true) {
954 button = rb->button_get(true);
956 switch(button) {
957 case BJACK_UP:
958 case (BJACK_UP|BUTTON_REPEAT):
959 if (amount + 10 < upper_limit + 1) {
960 amount += 10;
961 changed = true;
963 break;
964 case BJACK_DOWN:
965 case (BJACK_DOWN|BUTTON_REPEAT):
966 if (amount - 10 > lower_limit - 1) {
967 amount -= 10;
968 changed = true;
970 break;
971 case BJACK_RIGHT:
972 case (BJACK_RIGHT|BUTTON_REPEAT):
973 if (amount + 1 < upper_limit + 1) {
974 amount++;
975 changed = true;
977 break;
978 case BJACK_LEFT:
979 case (BJACK_LEFT|BUTTON_REPEAT):
980 if (amount - 1 > lower_limit - 1) {
981 amount--;
982 changed = true;
984 break;
985 case BJACK_MAX :
986 amount = upper_limit;
987 changed = true;
988 break;
989 case BJACK_MIN :
990 amount = lower_limit;
991 changed = true;
992 break;
993 case BJACK_QUIT:
994 return 0;
995 case BJACK_START:
996 #if LCD_DEPTH > 1
997 rb->lcd_set_foreground(FG_COLOR);
998 rb->lcd_set_background(BG_COLOR);
999 #endif
1000 rb->lcd_clear_display();
1001 return amount;
1004 if(changed) {
1005 rb->snprintf(str, 9, "$%d", amount);
1006 #if LCD_HEIGHT <= 64
1007 rb->lcd_puts(0, 2, str);
1008 rb->lcd_update();
1009 #else
1010 rb->lcd_set_drawmode(DRMODE_BG+DRMODE_INVERSEVID);
1011 rb->lcd_fillrect(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 3*h, 5*w, h);
1012 rb->lcd_set_drawmode(DRMODE_SOLID);
1013 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 3*h, str);
1014 rb->lcd_update_rect(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 3*h, 5*w, h);
1015 #endif
1016 changed = false;
1021 /*****************************************************************************
1022 * blackjack_get_bet() gets the player's bet.
1023 ******************************************************************************/
1024 static void blackjack_get_bet(struct game_context* bj) {
1025 bj->current_bet = blackjack_get_amount("Please enter a bet", 10,
1026 bj->player_money, bj->current_bet);
1029 /*****************************************************************************
1030 * double_down() returns one final card then finishes the game
1031 ******************************************************************************/
1032 static void double_down(struct game_context* bj) {
1033 bj->current_bet *= 2;
1034 bj->player_cards[0][bj->num_player_cards[0]] = new_card();
1035 bj->player_total += bj->player_cards[0][bj->num_player_cards[0]].value;
1036 bj->num_player_cards[0]++;
1039 /*****************************************************************************
1040 * split() checks if the player wants to split and acts accordingly.
1041 * When bj->split_status is 1, no split occurred. 2 means the player split and 3
1042 * means a split has already occurred and the first hand is done.
1043 ******************************************************************************/
1044 static void split(struct game_context* bj) {
1045 if (blackjack_get_yes_no("Split?") == 1)
1046 bj->split_status = 1;
1047 else {
1048 bj->split_status = 2;
1049 bj->current_bet *= 2;
1050 bj->num_player_cards[0] = 1;
1051 bj->num_player_cards[1] = 1;
1052 bj->player_cards[1][0] = bj->player_cards[0][1];
1053 bj->player_total = bj->player_cards[0][0].value;
1057 /*****************************************************************************
1058 * insurance() see if the player wants to buy insurance and how much.
1059 ******************************************************************************/
1060 static unsigned int insurance(struct game_context* bj) {
1061 unsigned int insurance, max_amount;
1063 insurance = blackjack_get_yes_no("Buy Insurance?");
1064 bj->asked_insurance = true;
1065 max_amount = bj->current_bet < (unsigned int)bj->player_money ?
1066 bj->current_bet/2 : (unsigned int)bj->player_money;
1067 if (insurance == 1) return 0;
1069 insurance = blackjack_get_amount("How much?", 0, max_amount, 0);
1070 redraw_board(bj);
1071 return insurance;
1074 /*****************************************************************************
1075 * play_again() checks to see if the player wants to keep playing.
1076 ******************************************************************************/
1077 static unsigned int play_again(void) {
1078 return blackjack_get_yes_no("Play Again?");
1081 /*****************************************************************************
1082 * blackjack_menu() is the initial menu at the start of the game.
1083 ******************************************************************************/
1084 static unsigned int blackjack_menu(struct game_context* bj) {
1085 int button;
1086 char *title = "Blackjack";
1087 char str[18];
1088 unsigned int i, w, h;
1089 bool breakout = false;
1090 bool showscores = false;
1092 while(true){
1093 #if LCD_DEPTH > 1
1094 rb->lcd_set_background(BG_COLOR);
1095 rb->lcd_set_foreground(FG_COLOR);
1096 #endif
1097 rb->lcd_clear_display();
1099 if(!showscores) {
1100 /* welcome screen to display key bindings */
1101 rb->lcd_getstringsize(title, &w, &h);
1102 rb->lcd_putsxy((LCD_WIDTH-w)/2, 0, title);
1104 #if CONFIG_KEYPAD == RECORDER_PAD
1105 rb->lcd_puts(0, 1, "ON: start");
1106 rb->lcd_puts(0, 2, "OFF: exit");
1107 rb->lcd_puts(0, 3, "F1: hit");
1108 rb->lcd_puts(0, 4, "F2: stay");
1109 rb->lcd_puts(0, 5, "F3: double down");
1110 rb->lcd_puts(0, 6, "PLAY: save/resume");
1111 rb->snprintf(str, 21, "High Score: $%d", bj->highscores[0]);
1112 rb->lcd_puts(0, 7, str);
1113 #elif CONFIG_KEYPAD == ONDIO_PAD
1114 rb->lcd_puts(0, 1, "MENU: start");
1115 rb->lcd_puts(0, 2, "OFF: exit");
1116 rb->lcd_puts(0, 3, "LEFT: hit");
1117 rb->lcd_puts(0, 4, "RIGHT: stay");
1118 rb->lcd_puts(0, 5, "UP: double down");
1119 rb->lcd_puts(0, 6, "DOWN: save/resume");
1120 rb->snprintf(str, 21, "High Score: $%d", bj->highscores[0]);
1121 rb->lcd_puts(0, 7, str);
1122 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || (CONFIG_KEYPAD == IRIVER_H300_PAD)
1123 rb->lcd_puts(0, 2, "PLAY to start & to hit");
1124 rb->lcd_puts(0, 3, "STOP to exit");
1125 rb->lcd_puts(0, 4, "REC to stay");
1126 rb->lcd_puts(0, 5, "NAVI to double down ");
1127 rb->lcd_puts(0, 6, " & to view highscores");
1128 rb->lcd_puts(0, 7, "AB to save/resume");
1129 rb->snprintf(str, 21, "High Score: $%d", bj->highscores[0]);
1130 rb->lcd_puts(0, 8, str);
1131 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
1132 rb->lcd_puts(0, 2, "PLAY to start & hit");
1133 rb->lcd_puts(0, 3, "POWER to exit");
1134 rb->lcd_puts(0, 4, ">>| to stay");
1135 rb->lcd_puts(0, 5, "|<< to double down");
1136 rb->lcd_puts(0, 6, "LEFT to view scores");
1137 rb->lcd_puts(0, 7, "RIGHT to save/resume");
1138 rb->snprintf(str, 21, "High Score: $%d", bj->highscores[0]);
1139 rb->lcd_puts(0, 8, str);
1141 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \
1142 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
1143 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
1144 #if LCD_WIDTH >=176
1145 rb->lcd_puts(0, 2, "SELECT to start & to hit");
1146 rb->lcd_puts(0, 3, "MENU to exit");
1147 rb->lcd_puts(0, 4, ">>| to stay & to view highscores");
1148 rb->lcd_puts(0, 5, "|<< to double down");
1149 rb->lcd_puts(0, 6, "PLAY to save/resume");
1150 rb->snprintf(str, 21, "High Score: $%d", bj->highscores[0]);
1151 rb->lcd_puts(0, 7, str);
1152 #else
1153 rb->lcd_puts(0, 2, "SELECT to start & to ");
1154 rb->lcd_puts(0, 3, " hit");
1155 rb->lcd_puts(0, 4, "MENU to exit");
1156 rb->lcd_puts(0, 5, ">>| to stay & to view ");
1157 rb->lcd_puts(0, 6, " highscores");
1158 rb->lcd_puts(0, 7, "|<< to double down");
1159 rb->lcd_puts(0, 8, "PLAY to save/resume");
1160 rb->snprintf(str, 21, "High Score: $%d", bj->highscores[0]);
1161 rb->lcd_puts(0, 9, str);
1162 #endif
1163 #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD
1164 rb->lcd_puts(0, 2, "PLAY to start to hit");
1165 rb->lcd_puts(0, 3, "POWER to exit");
1166 rb->lcd_puts(0, 4, "SELECT to hit");
1167 rb->lcd_puts(0, 5, "REC to stay");
1168 rb->lcd_puts(0, 6, "PLAY to double down");
1169 rb->lcd_puts(0, 7, "RIGHT to view highscores ");
1170 rb->lcd_puts(0, 8, "DOWN to save/resume");
1171 rb->snprintf(str, 21, "High Score: $%d", bj->highscores[0]);
1172 rb->lcd_puts(0, 9, str);
1173 #elif CONFIG_KEYPAD == IRIVER_IFP7XX_PAD
1174 rb->lcd_puts(0, 2, "AB to start & to");
1175 rb->lcd_puts(0, 3, " stay");
1176 rb->lcd_puts(0, 4, "EQ to hit");
1177 rb->lcd_puts(0, 5, "PLAY to exit");
1178 rb->lcd_puts(0, 6, "CLICK to double down");
1179 rb->lcd_puts(0, 7, "& to view highscores");
1180 rb->lcd_puts(0, 8, "AB+EQ to save/resume");
1181 rb->snprintf(str, 21, "High Score: $%d", bj->highscores[0]);
1182 rb->lcd_puts(0, 9, str);
1183 #elif CONFIG_KEYPAD == GIGABEAT_PAD
1184 rb->lcd_puts(0, 2, "POWER to start");
1185 rb->lcd_puts(0, 3, "A to exit");
1186 rb->lcd_puts(0, 4, "VOL+ to hit");
1187 rb->lcd_puts(0, 5, "VOL- to stay");
1188 rb->lcd_puts(0, 6, "CENTER to double down");
1189 rb->lcd_puts(0, 6, "RIGHT to view highscores ");
1190 rb->lcd_puts(0, 8, "MENU to save/resume");
1191 rb->snprintf(str, 21, "High Score: $%d", bj->highscores[0]);
1192 rb->lcd_puts(0, 9, str);
1193 #elif (CONFIG_KEYPAD == SANSA_E200_PAD)
1194 rb->lcd_puts(0, 2, "SELECT to start & to hit");
1195 rb->lcd_puts(0, 3, "POWER to exit");
1196 rb->lcd_puts(0, 4, "RIGHT to stay");
1197 rb->lcd_puts(0, 5, "LEFT to double down");
1198 rb->lcd_puts(0, 6, "REC to save/resume");
1199 rb->lcd_puts(0, 7, "UP to view scores");
1200 rb->snprintf(str, 21, "High Score: $%d", bj->highscores[0]);
1201 rb->lcd_puts(0, 8, str);
1202 #elif (CONFIG_KEYPAD == SANSA_C200_PAD)
1203 rb->lcd_puts(0, 2, "SELECT to start & to hit");
1204 rb->lcd_puts(0, 3, "POWER to exit");
1205 rb->lcd_puts(0, 4, "RIGHT to stay");
1206 rb->lcd_puts(0, 5, "LEFT to double down");
1207 rb->lcd_puts(0, 6, "DOWN to save/resume");
1208 rb->lcd_puts(0, 7, "REC to view scores");
1209 rb->snprintf(str, 21, "High Score: $%d", bj->highscores[0]);
1210 rb->lcd_puts(0, 9, str);
1211 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
1212 rb->lcd_puts(0, 2, "PLAY to start & to");
1213 rb->lcd_puts(0, 3, " hit");
1214 rb->lcd_puts(0, 4, "REC to exit");
1215 rb->lcd_puts(0, 5, "FF to stay");
1216 rb->lcd_puts(0, 6, "REW to double down");
1217 rb->lcd_puts(0, 7, "MODE to save/resume");
1218 rb->lcd_puts(0, 8, "MENU to view scores");
1219 rb->snprintf(str, 21, "High Score: $%d", bj->highscores[0]);
1220 rb->lcd_puts(0, 10, str);
1221 #elif CONFIG_KEYPAD == COWOND2_PAD
1222 rb->lcd_puts(0, 6, "POWER to exit");
1223 rb->lcd_puts(0, 7, "MINUS to double down");
1224 rb->lcd_puts(0, 8, "MENU to view scores");
1225 rb->snprintf(str, 21, "High Score: $%d", bj->highscores[0]);
1226 rb->lcd_puts(0, 10, str);
1227 #endif
1229 #ifdef HAVE_TOUCHPAD
1230 rb->lcd_puts(0, 2, "LCD CENTRE to start & to hit");
1231 rb->lcd_puts(0, 3, "LCD BOTTOMLEFT to stay");
1232 rb->lcd_puts(0, 4, "LCD BOTTOMRIGHT to save/resume");
1233 #endif
1234 } else {
1235 rb->snprintf(str, 12, "%s", "High Scores");
1236 rb->lcd_getstringsize(str, &w, &h);
1237 rb->lcd_putsxy((LCD_WIDTH-w)/2, 0, str);
1239 /* print high scores */
1240 for(i=0; i<NUM_SCORES; i++) {
1241 rb->snprintf(str, 14, "#%02d: $%d", i+1, bj->highscores[i]);
1242 rb->lcd_puts(0, i+1, str);
1246 rb->lcd_update();
1248 /* handle menu button presses */
1249 button = rb->button_get(true);
1251 switch(button) {
1252 case BJACK_START: /* start playing */
1253 breakout = true;
1254 break;
1256 case BJACK_QUIT: /* quit program */
1257 if(showscores) {
1258 showscores = 0;
1259 break;
1261 return BJ_QUIT;
1263 case BJACK_RESUME:/* resume game */
1264 if(!blackjack_loadgame(bj)) {
1265 rb->splash(HZ*2, "Nothing to resume");
1266 } else {
1267 rb->splash(HZ*2, "Loading...");
1268 breakout = true;
1270 break;
1272 case BJACK_SCORES:/* toggle high scores */
1273 showscores = !showscores;
1274 break;
1276 default:
1277 if(rb->default_event_handler_ex(button, blackjack_callback,
1278 (void*) bj) == SYS_USB_CONNECTED)
1279 return BJ_USB;
1280 break;
1283 if(breakout) break;
1286 return(0);
1289 /*****************************************************************************
1290 * blackjack() is the main game subroutine, it returns the final game status.
1291 ******************************************************************************/
1292 static int blackjack(struct game_context* bj) {
1293 int button;
1294 unsigned int w, h, temp_var, done = 0, todo = 1;
1295 signed int temp;
1296 bool breakout = false;
1297 bool dbl_down = false;
1299 /* don't resume by default */
1300 bj->resume = false;
1302 /********************
1303 * menu *
1304 ********************/
1305 temp_var = blackjack_menu(bj);
1306 if (temp_var == BJ_QUIT || temp_var == BJ_USB)
1307 return temp_var;
1310 /********************
1311 * init *
1312 ********************/
1313 blackjack_init(bj);
1314 bj->current_bet=10;
1316 /********************
1317 * play *
1318 ********************/
1320 /* check for resumed game */
1321 if(bj->resume) {
1322 bj->resume = false;
1323 redraw_board(bj);
1324 if (bj->split_status == 2) {
1325 todo=2;
1326 player_x = bj->num_player_cards[0] * 10 + 4;
1328 else if (bj->split_status == 3) {
1329 player_x = bj->num_player_cards[1] * 10 + LCD_WIDTH/2 + 4;
1330 todo=2;
1331 done=1;
1335 else {
1336 bj->player_money = 1000;
1337 blackjack_get_bet(bj);
1338 if (bj->current_bet == 0)
1339 return BJ_QUIT;
1340 rb->lcd_clear_display();
1341 deal_init_cards(bj);
1342 blackjack_drawtable(bj);
1345 rb->lcd_update();
1347 breakout = false;
1349 while(true){
1350 if(bj->player_total == 21 && bj->num_player_cards[0] == 2) {
1351 bj->is_blackjack = true;
1352 bj->end_hand = true;
1353 finish_game(bj);
1355 else if(bj->dealer_cards[1].is_soft_ace && !breakout &&
1356 !bj->asked_insurance) {
1357 temp_var = insurance(bj);
1358 if (bj->dealer_total == 21) {
1359 rb->splash(HZ, "Dealer has blackjack");
1360 bj->player_money += temp_var;
1361 bj->end_hand = true;
1362 breakout = true;
1363 redraw_board(bj);
1364 finish_game(bj);
1366 else {
1367 rb->splash(HZ, "Dealer does not have blackjack");
1368 bj->player_money -= temp_var;
1369 breakout = true;
1370 redraw_board(bj);
1371 rb->lcd_update();
1374 if(bj->split_status == 0 &&
1375 bj->player_cards[0][0].num == bj->player_cards[0][1].num) {
1376 split(bj);
1377 redraw_board(bj);
1378 rb->lcd_update_rect(0, LCD_HEIGHT/2, LCD_WIDTH, LCD_HEIGHT/2);
1379 if (bj->split_status == 2) {
1380 todo++;
1381 player_x = bj->num_player_cards[0] * 10 + 4;
1385 while(done < todo) {
1386 button = rb->button_get(true);
1388 switch(button) {
1389 case BJACK_HIT:
1390 NEXT_CARD = new_card();
1391 bj->player_total += NEXT_CARD.value;
1392 draw_card(NEXT_CARD, true, player_x, player_y);
1393 bj->num_player_cards[done]++;
1394 if (bj->num_player_cards[done] == MAX_CARDS + 1) {
1395 redraw_board(bj);
1396 rb->lcd_update_rect(0, LCD_HEIGHT/2, LCD_WIDTH,
1397 LCD_HEIGHT/2);
1399 else if (bj->num_player_cards[done]>MAX_CARDS || todo > 1) {
1400 rb->lcd_update_rect(player_x, player_y, CARD_WIDTH+2,
1401 CARD_HEIGHT+2);
1402 player_x += 10;
1404 else {
1405 rb->lcd_update_rect(player_x, player_y, CARD_WIDTH+2,
1406 CARD_HEIGHT+2);
1407 player_x += CARD_WIDTH + 4;
1409 update_total(bj);
1411 break;
1412 case BJACK_STAY:
1413 bj->end_hand = true;
1414 break;
1415 case BJACK_DOUBLEDOWN:
1416 if ((signed int)bj->current_bet * 2 < bj->player_money + 1 &&
1417 bj->num_player_cards[0]==2 && todo==1) {
1418 double_down(bj);
1419 dbl_down = true;
1420 if (bj->player_total < 22) {
1421 bj->end_hand = true;
1422 finish_game(bj);
1425 else if((signed int)bj->current_bet * 2 > bj->player_money) {
1426 rb->splash(HZ, "Not enough money to double down.");
1427 redraw_board(bj);
1428 rb->lcd_update();
1430 break;
1431 case BJACK_RESUME: /* save and end game */
1432 rb->splash(HZ, "Saving game...");
1433 blackjack_savegame(bj);
1434 /* fall through to BJACK_QUIT */
1436 case BJACK_QUIT:
1437 return BJ_END;
1440 while (bj->player_total > 21 && !bj->end_hand) {
1441 temp = check_for_aces(bj->player_cards[done],
1442 bj->num_player_cards[done]);
1443 if(temp != -1) {
1444 bj->player_cards[done][temp].is_soft_ace = false;
1445 bj->player_total -= 10;
1446 update_total(bj);
1447 if (dbl_down) {
1448 bj->end_hand = true;
1449 finish_game(bj);
1452 else
1453 bj->end_hand = true;
1456 if (bj->end_hand) {
1457 done++;
1458 if(todo > 1) {
1459 if (done == 2) {
1460 temp = bj->player_total;
1461 bj->player_total = temp_var;
1462 temp_var = temp;
1463 finish_game(bj);
1464 rb->lcd_getstringsize(" Split 1 ", &w, &h);
1465 rb->lcd_putsxy(LCD_WIDTH/2-w/2, LCD_HEIGHT/2-3*h/2,
1466 " Split 1 ");
1467 rb->lcd_update_rect(LCD_WIDTH/2-w/2, LCD_HEIGHT/2-3*h/2,
1468 w,h);
1469 bj->current_bet /= 2;
1470 rb->lcd_update_rect(LCD_WIDTH/2-w/2, LCD_HEIGHT/2-3*h/2,
1471 w,h);
1472 rb->sleep(HZ*2);
1473 bj->player_total = temp_var;
1474 finish_game(bj);
1475 rb->lcd_getstringsize(" Split 2 ", &w, &h);
1476 rb->lcd_putsxy(LCD_WIDTH/2-w/2, LCD_HEIGHT/2-3*h/2,
1477 " Split 2 ");
1478 rb->lcd_update_rect(LCD_WIDTH/2-w/2, LCD_HEIGHT/2-3*h/2,
1479 w,h);
1480 rb->sleep(HZ*2);
1482 else {
1483 bj->end_hand = false;
1484 bj->split_status = 3;
1485 temp_var = bj->player_total;
1486 bj->player_total = bj->player_cards[1][0].value;
1487 update_total(bj);
1488 redraw_board(bj);
1489 player_x += 10;
1490 rb->lcd_update();
1493 else
1494 finish_game(bj);
1498 if (bj->player_money < 10) {
1499 rb->sleep(HZ);
1500 return BJ_LOSE;
1503 if (bj->end_hand) { /* If hand is over */
1504 if (play_again() != 0) /* User wants to quit */
1505 return BJ_END;
1506 else { /* User keeps playing */
1507 breakout = false;
1508 redraw_board(bj);
1509 if(dbl_down) {
1510 bj->current_bet /= 2;
1511 dbl_down = false;
1513 done = 0;
1514 todo = 1;
1515 blackjack_init(bj);
1516 blackjack_get_bet(bj);
1517 if (bj->current_bet == 0)
1518 return BJ_END;
1519 deal_init_cards(bj);
1520 blackjack_drawtable(bj);
1521 rb->lcd_update();
1525 /* Never reached */
1526 return PLUGIN_OK;
1529 /*****************************************************************************
1530 * plugin entry point.
1531 ******************************************************************************/
1532 enum plugin_status plugin_start(const struct plugin_api* api, const void* parameter)
1534 struct game_context bj;
1535 bool exit = false;
1536 unsigned int position;
1537 char str[19];
1539 (void)parameter;
1540 rb = api;
1542 #if LCD_DEPTH > 1
1543 rb->lcd_set_backdrop(NULL);
1544 #endif
1546 /* load high scores */
1547 blackjack_loadscores(&bj);
1549 rb->lcd_setfont(FONT_SYSFIXED);
1551 while(!exit) {
1552 switch(blackjack(&bj)){
1553 case BJ_LOSE:
1554 rb->splash(HZ, "Not enough money to continue");
1555 /* fall through to BJ_END */
1557 case BJ_END:
1558 if(!bj.resume) {
1559 if((position = blackjack_recordscore(&bj))) {
1560 rb->snprintf(str, 19, "New high score #%d!", position);
1561 rb->splash(HZ*2, str);
1564 break;
1566 case BJ_USB:
1567 rb->lcd_setfont(FONT_UI);
1568 return PLUGIN_USB_CONNECTED;
1570 case BJ_QUIT:
1571 if(bj.dirty) {
1572 rb->splash(HZ, "Saving high scores...");
1573 blackjack_savescores(&bj);
1575 exit = true;
1576 break;
1578 default:
1579 break;
1583 rb->lcd_setfont(FONT_UI);
1584 return PLUGIN_OK;