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