summaryrefslogtreecommitdiff
path: root/apps/plugins/blackjack.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/blackjack.c')
-rw-r--r--apps/plugins/blackjack.c1442
1 files changed, 1442 insertions, 0 deletions
diff --git a/apps/plugins/blackjack.c b/apps/plugins/blackjack.c
new file mode 100644
index 0000000000..775fc8c834
--- /dev/null
+++ b/apps/plugins/blackjack.c
@@ -0,0 +1,1442 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id: blackjack.c,v 1.6 2006/11/21 20:528:13 midgey34 Exp $
9 *
10 * Copyright (C) 2006 Tom Ross (midgey34@gmail.com)
11 *
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.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19
20#include "plugin.h"
21#include "solitaire_deck.h"
22#include "solitaire_cardback.h"
23
24PLUGIN_HEADER
25
26/* save files */
27#define SCORE_FILE PLUGIN_DIR "/blackjack.score"
28#define SAVE_FILE PLUGIN_DIR "/blackjack.save"
29
30#define NUM_SCORES LCD_HEIGHT/8-2
31
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
37
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
52
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
67
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
82
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
98
99#elif (CONFIG_KEYPAD == IPOD_3G_PAD) || \
100 (CONFIG_KEYPAD == IPOD_4G_PAD)
101#define BJACK_START BUTTON_SELECT
102#define BJACK_QUIT BUTTON_MENU
103#define BJACK_MAX (BUTTON_SELECT|BUTTON_SCROLL_FWD)
104#define BJACK_MIN (BUTTON_SELECT|BUTTON_SCROLL_BACK)
105#define BJACK_HIT BUTTON_SELECT
106#define BJACK_STAY BUTTON_RIGHT
107#define BJACK_DOUBLEDOWN BUTTON_LEFT
108#define BJACK_SCORES BUTTON_RIGHT
109#define BJACK_RESUME BUTTON_PLAY
110#define BJACK_UP BUTTON_SCROLL_FWD
111#define BJACK_DOWN BUTTON_SCROLL_BACK
112#define BJACK_RIGHT BUTTON_RIGHT
113#define BJACK_LEFT BUTTON_LEFT
114
115#elif CONFIG_KEYPAD == IAUDIO_X5_PAD
116#define BJACK_START BUTTON_PLAY
117#define BJACK_QUIT BUTTON_POWER
118#define BJACK_MAX (BUTTON_PLAY|BUTTON_UP)
119#define BJACK_MIN (BUTTON_PLAY|BUTTON_DOWN)
120#define BJACK_HIT BUTTON_SELECT
121#define BJACK_STAY BUTTON_REC
122#define BJACK_DOUBLEDOWN BUTTON_PLAY
123#define BJACK_SCORES BUTTON_RIGHT
124#define BJACK_RESUME BUTTON_DOWN
125#define BJACK_UP BUTTON_UP
126#define BJACK_DOWN BUTTON_DOWN
127#define BJACK_RIGHT BUTTON_RIGHT
128#define BJACK_LEFT BUTTON_LEFT
129
130#elif CONFIG_KEYPAD == IRIVER_IFP7XX_PAD
131#define BJACK_START BUTTON_MODE
132#define BJACK_QUIT BUTTON_PLAY
133#define BJACK_MAX (BUTTON_EQ|BUTTON_UP)
134#define BJACK_MIN (BUTTON_EQ|BUTTON_DOWN)
135#define BJACK_HIT BUTTON_EQ
136#define BJACK_STAY BUTTON_MODE
137#define BJACK_DOUBLEDOWN BUTTON_SELECT
138#define BJACK_SCORES BUTTON_SELECT
139#define BJACK_RESUME (BUTTON_EQ|BUTTON_MODE)
140#define BJACK_UP BUTTON_UP
141#define BJACK_DOWN BUTTON_DOWN
142#define BJACK_RIGHT BUTTON_RIGHT
143#define BJACK_LEFT BUTTON_LEFT
144
145#elif CONFIG_KEYPAD == GIGABEAT_PAD
146#define BJACK_START BUTTON_POWER
147#define BJACK_QUIT BUTTON_A
148#define BJACK_MAX BUTTON_VOL_UP
149#define BJACK_MIN BUTTON_VOL_DOWN
150#define BJACK_HIT BUTTON_VOL_UP
151#define BJACK_STAY BUTTON_VOL_DOWN
152#define BJACK_DOUBLEDOWN BUTTON_SELECT
153#define BJACK_SCORES BUTTON_RIGHT
154#define BJACK_RESUME BUTTON_MENU
155#define BJACK_UP BUTTON_UP
156#define BJACK_DOWN BUTTON_DOWN
157#define BJACK_RIGHT BUTTON_RIGHT
158#define BJACK_LEFT BUTTON_LEFT
159
160#elif CONFIG_KEYPAD == SANSA_E200_PAD
161#define BJACK_START BUTTON_SELECT
162#define BJACK_QUIT BUTTON_POWER
163#define BJACK_MAX (BUTTON_REC|BUTTON_UP)
164#define BJACK_MIN (BUTTON_REC|BUTTON_DOWN)
165#define BJACK_HIT BUTTON_SELECT
166#define BJACK_STAY BUTTON_RIGHT
167#define BJACK_DOUBLEDOWN BUTTON_LEFT
168#define BJACK_SCORES BUTTON_UP
169#define BJACK_RESUME BUTTON_REC
170#define BJACK_UP BUTTON_SCROLL_UP
171#define BJACK_DOWN BUTTON_SCROLL_DOWN
172#define BJACK_RIGHT BUTTON_RIGHT
173#define BJACK_LEFT BUTTON_LEFT
174
175#elif CONFIG_KEYPAD == ELIO_TPJ1022_PAD
176#define BJACK_START BUTTON_MAIN
177#define BJACK_QUIT BUTTON_POWER
178#define BJACK_MAX (BUTTON_REC|BUTTON_UP)
179#define BJACK_MIN (BUTTON_REC|BUTTON_DOWN)
180#define BJACK_HIT BUTTON_MAIN
181#define BJACK_STAY BUTTON_MENU
182#define BJACK_DOUBLEDOWN BUTTON_DOWN
183#define BJACK_SCORES BUTTON_UP
184#define BJACK_RESUME BUTTON_FF
185#define BJACK_UP BUTTON_UP
186#define BJACK_DOWN BUTTON_DOWN
187#define BJACK_RIGHT BUTTON_RIGHT
188#define BJACK_LEFT BUTTON_LEFT
189
190#else
191 #error BLACKJACK: Unsupported keypad
192#endif
193
194#ifdef HAVE_LCD_COLOR
195#define BG_COLOR LCD_RGBPACK(0,157,0)
196#define FG_COLOR LCD_WHITE
197#elif LCD_DEPTH > 1
198#define BG_COLOR LCD_WHITE
199#define FG_COLOR LCD_BLACK
200#endif
201
202#define CARD_WIDTH BMPWIDTH_solitaire_cardback
203#define CARD_HEIGHT BMPHEIGHT_solitaire_cardback
204
205/* This is the max amount of cards onscreen before condensing */
206#define MAX_CARDS LCD_WIDTH/(CARD_WIDTH+4)
207
208extern const fb_data solitaire_deck[];
209extern const fb_data solitaire_cardback[];
210
211#define NEXT_CARD bj->player_cards[done][bj->num_player_cards[done]]
212
213/* global rockbox api */
214static struct plugin_api* rb;
215
216/* dealer and player card positions */
217unsigned int dealer_x, dealer_y, player_x, player_y;
218
219typedef struct card {
220 unsigned int value; /* Card's value in Blackjack */
221 unsigned int num; /* Value on card face 0-12 (0=Ace, 1=2, 11=Q) */
222 unsigned int suit; /* 0:Spades, 1:Hearts, 2: Clubs; 3: Diamonds */
223 bool is_soft_ace;
224} card;
225
226typedef struct game_context {
227 struct card player_cards[2][22]; /* 22 Cards means the deal was all aces */
228 struct card dealer_cards[22]; /* That is the worst-case scenario */
229 unsigned int player_total;
230 unsigned int dealer_total;
231 signed int player_money;
232 unsigned int num_player_cards[2];
233 unsigned int num_dealer_cards;
234 unsigned int current_bet;
235 unsigned int split_status; /* 0 = split hasn't been asked, *
236 * 1 = split did not occur *
237 * 2 = split occurred *
238 * 3 = split occurred and 1st hand done */
239 bool is_blackjack;
240 bool end_hand;
241 bool asked_insurance;
242 signed short highscores[NUM_SCORES];
243 bool resume;
244 bool dirty;
245} game_context;
246
247/*****************************************************************************
248* blackjack_init() initializes blackjack data structures.
249******************************************************************************/
250static void blackjack_init(struct game_context* bj) {
251 /* seed the rand generator */
252 rb->srand(*rb->current_tick);
253
254 /* reset card positions */
255 dealer_x = 4;
256 dealer_y = LCD_HEIGHT/4 - CARD_HEIGHT/2;
257 player_x = 4;
258 player_y = LCD_HEIGHT - LCD_HEIGHT/4 - CARD_HEIGHT/2;
259
260 /* check for resumed game */
261 if(bj->resume) return;
262
263 /* reset scoring */
264 bj->player_total = 0;
265 bj->dealer_total = 0;
266 bj->num_player_cards[0] = 2;
267 bj->num_player_cards[1] = 0;
268 bj->num_dealer_cards = 2;
269 bj->end_hand = false;
270 bj->split_status = 0;
271 bj->is_blackjack = false;
272 bj->asked_insurance = false;
273}
274
275/*****************************************************************************
276* blackjack_drawtable() draws the table and some text.
277******************************************************************************/
278static void blackjack_drawtable(struct game_context* bj) {
279 unsigned int w, h, y_loc;
280 char str[10];
281
282#if LCD_HEIGHT <= 64
283 rb->lcd_getstringsize("Bet", &w, &h);
284 rb->lcd_putsxy(LCD_WIDTH - w, 2*h + 1, "Bet");
285 rb->snprintf(str, 9, "$%d", bj->current_bet);
286 rb->lcd_getstringsize(str, &w, &h);
287 rb->lcd_putsxy(LCD_WIDTH - w, 3*h + 1, str);
288 y_loc = LCD_HEIGHT/2;
289#else
290 rb->lcd_getstringsize("Bet", &w, &h);
291 rb->lcd_putsxy(LCD_WIDTH - w, 5*h / 2, "Bet");
292 rb->snprintf(str, 9, "$%d", bj->current_bet);
293 rb->lcd_getstringsize(str, &w, &h);
294 rb->lcd_putsxy(LCD_WIDTH - w, 7*h / 2, str);
295 rb->lcd_hline(0, LCD_WIDTH, LCD_HEIGHT/2);
296 y_loc = LCD_HEIGHT/2 + h;
297#endif
298
299 rb->lcd_putsxy(0,0, "Dealer");
300 rb->lcd_getstringsize("Player", &w, &h);
301 rb->lcd_putsxy(0, y_loc, "Player");
302 rb->lcd_getstringsize("Total", &w, &h);
303 rb->lcd_putsxy(LCD_WIDTH - w, y_loc, "Total");
304 rb->lcd_getstringsize("Money", &w, &h);
305 rb->lcd_putsxy(LCD_WIDTH - w, 0, "Money");
306 rb->snprintf(str, 9, "$%d", bj->player_money - bj->current_bet);
307 rb->lcd_getstringsize(str, &w, &h);
308 rb->lcd_putsxy(LCD_WIDTH - w, h + 1, str);
309 rb->snprintf(str, 3, "%d", bj->player_total);
310 rb->lcd_getstringsize(str, &w, &h);
311 rb->lcd_putsxy(LCD_WIDTH - w, y_loc + h, str);
312}
313
314/*****************************************************************************
315* find_value() is passed a card and returns its blackjack value.
316******************************************************************************/
317static unsigned int find_value(unsigned int number) {
318 unsigned int thisValue;
319 if (number == 0)
320 thisValue = 11; /* Aces get a value of 11 at first */
321 else if (number < 10)
322 thisValue = number + 1;
323 else
324 thisValue = 10; /* Anything 10 or higher gets a value of 10 */
325
326 return thisValue;
327}
328
329/*****************************************************************************
330* draw_card() draws a card to the screen.
331******************************************************************************/
332static void draw_card(struct card temp_card, bool shown, unsigned int x,
333 unsigned int y) {
334 if(shown)
335 rb->lcd_bitmap_part(solitaire_deck, CARD_WIDTH*temp_card.num,
336 CARD_HEIGHT*temp_card.suit, BMPWIDTH_solitaire_deck,
337 x+1, y+1, CARD_WIDTH, CARD_HEIGHT);
338 else
339 rb->lcd_bitmap(solitaire_cardback, x+1, y+1,CARD_WIDTH, CARD_HEIGHT);
340#if LCD_DEPTH > 1
341 rb->lcd_set_foreground(LCD_BLACK);
342#endif
343
344 /* Print outlines */
345#if CARD_WIDTH >= 26
346 rb->lcd_hline(x+2, x+CARD_WIDTH-1, y);
347 rb->lcd_hline(x+2, x+CARD_WIDTH-1, y+CARD_HEIGHT+1);
348 rb->lcd_vline(x, y+2, y+CARD_HEIGHT-3);
349 rb->lcd_vline(x+CARD_WIDTH+1, y+2, y+CARD_HEIGHT-1);
350 rb->lcd_drawpixel(x+1, y+1);
351 rb->lcd_drawpixel(x+1, y+CARD_HEIGHT);
352 rb->lcd_drawpixel(x+CARD_WIDTH, y+1);
353 rb->lcd_drawpixel(x+CARD_WIDTH, y+CARD_HEIGHT);
354#else
355 rb->lcd_hline(x+1, x+CARD_WIDTH, y);
356 rb->lcd_hline(x+1, x+CARD_WIDTH, y+CARD_HEIGHT+1);
357 rb->lcd_vline(x, y+1, y+CARD_HEIGHT);
358 rb->lcd_vline(x+CARD_WIDTH+1, y+1, y+CARD_HEIGHT);
359#endif
360
361#if LCD_DEPTH > 1
362 rb->lcd_set_foreground(FG_COLOR);
363#endif
364}
365
366/*****************************************************************************
367* new_card() initializes a new card and gives it values.
368******************************************************************************/
369static struct card new_card(void) {
370 struct card new_card;
371 new_card.suit = rb->rand()%4; /* Random number 0-3 */
372 new_card.num = rb->rand()%13; /* Random number 0-12 */
373 new_card.value = find_value(new_card.num);
374 new_card.is_soft_ace = new_card.num == 0 ? true : false;
375 return new_card;
376}
377
378/*****************************************************************************
379* deal_init_card() deals and draws to the screen the player's and dealer's
380* initial cards.
381******************************************************************************/
382static void deal_init_cards(struct game_context* bj) {
383 bj->dealer_cards[0] = new_card();
384 bj->dealer_total += bj->dealer_cards[0].value;
385
386 draw_card(bj->dealer_cards[0], false, dealer_x, dealer_y);
387
388 bj->dealer_cards[1] = new_card();
389 bj->dealer_total += bj->dealer_cards[1].value;
390 draw_card(bj->dealer_cards[1], true, dealer_x + CARD_WIDTH + 4, dealer_y);
391
392 bj->player_cards[0][0] = new_card();
393 bj->player_total += bj->player_cards[0][0].value;
394 draw_card(bj->player_cards[0][0], true, player_x, player_y);
395 player_x += CARD_WIDTH + 4;
396
397 bj->player_cards[0][1] = new_card();
398 bj->player_total += bj->player_cards[0][1].value;
399 draw_card(bj->player_cards[0][1], true, player_x, player_y);
400 player_x += CARD_WIDTH + 4;
401}
402
403/*****************************************************************************
404* redraw_board() redraws all the cards and the board
405******************************************************************************/
406static void redraw_board(struct game_context* bj) {
407 unsigned int i, n, upper_bound;
408 rb->lcd_clear_display();
409
410 blackjack_drawtable(bj);
411 player_x = 4;
412 dealer_x = 4;
413 upper_bound = bj->split_status > 1 ? 2 : 1;
414
415 for (i = 0; i < bj->num_dealer_cards; i++) {
416 if (!bj->end_hand) {
417 draw_card(bj->dealer_cards[0], false, dealer_x, dealer_y);
418
419 /* increment i so the dealer's first card isn't displayed */
420 i++;
421 dealer_x += CARD_WIDTH + 4;
422 }
423 draw_card(bj->dealer_cards[i], true, dealer_x, dealer_y);
424
425 if (bj->num_dealer_cards > MAX_CARDS-1)
426 dealer_x += 10;
427 else
428 dealer_x += CARD_WIDTH + 4;
429 }
430
431 for (n = 0; n < upper_bound; n++) {
432 for (i = 0; i < bj->num_player_cards[n]; i++) {
433 draw_card(bj->player_cards[n][i], true, player_x, player_y);
434 if (bj->split_status>1 || bj->num_player_cards[n]>MAX_CARDS)
435 player_x += 10;
436 else
437 player_x += CARD_WIDTH + 4;
438 }
439 if (bj->split_status > 1)
440 player_x = LCD_WIDTH/2 + 4;
441 }
442}
443
444/*****************************************************************************
445* update_total updates the player's total
446******************************************************************************/
447static void update_total(struct game_context* bj) {
448 char total[3];
449 unsigned int w, h;
450 rb->snprintf(total, 3, "%d", bj->player_total);
451 rb->lcd_getstringsize(total, &w, &h);
452#if LCD_HEIGHT > 64
453 h *= 2;
454#endif
455 rb->lcd_putsxy(LCD_WIDTH - w, LCD_HEIGHT/2 + h, total);
456 rb->lcd_update_rect(LCD_WIDTH - w, LCD_HEIGHT/2 + h, w, h);
457}
458
459
460/*****************************************************************************
461* check_for_aces() is passed an array of cards and returns where an ace is
462* located. Otherwise, returns -1.
463******************************************************************************/
464static signed int check_for_aces(struct card temp_cards[],
465 unsigned int size) {
466 unsigned int i;
467 for(i = 0; i < size; i++) {
468 if (temp_cards[i].is_soft_ace == true)
469 return i;
470 }
471 return -1;
472}
473
474/*****************************************************************************
475* check_totals() compares player and dealer totals.
476* 0: bust 1: loss, 2: push, 3: win, 4: blackjack, 5: something's not right...
477******************************************************************************/
478static unsigned int check_totals(struct game_context* bj)
479{
480 unsigned int temp;
481 if (bj->player_total > 21)
482 temp = 0;
483 else if (bj->player_total == 21 && bj->is_blackjack)
484 if (bj->dealer_total == 21 && bj->num_dealer_cards == 2)
485 temp = 2;
486 else
487 temp = 4;
488 else if (bj->player_total == bj->dealer_total)
489 temp = 2;
490 else if (bj->dealer_total > 21 && bj->player_total < 22)
491 temp = 3;
492 else if (bj->dealer_total > bj->player_total)
493 temp = 1;
494 else if (bj->player_total > bj->dealer_total)
495 temp = 3;
496 else
497 temp = 5;
498
499 return temp;
500}
501
502/*****************************************************************************
503* finish_dealer() draws cards for the dealer until he has 17 or more.
504******************************************************************************/
505static void finish_dealer(struct game_context* bj) {
506 signed int temp = 0;
507
508 if (bj->dealer_total > 16 && bj->dealer_total < 22)
509 return;
510
511 while (bj->dealer_total < 17) {
512 bj->dealer_cards[bj->num_dealer_cards] = new_card();
513 bj->dealer_total += bj->dealer_cards[bj->num_dealer_cards].value;
514 bj->num_dealer_cards++;
515 }
516
517 while (bj->dealer_total > 21) {
518 temp = check_for_aces(bj->dealer_cards, bj->num_dealer_cards);
519 if(temp != -1) {
520 bj->dealer_cards[temp].is_soft_ace = false;
521 bj->dealer_total -= 10;
522 }
523 else
524 return;
525 }
526}
527
528/*****************************************************************************
529* finish_game() completes the game once player's turn is over.
530******************************************************************************/
531static void finish_game(struct game_context* bj) {
532 unsigned int rValue, w, h;
533 char str[19];
534
535 do {
536 finish_dealer(bj);
537 } while (bj->dealer_total < 17);
538
539 redraw_board(bj);
540 rValue = check_totals(bj);
541
542 if (rValue == 0) {
543 rb->snprintf(str, sizeof(str), " Bust! ");
544 bj->player_money -= bj->current_bet;
545 }
546 else if (rValue == 1) {
547 rb->snprintf(str, sizeof(str), " Sorry, you lost. ");
548 bj->player_money -= bj->current_bet;
549 }
550 else if (rValue == 2) {
551 rb->snprintf(str, sizeof(str), " Push ");
552 }
553 else if (rValue == 3) {
554 rb->snprintf(str, sizeof(str), " You won! ");
555 bj->player_money+= bj->current_bet;
556 }
557 else {
558 rb->snprintf(str, sizeof(str), " Blackjack! ");
559 bj->player_money += bj->current_bet * 3 / 2;
560 }
561 rb->lcd_getstringsize(str, &w, &h);
562
563#if LCD_HEIGHT <= 64
564 rb->lcd_set_drawmode(DRMODE_BG+DRMODE_INVERSEVID);
565 rb->lcd_fillrect(0, LCD_HEIGHT/2, LCD_WIDTH, LCD_HEIGHT/2);
566 rb->lcd_set_drawmode(DRMODE_SOLID);
567 rb->lcd_putsxy(LCD_WIDTH/2 - w/2, LCD_HEIGHT/2 + h, str);
568 rb->snprintf(str, 12, "You have %d", bj->player_total);
569 rb->lcd_getstringsize(str, &w, &h);
570 rb->lcd_putsxy(LCD_WIDTH/2 - w/2, LCD_HEIGHT/2, str);
571#else
572 rb->lcd_putsxy(LCD_WIDTH/2 - w/2, LCD_HEIGHT/2 - h/2, str);
573#endif
574 rb->lcd_update();
575}
576
577/*****************************************************************************
578* blackjack_recordscore() inserts a high score into the high scores list and
579* returns the high score position.
580******************************************************************************/
581static unsigned int blackjack_recordscore(struct game_context* bj) {
582 unsigned int i;
583 unsigned int position = 0;
584 signed short current, temp;
585
586 /* calculate total score */
587 current = bj->player_money;
588 if(current <= 10) return 0;
589
590 /* insert the current score into the high scores */
591 for(i=0; i<NUM_SCORES; i++) {
592 if(current >= bj->highscores[i]) {
593 if(!position) {
594 position = i+1;
595 bj->dirty = true;
596 }
597 temp = bj->highscores[i];
598 bj->highscores[i] = current;
599 current = temp;
600 }
601 }
602
603 return position;
604}
605
606/*****************************************************************************
607* blackjack_loadscores() loads the high scores saved file.
608******************************************************************************/
609static void blackjack_loadscores(struct game_context* bj) {
610 signed int fd;
611
612 bj->dirty = false;
613
614 /* clear high scores */
615 rb->memset(bj->highscores, 0, sizeof(bj->highscores));
616
617 /* open scores file */
618 fd = rb->open(SCORE_FILE, O_RDONLY);
619 if(fd < 0) return;
620
621 /* read in high scores */
622 if(rb->read(fd, bj->highscores, sizeof(bj->highscores)) <= 0) {
623 /* scores are bad, reset */
624 rb->memset(bj->highscores, 0, sizeof(bj->highscores));
625 }
626
627 rb->close(fd);
628}
629
630/*****************************************************************************
631* blackjack_savescores() saves the high scores saved file.
632******************************************************************************/
633static void blackjack_savescores(struct game_context* bj) {
634 unsigned int fd;
635
636 /* write out the high scores to the save file */
637 fd = rb->open(SCORE_FILE, O_WRONLY|O_CREAT);
638 rb->write(fd, bj->highscores, sizeof(bj->highscores));
639 rb->close(fd);
640 bj->dirty = false;
641}
642
643/*****************************************************************************
644* blackjack_loadgame() loads the saved game and returns load success.
645******************************************************************************/
646static bool blackjack_loadgame(struct game_context* bj) {
647 signed int fd;
648 bool loaded = false;
649
650 /* open game file */
651 fd = rb->open(SAVE_FILE, O_RDONLY);
652 if(fd < 0) return loaded;
653
654 /* read in saved game */
655 while(true) {
656 if(rb->read(fd, &bj->player_money, sizeof(bj->player_money)) <= 0) break;
657 if(rb->read(fd, &bj->player_total, sizeof(bj->player_total)) <= 0) break;
658 if(rb->read(fd, &bj->dealer_total, sizeof(bj->dealer_total)) <= 0) break;
659 if(rb->read(fd, &bj->num_player_cards, sizeof(bj->num_player_cards))<=0)
660 break;
661 if(rb->read(fd, &bj->num_dealer_cards, sizeof(bj->num_dealer_cards))<=0)
662 break;
663 if(rb->read(fd, &bj->current_bet, sizeof(bj->current_bet)) <= 0) break;
664 if(rb->read(fd, &bj->is_blackjack, sizeof(bj->is_blackjack)) <= 0) break;
665 if(rb->read(fd, &bj->split_status, sizeof(bj->split_status)) <= 0) break;
666 if(rb->read(fd, &bj->asked_insurance, sizeof(bj->asked_insurance)) <= 0)
667 break;
668 if(rb->read(fd, &bj->end_hand, sizeof(bj->end_hand)) <= 0) break;
669 if(rb->read(fd, &bj->player_cards, sizeof(bj->player_cards)) <= 0) break;
670 if(rb->read(fd, &bj->dealer_cards, sizeof(bj->dealer_cards)) <= 0) break;
671 bj->resume = true;
672 loaded = true;
673 break;
674 }
675
676 rb->close(fd);
677
678 /* delete saved file */
679 rb->remove(SAVE_FILE);
680 return loaded;
681}
682
683/*****************************************************************************
684* blackjack_savegame() saves the current game state.
685******************************************************************************/
686static void blackjack_savegame(struct game_context* bj) {
687 unsigned int fd;
688
689 /* write out the game state to the save file */
690 fd = rb->open(SAVE_FILE, O_WRONLY|O_CREAT);
691 rb->write(fd, &bj->player_money, sizeof(bj->player_money));
692 rb->write(fd, &bj->player_total, sizeof(bj->player_total));
693 rb->write(fd, &bj->dealer_total, sizeof(bj->dealer_total));
694 rb->write(fd, &bj->num_player_cards, sizeof(bj->num_player_cards));
695 rb->write(fd, &bj->num_dealer_cards, sizeof(bj->num_dealer_cards));
696 rb->write(fd, &bj->current_bet, sizeof(bj->current_bet));
697 rb->write(fd, &bj->is_blackjack, sizeof(bj->is_blackjack));
698 rb->write(fd, &bj->split_status, sizeof(bj->split_status));
699 rb->write(fd, &bj->asked_insurance, sizeof(bj->asked_insurance));
700 rb->write(fd, &bj->end_hand, sizeof(bj->end_hand));
701 rb->write(fd, &bj->player_cards, sizeof(bj->player_cards));
702 rb->write(fd, &bj->dealer_cards, sizeof(bj->dealer_cards));
703 rb->close(fd);
704
705 bj->resume = true;
706}
707
708/*****************************************************************************
709* blackjack_callback() is the default event handler callback which is called
710* on usb connect and shutdown.
711******************************************************************************/
712static void blackjack_callback(void* param) {
713 struct game_context* bj = (struct game_context*) param;
714 if(bj->dirty) {
715 rb->splash(HZ, true, "Saving high scores...");
716 blackjack_savescores(bj);
717 }
718}
719
720/*****************************************************************************
721* blackjack_get_yes_no() gets a yes/no answer from the user
722******************************************************************************/
723static unsigned int blackjack_get_yes_no(char message[20]) {
724 int button;
725 unsigned int w, h, b, choice = 0;
726 bool breakout = false;
727 char message_yes[24], message_no[24];
728
729 rb->strcpy(message_yes, message);
730 rb->strcpy(message_no, message);
731 rb->strcat(message_yes, " Yes");
732 rb->strcat(message_no, " No");
733 rb->lcd_getstringsize(message_yes, &w, &h);
734 const char *stg[] = {message_yes, message_no};
735
736#if LCD_HEIGHT <= 64
737 b = 2*h+1;
738#else
739 b = h-1;
740#endif
741
742#ifdef HAVE_LCD_COLOR
743 rb->lcd_fillrect(LCD_WIDTH/2 - w/2, LCD_HEIGHT/2 + b, w+1, h+3);
744 rb->lcd_set_foreground(LCD_BLACK);
745 rb->lcd_set_background(LCD_WHITE);
746#else
747 rb->lcd_set_drawmode(DRMODE_BG+DRMODE_INVERSEVID);
748 rb->lcd_fillrect(LCD_WIDTH/2 - w/2, LCD_HEIGHT/2 + b, w+1, h+3);
749 rb->lcd_set_drawmode(DRMODE_SOLID);
750#endif
751 rb->lcd_drawrect(LCD_WIDTH/2 - w/2 - 1, LCD_HEIGHT/2 + b - 1, w+3, h+4);
752
753 while(!breakout) {
754 rb->lcd_putsxy(LCD_WIDTH/2 - w/2, LCD_HEIGHT/2 + b +1, stg[choice]);
755 rb->lcd_update_rect(LCD_WIDTH/2 - w/2 - 1, LCD_HEIGHT/2 + b -1,
756 w+3, h+4);
757 button = rb->button_get(true);
758
759 switch(button) {
760 case BJACK_LEFT:
761 case (BJACK_LEFT|BUTTON_REPEAT):
762 case BJACK_RIGHT:
763 case (BJACK_RIGHT|BUTTON_REPEAT):
764 choice ^= 1;
765 break;
766 case BJACK_START: breakout = true;
767 break;
768 case BJACK_QUIT: breakout = true;
769 choice = BJ_QUIT;
770 break;
771 }
772 }
773
774#if LCD_DEPTH > 1
775 rb->lcd_set_foreground(FG_COLOR);
776 rb->lcd_set_background(BG_COLOR);
777#endif
778 return choice;
779}
780
781/*****************************************************************************
782* blackjack_get_amount() gets an amount from the player to be used
783******************************************************************************/
784static signed int blackjack_get_amount(char message[20], signed int lower_limit,
785 signed int upper_limit,
786 signed int start) {
787 int button;
788 char str[6];
789 bool changed = false;
790 unsigned int w, h;
791 signed int amount;
792
793 rb->lcd_getstringsize("A", &w, &h); /* find the size of one character */
794
795 if (start > upper_limit)
796 amount = upper_limit;
797 else if (start < lower_limit)
798 amount = lower_limit;
799 else
800 amount = start;
801
802#if LCD_DEPTH > 1
803 rb->lcd_set_background(LCD_WHITE);
804 rb->lcd_set_foreground(LCD_BLACK);
805#endif
806
807#if LCD_HEIGHT <= 64
808 rb->lcd_clear_display();
809 rb->lcd_puts(0, 1, message);
810 rb->snprintf(str, 9, "$%d", amount);
811 rb->lcd_puts(0, 2, str);
812 rb->lcd_puts(0, 3, "RIGHT: +1");
813 rb->lcd_puts(0, 4, "LEFT: -1");
814 rb->lcd_puts(0, 5, "UP: +10");
815 rb->lcd_puts(0, 6, "DOWN: -10");
816 rb->lcd_update();
817#else
818 rb->lcd_set_drawmode(DRMODE_BG+DRMODE_INVERSEVID);
819 rb->lcd_fillrect(LCD_WIDTH/2 - 9*w - 1, LCD_HEIGHT/2 - 4*h - 3, 37*w / 2,
820 8*h -3);
821 rb->lcd_set_drawmode(DRMODE_SOLID);
822 rb->lcd_drawrect(LCD_WIDTH/2 - 9*w - 1, LCD_HEIGHT/2 - 4*h - 3, 37*w / 2,
823 8*h -3);
824 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 4*h - 1, message);
825 rb->snprintf(str, 9, "$%d", amount);
826 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 3*h, str);
827#if (CONFIG_KEY == IPOD_3G_PAD) || (CONFIG_KEYPAD == IPOD_4G_PAD)
828 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - h-2, " >>|: +1");
829 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 1, " |<<: -1");
830 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 + h, "SCROLL+: +10");
831 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 + 2*h + 1, "SCROLL-: -10");
832#elif CONFIG_KEYPAD == IRIVER_H10_PAD
833 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - h-2, "RIGHT: +1");
834 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 1, "LEFT: -1");
835 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 + h, "SCROLL+: +10");
836 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 + 2*h + 1, "SCROLL-: -10");
837#else
838 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - h-2, "RIGHT: +1");
839 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 1, "LEFT: -1");
840 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 + h, "UP: +10");
841 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 + 2*h + 1, "DOWN: -10");
842#endif
843 rb->lcd_update_rect(LCD_WIDTH/2 - 9*w - 2, LCD_HEIGHT/2 - 9*h/2, 37*w/2 + 1,
844 8*h-2);
845#endif
846
847 while(true) {
848 button = rb->button_get(true);
849
850 switch(button) {
851 case BJACK_UP:
852 case (BJACK_UP|BUTTON_REPEAT):
853 if (amount + 10 < upper_limit + 1) {
854 amount += 10;
855 changed = true;
856 }
857 break;
858 case BJACK_DOWN:
859 case (BJACK_DOWN|BUTTON_REPEAT):
860 if (amount - 10 > lower_limit - 1) {
861 amount -= 10;
862 changed = true;
863 }
864 break;
865 case BJACK_RIGHT:
866 case (BJACK_RIGHT|BUTTON_REPEAT):
867 if (amount + 1 < upper_limit + 1) {
868 amount++;
869 changed = true;
870 }
871 break;
872 case BJACK_LEFT:
873 case (BJACK_LEFT|BUTTON_REPEAT):
874 if (amount - 1 > lower_limit - 1) {
875 amount--;
876 changed = true;
877 }
878 break;
879 case BJACK_MAX :
880 amount = upper_limit;
881 changed = true;
882 break;
883 case BJACK_MIN :
884 amount = lower_limit;
885 changed = true;
886 break;
887 case BJACK_QUIT:
888 return 0;
889 case BJACK_START:
890#if LCD_DEPTH > 1
891 rb->lcd_set_foreground(FG_COLOR);
892 rb->lcd_set_background(BG_COLOR);
893#endif
894 rb->lcd_clear_display();
895 return amount;
896 }
897
898 if(changed) {
899 rb->snprintf(str, 9, "$%d", amount);
900#if LCD_HEIGHT <= 64
901 rb->lcd_puts(0, 2, str);
902 rb->lcd_update();
903#else
904 rb->lcd_set_drawmode(DRMODE_BG+DRMODE_INVERSEVID);
905 rb->lcd_fillrect(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 3*h, 5*w, h);
906 rb->lcd_set_drawmode(DRMODE_SOLID);
907 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 3*h, str);
908 rb->lcd_update_rect(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 3*h, 5*w, h);
909#endif
910 changed = false;
911 }
912 }
913}
914
915/*****************************************************************************
916* blackjack_get_bet() gets the player's bet.
917******************************************************************************/
918static void blackjack_get_bet(struct game_context* bj) {
919 bj->current_bet = blackjack_get_amount("Please enter a bet", 10,
920 bj->player_money, bj->current_bet);
921}
922
923/*****************************************************************************
924* double_down() returns one final card then finishes the game
925******************************************************************************/
926static void double_down(struct game_context* bj) {
927 bj->current_bet *= 2;
928 bj->player_cards[0][bj->num_player_cards[0]] = new_card();
929 bj->player_total += bj->player_cards[0][bj->num_player_cards[0]].value;
930 bj->num_player_cards[0]++;
931}
932
933/*****************************************************************************
934* split() checks if the player wants to split and acts accordingly.
935* When bj->split_status is 1, no split occurred. 2 means the player split and 3
936* means a split has already occurred and the first hand is done.
937******************************************************************************/
938static void split(struct game_context* bj) {
939 if (blackjack_get_yes_no("Split?") == 1)
940 bj->split_status = 1;
941 else {
942 bj->split_status = 2;
943 bj->current_bet *= 2;
944 bj->num_player_cards[0] = 1;
945 bj->num_player_cards[1] = 1;
946 bj->player_cards[1][0] = bj->player_cards[0][1];
947 bj->player_total = bj->player_cards[0][0].value;
948 }
949}
950
951/*****************************************************************************
952* insurance() see if the player wants to buy insurance and how much.
953******************************************************************************/
954static unsigned int insurance(struct game_context* bj) {
955 unsigned int insurance, max_amount;
956
957 insurance = blackjack_get_yes_no("Buy Insurance?");
958 bj->asked_insurance = true;
959 max_amount = bj->current_bet < (unsigned int)bj->player_money ?
960 bj->current_bet/2 : (unsigned int)bj->player_money;
961 if (insurance == 1) return 0;
962
963 insurance = blackjack_get_amount("How much?", 0, max_amount, 0);
964 redraw_board(bj);
965 return insurance;
966}
967
968/*****************************************************************************
969* play_again() checks to see if the player wants to keep playing.
970******************************************************************************/
971static unsigned int play_again(void) {
972 return blackjack_get_yes_no("Play Again?");
973}
974
975/*****************************************************************************
976* blackjack_menu() is the initial menu at the start of the game.
977******************************************************************************/
978static unsigned int blackjack_menu(struct game_context* bj) {
979 int button;
980 char *title = "Blackjack";
981 char str[18];
982 unsigned int i, w, h;
983 bool breakout = false;
984 bool showscores = false;
985
986 while(true){
987#if LCD_DEPTH > 1
988 rb->lcd_set_background(BG_COLOR);
989 rb->lcd_set_foreground(FG_COLOR);
990#endif
991 rb->lcd_clear_display();
992
993 if(!showscores) {
994 /* welcome screen to display key bindings */
995 rb->lcd_getstringsize(title, &w, &h);
996 rb->lcd_putsxy((LCD_WIDTH-w)/2, 0, title);
997
998#if CONFIG_KEYPAD == RECORDER_PAD
999 rb->lcd_puts(0, 1, "ON: start");
1000 rb->lcd_puts(0, 2, "OFF: exit");
1001 rb->lcd_puts(0, 3, "F1: hit");
1002 rb->lcd_puts(0, 4, "F2: stay");
1003 rb->lcd_puts(0, 5, "F3: double down");
1004 rb->lcd_puts(0, 6, "PLAY: save/resume");
1005 rb->snprintf(str, 21, "High Score: $%d", bj->highscores[0]);
1006 rb->lcd_puts(0, 7, str);
1007#elif CONFIG_KEYPAD == ONDIO_PAD
1008 rb->lcd_puts(0, 1, "MENU: start");
1009 rb->lcd_puts(0, 2, "OFF: exit");
1010 rb->lcd_puts(0, 3, "LEFT: hit");
1011 rb->lcd_puts(0, 4, "RIGHT: stay");
1012 rb->lcd_puts(0, 5, "UP: double down");
1013 rb->lcd_puts(0, 6, "DOWN: save/resume");
1014 rb->snprintf(str, 21, "High Score: $%d", bj->highscores[0]);
1015 rb->lcd_puts(0, 7, str);
1016#elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || (CONFIG_KEYPAD == IRIVER_H300_PAD)
1017 rb->lcd_puts(0, 2, "PLAY to start & to hit");
1018 rb->lcd_puts(0, 3, "STOP to exit");
1019 rb->lcd_puts(0, 4, "REC to stay");
1020 rb->lcd_puts(0, 5, "NAVI to double down ");
1021 rb->lcd_puts(0, 6, " & to view highscores");
1022 rb->lcd_puts(0, 7, "AB to save/resume");
1023 rb->snprintf(str, 21, "High Score: $%d", bj->highscores[0]);
1024 rb->lcd_puts(0, 8, str);
1025#elif CONFIG_KEYPAD == IRIVER_H10_PAD
1026 rb->lcd_puts(0, 2, "PLAY to start & hit");
1027 rb->lcd_puts(0, 3, "POWER to exit");
1028 rb->lcd_puts(0, 4, ">>| to stay");
1029 rb->lcd_puts(0, 5, "|<< to double down");
1030 rb->lcd_puts(0, 6, "LEFT to view scores");
1031 rb->lcd_puts(0, 7, "RIGHT to save/resume");
1032 rb->snprintf(str, 21, "High Score: $%d", bj->highscores[0]);
1033 rb->lcd_puts(0, 8, str);
1034
1035#elif (CONFIG_KEYPAD == IPOD_3G_PAD) || (CONFIG_KEYPAD == IPOD_4G_PAD)
1036#if LCD_WIDTH >=176
1037 rb->lcd_puts(0, 2, "SELECT to start & to hit");
1038 rb->lcd_puts(0, 3, "MENU to exit");
1039 rb->lcd_puts(0, 4, ">>| to stay & to view highscores");
1040 rb->lcd_puts(0, 5, "|<< to double down");
1041 rb->lcd_puts(0, 6, "PLAY to save/resume");
1042 rb->snprintf(str, 21, "High Score: $%d", bj->highscores[0]);
1043 rb->lcd_puts(0, 7, str);
1044#else
1045 rb->lcd_puts(0, 2, "SELECT to start & to ");
1046 rb->lcd_puts(0, 3, " hit");
1047 rb->lcd_puts(0, 4, "MENU to exit");
1048 rb->lcd_puts(0, 5, ">>| to stay & to view ");
1049 rb->lcd_puts(0, 6, " highscores");
1050 rb->lcd_puts(0, 7, "|<< to double down");
1051 rb->lcd_puts(0, 8, "PLAY to save/resume");
1052 rb->snprintf(str, 21, "High Score: $%d", bj->highscores[0]);
1053 rb->lcd_puts(0, 9, str);
1054#endif
1055#elif CONFIG_KEYPAD == IAUDIO_X5_PAD
1056 rb->lcd_puts(0, 2, "PLAY to start to hit");
1057 rb->lcd_puts(0, 3, "POWER to exit");
1058 rb->lcd_puts(0, 4, "SELECT to hit");
1059 rb->lcd_puts(0, 5, "REC to stay");
1060 rb->lcd_puts(0, 6, "PLAY to double down");
1061 rb->lcd_puts(0, 7, "RIGHT to view highscores ");
1062 rb->lcd_puts(0, 8, "DOWN to save/resume");
1063 rb->snprintf(str, 21, "High Score: $%d", bj->highscores[0]);
1064 rb->lcd_puts(0, 9, str);
1065#elif CONFIG_KEYPAD == IRIVER_IFP7XX_PAD
1066 rb->lcd_puts(0, 2, "AB to start & to");
1067 rb->lcd_puts(0, 3, " stay");
1068 rb->lcd_puts(0, 4, "EQ to hit");
1069 rb->lcd_puts(0, 5, "PLAY to exit");
1070 rb->lcd_puts(0, 6, "CLICK to double down");
1071 rb->lcd_puts(0, 7, "& to view highscores");
1072 rb->lcd_puts(0, 8, "AB+EQ to save/resume");
1073 rb->snprintf(str, 21, "High Score: $%d", bj->highscores[0]);
1074 rb->lcd_puts(0, 9, str);
1075#elif CONFIG_KEYPAD == GIGABEAT_PAD
1076 rb->lcd_puts(0, 2, "POWER to start");
1077 rb->lcd_puts(0, 3, "A to exit");
1078 rb->lcd_puts(0, 4, "VOL+ to hit");
1079 rb->lcd_puts(0, 5, "VOL- to stay");
1080 rb->lcd_puts(0, 6, "CENTER to double down");
1081 rb->lcd_puts(0, 6, "RIGHT to view highscores ");
1082 rb->lcd_puts(0, 8, "MENU to save/resume");
1083 rb->snprintf(str, 21, "High Score: $%d", bj->highscores[0]);
1084 rb->lcd_puts(0, 9, str);
1085#elif (CONFIG_KEYPAD == SANSA_E200_PAD)
1086 rb->lcd_puts(0, 2, "SELECT to start & to hit");
1087 rb->lcd_puts(0, 3, "POWER to exit");
1088 rb->lcd_puts(0, 4, "RIGHT to stay");
1089 rb->lcd_puts(0, 5, "LEFT to double down");
1090 rb->lcd_puts(0, 6, "REC to save/resume");
1091 rb->lcd_puts(0, 7, "UP to view scores");
1092 rb->snprintf(str, 21, "High Score: $%d", bj->highscores[0]);
1093 rb->lcd_puts(0, 8, str);
1094
1095#endif
1096 } else {
1097 rb->snprintf(str, 12, "%s", "High Scores");
1098 rb->lcd_getstringsize(str, &w, &h);
1099 rb->lcd_putsxy((LCD_WIDTH-w)/2, 0, str);
1100
1101 /* print high scores */
1102 for(i=0; i<NUM_SCORES; i++) {
1103 rb->snprintf(str, 14, "#%02d: $%d", i+1, bj->highscores[i]);
1104 rb->lcd_puts(0, i+1, str);
1105 }
1106 }
1107
1108 rb->lcd_update();
1109
1110 /* handle menu button presses */
1111 button = rb->button_get(true);
1112
1113 switch(button) {
1114 case BJACK_START: /* start playing */
1115 breakout = true;
1116 break;
1117
1118 case BJACK_QUIT: /* quit program */
1119 if(showscores) {
1120 showscores = 0;
1121 break;
1122 }
1123 return BJ_QUIT;
1124
1125 case BJACK_RESUME:/* resume game */
1126 if(!blackjack_loadgame(bj)) {
1127 rb->splash(HZ*2, true, "Nothing to resume");
1128 } else {
1129 rb->splash(HZ*2, true, "Loading...");
1130 breakout = true;
1131 }
1132 break;
1133
1134 case BJACK_SCORES:/* toggle high scores */
1135 showscores = !showscores;
1136 break;
1137
1138 default:
1139 if(rb->default_event_handler_ex(button, blackjack_callback,
1140 (void*) bj) == SYS_USB_CONNECTED)
1141 return BJ_USB;
1142 break;
1143 }
1144
1145 if(breakout) break;
1146 }
1147
1148 return(0);
1149}
1150
1151/*****************************************************************************
1152* blackjack() is the main game subroutine, it returns the final game status.
1153******************************************************************************/
1154static int blackjack(struct game_context* bj) {
1155 int button;
1156 unsigned int w, h, temp_var, done = 0, todo = 1;
1157 signed int temp;
1158 bool breakout = false;
1159 bool dbl_down = false;
1160
1161 /* don't resume by default */
1162 bj->resume = false;
1163
1164 /********************
1165 * menu *
1166 ********************/
1167 temp_var = blackjack_menu(bj);
1168 if (temp_var == BJ_QUIT || temp_var == BJ_USB)
1169 return temp_var;
1170
1171
1172 /********************
1173 * init *
1174 ********************/
1175 blackjack_init(bj);
1176 bj->current_bet=10;
1177
1178 /********************
1179 * play *
1180 ********************/
1181
1182 /* check for resumed game */
1183 if(bj->resume) {
1184 bj->resume = false;
1185 redraw_board(bj);
1186 if (bj->split_status == 2) {
1187 todo=2;
1188 player_x = bj->num_player_cards[0] * 10 + 4;
1189 }
1190 else if (bj->split_status == 3) {
1191 player_x = bj->num_player_cards[1] * 10 + LCD_WIDTH/2 + 4;
1192 todo=2;
1193 done=1;
1194 }
1195
1196 }
1197 else {
1198 bj->player_money = 1000;
1199 blackjack_get_bet(bj);
1200 if (bj->current_bet == 0)
1201 return BJ_QUIT;
1202 rb->lcd_clear_display();
1203 deal_init_cards(bj);
1204 blackjack_drawtable(bj);
1205 }
1206
1207 rb->lcd_update();
1208
1209 breakout = false;
1210
1211 while(true){
1212 if(bj->player_total == 21 && bj->num_player_cards[0] == 2) {
1213 bj->is_blackjack = true;
1214 bj->end_hand = true;
1215 finish_game(bj);
1216 }
1217 else if(bj->dealer_cards[1].is_soft_ace && !breakout &&
1218 !bj->asked_insurance) {
1219 temp_var = insurance(bj);
1220 if (bj->dealer_total == 21) {
1221 rb->splash(HZ, true, "Dealer has blackjack");
1222 bj->player_money += temp_var;
1223 bj->end_hand = true;
1224 breakout = true;
1225 redraw_board(bj);
1226 finish_game(bj);
1227 }
1228 else {
1229 rb->splash(HZ, true, "Dealer does not have blackjack");
1230 bj->player_money -= temp_var;
1231 breakout = true;
1232 redraw_board(bj);
1233 rb->lcd_update();
1234 }
1235 }
1236 if(bj->split_status == 0 &&
1237 bj->player_cards[0][0].num == bj->player_cards[0][1].num) {
1238 split(bj);
1239 redraw_board(bj);
1240 rb->lcd_update_rect(0, LCD_HEIGHT/2, LCD_WIDTH, LCD_HEIGHT/2);
1241 if (bj->split_status == 2) {
1242 todo++;
1243 player_x = bj->num_player_cards[0] * 10 + 4;
1244 }
1245 }
1246
1247 while(done < todo) {
1248 button = rb->button_get(true);
1249
1250 switch(button) {
1251 case BJACK_HIT:
1252 NEXT_CARD = new_card();
1253 bj->player_total += NEXT_CARD.value;
1254 draw_card(NEXT_CARD, true, player_x, player_y);
1255 bj->num_player_cards[done]++;
1256 if (bj->num_player_cards[done] == MAX_CARDS + 1) {
1257 redraw_board(bj);
1258 rb->lcd_update_rect(0, LCD_HEIGHT/2, LCD_WIDTH,
1259 LCD_HEIGHT/2);
1260 }
1261 else if (bj->num_player_cards[done]>MAX_CARDS || todo > 1) {
1262 rb->lcd_update_rect(player_x, player_y, CARD_WIDTH+2,
1263 CARD_HEIGHT+2);
1264 player_x += 10;
1265 }
1266 else {
1267 rb->lcd_update_rect(player_x, player_y, CARD_WIDTH+2,
1268 CARD_HEIGHT+2);
1269 player_x += CARD_WIDTH + 4;
1270 }
1271 update_total(bj);
1272
1273 break;
1274 case BJACK_STAY:
1275 bj->end_hand = true;
1276 break;
1277 case BJACK_DOUBLEDOWN:
1278 if ((signed int)bj->current_bet * 2 < bj->player_money + 1 &&
1279 bj->num_player_cards[0]==2 && todo==1) {
1280 double_down(bj);
1281 dbl_down = true;
1282 if (bj->player_total < 22) {
1283 bj->end_hand = true;
1284 finish_game(bj);
1285 }
1286 }
1287 else if((signed int)bj->current_bet * 2 > bj->player_money) {
1288 rb->splash(HZ, true, "Not enough money to double down.");
1289 redraw_board(bj);
1290 rb->lcd_update();
1291 }
1292 break;
1293 case BJACK_RESUME: /* save and end game */
1294 rb->splash(HZ, true, "Saving game...");
1295 blackjack_savegame(bj);
1296 /* fall through to BJACK_QUIT */
1297
1298 case BJACK_QUIT:
1299 return BJ_END;
1300 }
1301
1302 while (bj->player_total > 21 && !bj->end_hand) {
1303 temp = check_for_aces(bj->player_cards[done],
1304 bj->num_player_cards[done]);
1305 if(temp != -1) {
1306 bj->player_cards[done][temp].is_soft_ace = false;
1307 bj->player_total -= 10;
1308 update_total(bj);
1309 if (dbl_down) {
1310 bj->end_hand = true;
1311 finish_game(bj);
1312 }
1313 }
1314 else
1315 bj->end_hand = true;
1316 }
1317
1318 if (bj->end_hand) {
1319 done++;
1320 if(todo > 1) {
1321 if (done == 2) {
1322 temp = bj->player_total;
1323 bj->player_total = temp_var;
1324 temp_var = temp;
1325 finish_game(bj);
1326 rb->lcd_getstringsize(" Split 1 ", &w, &h);
1327 rb->lcd_putsxy(LCD_WIDTH/2-w/2, LCD_HEIGHT/2-3*h/2,
1328 " Split 1 ");
1329 rb->lcd_update_rect(LCD_WIDTH/2-w/2, LCD_HEIGHT/2-3*h/2,
1330 w,h);
1331 bj->current_bet /= 2;
1332 rb->lcd_update_rect(LCD_WIDTH/2-w/2, LCD_HEIGHT/2-3*h/2,
1333 w,h);
1334 rb->sleep(HZ*2);
1335 bj->player_total = temp_var;
1336 finish_game(bj);
1337 rb->lcd_getstringsize(" Split 2 ", &w, &h);
1338 rb->lcd_putsxy(LCD_WIDTH/2-w/2, LCD_HEIGHT/2-3*h/2,
1339 " Split 2 ");
1340 rb->lcd_update_rect(LCD_WIDTH/2-w/2, LCD_HEIGHT/2-3*h/2,
1341 w,h);
1342 rb->sleep(HZ*2);
1343 }
1344 else {
1345 bj->end_hand = false;
1346 bj->split_status = 3;
1347 temp_var = bj->player_total;
1348 bj->player_total = bj->player_cards[1][0].value;
1349 update_total(bj);
1350 redraw_board(bj);
1351 player_x += 10;
1352 rb->lcd_update();
1353 }
1354 }
1355 else
1356 finish_game(bj);
1357 }
1358 }
1359
1360 if (bj->player_money < 10) {
1361 rb->sleep(HZ);
1362 return BJ_LOSE;
1363 }
1364
1365 if (bj->end_hand) { /* If hand is over */
1366 if (play_again() != 0) /* User wants to quit */
1367 return BJ_END;
1368 else { /* User keeps playing */
1369 breakout = false;
1370 redraw_board(bj);
1371 if(dbl_down) {
1372 bj->current_bet /= 2;
1373 dbl_down = false;
1374 }
1375 done = 0;
1376 todo = 1;
1377 blackjack_init(bj);
1378 blackjack_get_bet(bj);
1379 if (bj->current_bet == 0)
1380 return BJ_END;
1381 deal_init_cards(bj);
1382 blackjack_drawtable(bj);
1383 rb->lcd_update();
1384 }
1385 }
1386 }
1387 /* Never reached */
1388 return PLUGIN_OK;
1389}
1390
1391/*****************************************************************************
1392* plugin entry point.
1393******************************************************************************/
1394enum plugin_status plugin_start(struct plugin_api* api, void* parameter) {
1395 struct game_context bj;
1396 bool exit = false;
1397 unsigned int position;
1398 char str[19];
1399
1400 (void)parameter;
1401 rb = api;
1402
1403 /* load high scores */
1404 blackjack_loadscores(&bj);
1405
1406 rb->lcd_setfont(FONT_SYSFIXED);
1407
1408 while(!exit) {
1409 switch(blackjack(&bj)){
1410 case BJ_LOSE:
1411 rb->splash(HZ, true, "Not enough money to continue");
1412 /* fall through to BJ_END */
1413
1414 case BJ_END:
1415 if(!bj.resume) {
1416 if((position = blackjack_recordscore(&bj))) {
1417 rb->snprintf(str, 19, "New high score #%d!", position);
1418 rb->splash(HZ*2, true, str);
1419 }
1420 }
1421 break;
1422
1423 case BJ_USB:
1424 rb->lcd_setfont(FONT_UI);
1425 return PLUGIN_USB_CONNECTED;
1426
1427 case BJ_QUIT:
1428 if(bj.dirty) {
1429 rb->splash(HZ, true, "Saving high scores...");
1430 blackjack_savescores(&bj);
1431 }
1432 exit = true;
1433 break;
1434
1435 default:
1436 break;
1437 }
1438 }
1439
1440 rb->lcd_setfont(FONT_UI);
1441 return PLUGIN_OK;
1442}