summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apps/plugins/SOURCES1
-rw-r--r--apps/plugins/blackjack.c1442
-rw-r--r--manual/plugins/blackjack.tex81
-rw-r--r--manual/plugins/images/ss-blackjack-112x64x1.pngbin0 -> 476 bytes
-rw-r--r--manual/plugins/images/ss-blackjack-128x128x16.pngbin0 -> 2047 bytes
-rw-r--r--manual/plugins/images/ss-blackjack-138x110x2.pngbin0 -> 816 bytes
-rw-r--r--manual/plugins/images/ss-blackjack-160x128x16.pngbin0 -> 2376 bytes
-rw-r--r--manual/plugins/images/ss-blackjack-160x128x2.pngbin0 -> 871 bytes
-rw-r--r--manual/plugins/images/ss-blackjack-176x132x16.pngbin0 -> 2433 bytes
-rw-r--r--manual/plugins/images/ss-blackjack-176x220x16.pngbin0 -> 2722 bytes
-rw-r--r--manual/plugins/images/ss-blackjack-220x176x16.pngbin0 -> 4134 bytes
-rw-r--r--manual/plugins/images/ss-blackjack-240x320x16.pngbin0 -> 4574 bytes
-rw-r--r--manual/plugins/images/ss-blackjack-320x240x16.pngbin0 -> 8600 bytes
-rw-r--r--manual/plugins/main.tex2
14 files changed, 1526 insertions, 0 deletions
diff --git a/apps/plugins/SOURCES b/apps/plugins/SOURCES
index f00ac71bed..72fdf7454e 100644
--- a/apps/plugins/SOURCES
+++ b/apps/plugins/SOURCES
@@ -43,6 +43,7 @@ jpeg.c
mandelbrot.c
plasma.c
+blackjack.c
bounce.c
#ifndef SANSA_E200
bubbles.c
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 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id: blackjack.c,v 1.6 2006/11/21 20:528:13 midgey34 Exp $
+ *
+ * Copyright (C) 2006 Tom Ross (midgey34@gmail.com)
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include "plugin.h"
+#include "solitaire_deck.h"
+#include "solitaire_cardback.h"
+
+PLUGIN_HEADER
+
+/* save files */
+#define SCORE_FILE PLUGIN_DIR "/blackjack.score"
+#define SAVE_FILE PLUGIN_DIR "/blackjack.save"
+
+#define NUM_SCORES LCD_HEIGHT/8-2
+
+/* final game return status */
+#define BJ_END 3
+#define BJ_USB 2
+#define BJ_QUIT 1
+#define BJ_LOSE 0
+
+#if CONFIG_KEYPAD == RECORDER_PAD
+#define BJACK_START BUTTON_ON
+#define BJACK_QUIT BUTTON_OFF
+#define BJACK_MAX (BUTTON_ON|BUTTON_UP)
+#define BJACK_MIN (BUTTON_ON|BUTTON_DOWN)
+#define BJACK_HIT BUTTON_F1
+#define BJACK_STAY BUTTON_F2
+#define BJACK_DOUBLEDOWN BUTTON_F3
+#define BJACK_SCORES BUTTON_RIGHT
+#define BJACK_RESUME BUTTON_PLAY
+#define BJACK_UP BUTTON_UP
+#define BJACK_DOWN BUTTON_DOWN
+#define BJACK_RIGHT BUTTON_RIGHT
+#define BJACK_LEFT BUTTON_LEFT
+
+#elif CONFIG_KEYPAD == ONDIO_PAD
+#define BJACK_START BUTTON_MENU
+#define BJACK_QUIT BUTTON_OFF
+#define BJACK_MAX (BUTTON_MENU|BUTTON_UP)
+#define BJACK_MIN (BUTTON_MENU|BUTTON_DOWN)
+#define BJACK_HIT BUTTON_LEFT
+#define BJACK_STAY BUTTON_RIGHT
+#define BJACK_DOUBLEDOWN BUTTON_UP
+#define BJACK_SCORES BUTTON_UP
+#define BJACK_RESUME BUTTON_DOWN
+#define BJACK_UP BUTTON_UP
+#define BJACK_DOWN BUTTON_DOWN
+#define BJACK_RIGHT BUTTON_RIGHT
+#define BJACK_LEFT BUTTON_LEFT
+
+#elif CONFIG_KEYPAD == IRIVER_H10_PAD
+#define BJACK_START BUTTON_PLAY
+#define BJACK_QUIT BUTTON_POWER
+#define BJACK_MAX (BUTTON_PLAY|BUTTON_SCROLL_UP)
+#define BJACK_MIN (BUTTON_PLAY|BUTTON_SCROLL_DOWN)
+#define BJACK_HIT BUTTON_PLAY
+#define BJACK_STAY BUTTON_FF
+#define BJACK_DOUBLEDOWN BUTTON_REW
+#define BJACK_SCORES BUTTON_LEFT
+#define BJACK_RESUME BUTTON_RIGHT
+#define BJACK_UP BUTTON_SCROLL_UP
+#define BJACK_DOWN BUTTON_SCROLL_DOWN
+#define BJACK_RIGHT BUTTON_RIGHT
+#define BJACK_LEFT BUTTON_LEFT
+
+#elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
+ (CONFIG_KEYPAD == IRIVER_H300_PAD)
+#define BJACK_START BUTTON_ON
+#define BJACK_QUIT BUTTON_OFF
+#define BJACK_MAX (BUTTON_ON|BUTTON_UP)
+#define BJACK_MIN (BUTTON_ON|BUTTON_DOWN)
+#define BJACK_HIT BUTTON_ON
+#define BJACK_STAY BUTTON_REC
+#define BJACK_DOUBLEDOWN BUTTON_SELECT
+#define BJACK_SCORES BUTTON_SELECT
+#define BJACK_RESUME BUTTON_MODE
+#define BJACK_UP BUTTON_UP
+#define BJACK_DOWN BUTTON_DOWN
+#define BJACK_RIGHT BUTTON_RIGHT
+#define BJACK_LEFT BUTTON_LEFT
+
+#elif (CONFIG_KEYPAD == IPOD_3G_PAD) || \
+ (CONFIG_KEYPAD == IPOD_4G_PAD)
+#define BJACK_START BUTTON_SELECT
+#define BJACK_QUIT BUTTON_MENU
+#define BJACK_MAX (BUTTON_SELECT|BUTTON_SCROLL_FWD)
+#define BJACK_MIN (BUTTON_SELECT|BUTTON_SCROLL_BACK)
+#define BJACK_HIT BUTTON_SELECT
+#define BJACK_STAY BUTTON_RIGHT
+#define BJACK_DOUBLEDOWN BUTTON_LEFT
+#define BJACK_SCORES BUTTON_RIGHT
+#define BJACK_RESUME BUTTON_PLAY
+#define BJACK_UP BUTTON_SCROLL_FWD
+#define BJACK_DOWN BUTTON_SCROLL_BACK
+#define BJACK_RIGHT BUTTON_RIGHT
+#define BJACK_LEFT BUTTON_LEFT
+
+#elif CONFIG_KEYPAD == IAUDIO_X5_PAD
+#define BJACK_START BUTTON_PLAY
+#define BJACK_QUIT BUTTON_POWER
+#define BJACK_MAX (BUTTON_PLAY|BUTTON_UP)
+#define BJACK_MIN (BUTTON_PLAY|BUTTON_DOWN)
+#define BJACK_HIT BUTTON_SELECT
+#define BJACK_STAY BUTTON_REC
+#define BJACK_DOUBLEDOWN BUTTON_PLAY
+#define BJACK_SCORES BUTTON_RIGHT
+#define BJACK_RESUME BUTTON_DOWN
+#define BJACK_UP BUTTON_UP
+#define BJACK_DOWN BUTTON_DOWN
+#define BJACK_RIGHT BUTTON_RIGHT
+#define BJACK_LEFT BUTTON_LEFT
+
+#elif CONFIG_KEYPAD == IRIVER_IFP7XX_PAD
+#define BJACK_START BUTTON_MODE
+#define BJACK_QUIT BUTTON_PLAY
+#define BJACK_MAX (BUTTON_EQ|BUTTON_UP)
+#define BJACK_MIN (BUTTON_EQ|BUTTON_DOWN)
+#define BJACK_HIT BUTTON_EQ
+#define BJACK_STAY BUTTON_MODE
+#define BJACK_DOUBLEDOWN BUTTON_SELECT
+#define BJACK_SCORES BUTTON_SELECT
+#define BJACK_RESUME (BUTTON_EQ|BUTTON_MODE)
+#define BJACK_UP BUTTON_UP
+#define BJACK_DOWN BUTTON_DOWN
+#define BJACK_RIGHT BUTTON_RIGHT
+#define BJACK_LEFT BUTTON_LEFT
+
+#elif CONFIG_KEYPAD == GIGABEAT_PAD
+#define BJACK_START BUTTON_POWER
+#define BJACK_QUIT BUTTON_A
+#define BJACK_MAX BUTTON_VOL_UP
+#define BJACK_MIN BUTTON_VOL_DOWN
+#define BJACK_HIT BUTTON_VOL_UP
+#define BJACK_STAY BUTTON_VOL_DOWN
+#define BJACK_DOUBLEDOWN BUTTON_SELECT
+#define BJACK_SCORES BUTTON_RIGHT
+#define BJACK_RESUME BUTTON_MENU
+#define BJACK_UP BUTTON_UP
+#define BJACK_DOWN BUTTON_DOWN
+#define BJACK_RIGHT BUTTON_RIGHT
+#define BJACK_LEFT BUTTON_LEFT
+
+#elif CONFIG_KEYPAD == SANSA_E200_PAD
+#define BJACK_START BUTTON_SELECT
+#define BJACK_QUIT BUTTON_POWER
+#define BJACK_MAX (BUTTON_REC|BUTTON_UP)
+#define BJACK_MIN (BUTTON_REC|BUTTON_DOWN)
+#define BJACK_HIT BUTTON_SELECT
+#define BJACK_STAY BUTTON_RIGHT
+#define BJACK_DOUBLEDOWN BUTTON_LEFT
+#define BJACK_SCORES BUTTON_UP
+#define BJACK_RESUME BUTTON_REC
+#define BJACK_UP BUTTON_SCROLL_UP
+#define BJACK_DOWN BUTTON_SCROLL_DOWN
+#define BJACK_RIGHT BUTTON_RIGHT
+#define BJACK_LEFT BUTTON_LEFT
+
+#elif CONFIG_KEYPAD == ELIO_TPJ1022_PAD
+#define BJACK_START BUTTON_MAIN
+#define BJACK_QUIT BUTTON_POWER
+#define BJACK_MAX (BUTTON_REC|BUTTON_UP)
+#define BJACK_MIN (BUTTON_REC|BUTTON_DOWN)
+#define BJACK_HIT BUTTON_MAIN
+#define BJACK_STAY BUTTON_MENU
+#define BJACK_DOUBLEDOWN BUTTON_DOWN
+#define BJACK_SCORES BUTTON_UP
+#define BJACK_RESUME BUTTON_FF
+#define BJACK_UP BUTTON_UP
+#define BJACK_DOWN BUTTON_DOWN
+#define BJACK_RIGHT BUTTON_RIGHT
+#define BJACK_LEFT BUTTON_LEFT
+
+#else
+ #error BLACKJACK: Unsupported keypad
+#endif
+
+#ifdef HAVE_LCD_COLOR
+#define BG_COLOR LCD_RGBPACK(0,157,0)
+#define FG_COLOR LCD_WHITE
+#elif LCD_DEPTH > 1
+#define BG_COLOR LCD_WHITE
+#define FG_COLOR LCD_BLACK
+#endif
+
+#define CARD_WIDTH BMPWIDTH_solitaire_cardback
+#define CARD_HEIGHT BMPHEIGHT_solitaire_cardback
+
+/* This is the max amount of cards onscreen before condensing */
+#define MAX_CARDS LCD_WIDTH/(CARD_WIDTH+4)
+
+extern const fb_data solitaire_deck[];
+extern const fb_data solitaire_cardback[];
+
+#define NEXT_CARD bj->player_cards[done][bj->num_player_cards[done]]
+
+/* global rockbox api */
+static struct plugin_api* rb;
+
+/* dealer and player card positions */
+unsigned int dealer_x, dealer_y, player_x, player_y;
+
+typedef struct card {
+ unsigned int value; /* Card's value in Blackjack */
+ unsigned int num; /* Value on card face 0-12 (0=Ace, 1=2, 11=Q) */
+ unsigned int suit; /* 0:Spades, 1:Hearts, 2: Clubs; 3: Diamonds */
+ bool is_soft_ace;
+} card;
+
+typedef struct game_context {
+ struct card player_cards[2][22]; /* 22 Cards means the deal was all aces */
+ struct card dealer_cards[22]; /* That is the worst-case scenario */
+ unsigned int player_total;
+ unsigned int dealer_total;
+ signed int player_money;
+ unsigned int num_player_cards[2];
+ unsigned int num_dealer_cards;
+ unsigned int current_bet;
+ unsigned int split_status; /* 0 = split hasn't been asked, *
+ * 1 = split did not occur *
+ * 2 = split occurred *
+ * 3 = split occurred and 1st hand done */
+ bool is_blackjack;
+ bool end_hand;
+ bool asked_insurance;
+ signed short highscores[NUM_SCORES];
+ bool resume;
+ bool dirty;
+} game_context;
+
+/*****************************************************************************
+* blackjack_init() initializes blackjack data structures.
+******************************************************************************/
+static void blackjack_init(struct game_context* bj) {
+ /* seed the rand generator */
+ rb->srand(*rb->current_tick);
+
+ /* reset card positions */
+ dealer_x = 4;
+ dealer_y = LCD_HEIGHT/4 - CARD_HEIGHT/2;
+ player_x = 4;
+ player_y = LCD_HEIGHT - LCD_HEIGHT/4 - CARD_HEIGHT/2;
+
+ /* check for resumed game */
+ if(bj->resume) return;
+
+ /* reset scoring */
+ bj->player_total = 0;
+ bj->dealer_total = 0;
+ bj->num_player_cards[0] = 2;
+ bj->num_player_cards[1] = 0;
+ bj->num_dealer_cards = 2;
+ bj->end_hand = false;
+ bj->split_status = 0;
+ bj->is_blackjack = false;
+ bj->asked_insurance = false;
+}
+
+/*****************************************************************************
+* blackjack_drawtable() draws the table and some text.
+******************************************************************************/
+static void blackjack_drawtable(struct game_context* bj) {
+ unsigned int w, h, y_loc;
+ char str[10];
+
+#if LCD_HEIGHT <= 64
+ rb->lcd_getstringsize("Bet", &w, &h);
+ rb->lcd_putsxy(LCD_WIDTH - w, 2*h + 1, "Bet");
+ rb->snprintf(str, 9, "$%d", bj->current_bet);
+ rb->lcd_getstringsize(str, &w, &h);
+ rb->lcd_putsxy(LCD_WIDTH - w, 3*h + 1, str);
+ y_loc = LCD_HEIGHT/2;
+#else
+ rb->lcd_getstringsize("Bet", &w, &h);
+ rb->lcd_putsxy(LCD_WIDTH - w, 5*h / 2, "Bet");
+ rb->snprintf(str, 9, "$%d", bj->current_bet);
+ rb->lcd_getstringsize(str, &w, &h);
+ rb->lcd_putsxy(LCD_WIDTH - w, 7*h / 2, str);
+ rb->lcd_hline(0, LCD_WIDTH, LCD_HEIGHT/2);
+ y_loc = LCD_HEIGHT/2 + h;
+#endif
+
+ rb->lcd_putsxy(0,0, "Dealer");
+ rb->lcd_getstringsize("Player", &w, &h);
+ rb->lcd_putsxy(0, y_loc, "Player");
+ rb->lcd_getstringsize("Total", &w, &h);
+ rb->lcd_putsxy(LCD_WIDTH - w, y_loc, "Total");
+ rb->lcd_getstringsize("Money", &w, &h);
+ rb->lcd_putsxy(LCD_WIDTH - w, 0, "Money");
+ rb->snprintf(str, 9, "$%d", bj->player_money - bj->current_bet);
+ rb->lcd_getstringsize(str, &w, &h);
+ rb->lcd_putsxy(LCD_WIDTH - w, h + 1, str);
+ rb->snprintf(str, 3, "%d", bj->player_total);
+ rb->lcd_getstringsize(str, &w, &h);
+ rb->lcd_putsxy(LCD_WIDTH - w, y_loc + h, str);
+}
+
+/*****************************************************************************
+* find_value() is passed a card and returns its blackjack value.
+******************************************************************************/
+static unsigned int find_value(unsigned int number) {
+ unsigned int thisValue;
+ if (number == 0)
+ thisValue = 11; /* Aces get a value of 11 at first */
+ else if (number < 10)
+ thisValue = number + 1;
+ else
+ thisValue = 10; /* Anything 10 or higher gets a value of 10 */
+
+ return thisValue;
+}
+
+/*****************************************************************************
+* draw_card() draws a card to the screen.
+******************************************************************************/
+static void draw_card(struct card temp_card, bool shown, unsigned int x,
+ unsigned int y) {
+ if(shown)
+ rb->lcd_bitmap_part(solitaire_deck, CARD_WIDTH*temp_card.num,
+ CARD_HEIGHT*temp_card.suit, BMPWIDTH_solitaire_deck,
+ x+1, y+1, CARD_WIDTH, CARD_HEIGHT);
+ else
+ rb->lcd_bitmap(solitaire_cardback, x+1, y+1,CARD_WIDTH, CARD_HEIGHT);
+#if LCD_DEPTH > 1
+ rb->lcd_set_foreground(LCD_BLACK);
+#endif
+
+ /* Print outlines */
+#if CARD_WIDTH >= 26
+ rb->lcd_hline(x+2, x+CARD_WIDTH-1, y);
+ rb->lcd_hline(x+2, x+CARD_WIDTH-1, y+CARD_HEIGHT+1);
+ rb->lcd_vline(x, y+2, y+CARD_HEIGHT-3);
+ rb->lcd_vline(x+CARD_WIDTH+1, y+2, y+CARD_HEIGHT-1);
+ rb->lcd_drawpixel(x+1, y+1);
+ rb->lcd_drawpixel(x+1, y+CARD_HEIGHT);
+ rb->lcd_drawpixel(x+CARD_WIDTH, y+1);
+ rb->lcd_drawpixel(x+CARD_WIDTH, y+CARD_HEIGHT);
+#else
+ rb->lcd_hline(x+1, x+CARD_WIDTH, y);
+ rb->lcd_hline(x+1, x+CARD_WIDTH, y+CARD_HEIGHT+1);
+ rb->lcd_vline(x, y+1, y+CARD_HEIGHT);
+ rb->lcd_vline(x+CARD_WIDTH+1, y+1, y+CARD_HEIGHT);
+#endif
+
+#if LCD_DEPTH > 1
+ rb->lcd_set_foreground(FG_COLOR);
+#endif
+}
+
+/*****************************************************************************
+* new_card() initializes a new card and gives it values.
+******************************************************************************/
+static struct card new_card(void) {
+ struct card new_card;
+ new_card.suit = rb->rand()%4; /* Random number 0-3 */
+ new_card.num = rb->rand()%13; /* Random number 0-12 */
+ new_card.value = find_value(new_card.num);
+ new_card.is_soft_ace = new_card.num == 0 ? true : false;
+ return new_card;
+}
+
+/*****************************************************************************
+* deal_init_card() deals and draws to the screen the player's and dealer's
+* initial cards.
+******************************************************************************/
+static void deal_init_cards(struct game_context* bj) {
+ bj->dealer_cards[0] = new_card();
+ bj->dealer_total += bj->dealer_cards[0].value;
+
+ draw_card(bj->dealer_cards[0], false, dealer_x, dealer_y);
+
+ bj->dealer_cards[1] = new_card();
+ bj->dealer_total += bj->dealer_cards[1].value;
+ draw_card(bj->dealer_cards[1], true, dealer_x + CARD_WIDTH + 4, dealer_y);
+
+ bj->player_cards[0][0] = new_card();
+ bj->player_total += bj->player_cards[0][0].value;
+ draw_card(bj->player_cards[0][0], true, player_x, player_y);
+ player_x += CARD_WIDTH + 4;
+
+ bj->player_cards[0][1] = new_card();
+ bj->player_total += bj->player_cards[0][1].value;
+ draw_card(bj->player_cards[0][1], true, player_x, player_y);
+ player_x += CARD_WIDTH + 4;
+}
+
+/*****************************************************************************
+* redraw_board() redraws all the cards and the board
+******************************************************************************/
+static void redraw_board(struct game_context* bj) {
+ unsigned int i, n, upper_bound;
+ rb->lcd_clear_display();
+
+ blackjack_drawtable(bj);
+ player_x = 4;
+ dealer_x = 4;
+ upper_bound = bj->split_status > 1 ? 2 : 1;
+
+ for (i = 0; i < bj->num_dealer_cards; i++) {
+ if (!bj->end_hand) {
+ draw_card(bj->dealer_cards[0], false, dealer_x, dealer_y);
+
+ /* increment i so the dealer's first card isn't displayed */
+ i++;
+ dealer_x += CARD_WIDTH + 4;
+ }
+ draw_card(bj->dealer_cards[i], true, dealer_x, dealer_y);
+
+ if (bj->num_dealer_cards > MAX_CARDS-1)
+ dealer_x += 10;
+ else
+ dealer_x += CARD_WIDTH + 4;
+ }
+
+ for (n = 0; n < upper_bound; n++) {
+ for (i = 0; i < bj->num_player_cards[n]; i++) {
+ draw_card(bj->player_cards[n][i], true, player_x, player_y);
+ if (bj->split_status>1 || bj->num_player_cards[n]>MAX_CARDS)
+ player_x += 10;
+ else
+ player_x += CARD_WIDTH + 4;
+ }
+ if (bj->split_status > 1)
+ player_x = LCD_WIDTH/2 + 4;
+ }
+}
+
+/*****************************************************************************
+* update_total updates the player's total
+******************************************************************************/
+static void update_total(struct game_context* bj) {
+ char total[3];
+ unsigned int w, h;
+ rb->snprintf(total, 3, "%d", bj->player_total);
+ rb->lcd_getstringsize(total, &w, &h);
+#if LCD_HEIGHT > 64
+ h *= 2;
+#endif
+ rb->lcd_putsxy(LCD_WIDTH - w, LCD_HEIGHT/2 + h, total);
+ rb->lcd_update_rect(LCD_WIDTH - w, LCD_HEIGHT/2 + h, w, h);
+}
+
+
+/*****************************************************************************
+* check_for_aces() is passed an array of cards and returns where an ace is
+* located. Otherwise, returns -1.
+******************************************************************************/
+static signed int check_for_aces(struct card temp_cards[],
+ unsigned int size) {
+ unsigned int i;
+ for(i = 0; i < size; i++) {
+ if (temp_cards[i].is_soft_ace == true)
+ return i;
+ }
+ return -1;
+}
+
+/*****************************************************************************
+* check_totals() compares player and dealer totals.
+* 0: bust 1: loss, 2: push, 3: win, 4: blackjack, 5: something's not right...
+******************************************************************************/
+static unsigned int check_totals(struct game_context* bj)
+{
+ unsigned int temp;
+ if (bj->player_total > 21)
+ temp = 0;
+ else if (bj->player_total == 21 && bj->is_blackjack)
+ if (bj->dealer_total == 21 && bj->num_dealer_cards == 2)
+ temp = 2;
+ else
+ temp = 4;
+ else if (bj->player_total == bj->dealer_total)
+ temp = 2;
+ else if (bj->dealer_total > 21 && bj->player_total < 22)
+ temp = 3;
+ else if (bj->dealer_total > bj->player_total)
+ temp = 1;
+ else if (bj->player_total > bj->dealer_total)
+ temp = 3;
+ else
+ temp = 5;
+
+ return temp;
+}
+
+/*****************************************************************************
+* finish_dealer() draws cards for the dealer until he has 17 or more.
+******************************************************************************/
+static void finish_dealer(struct game_context* bj) {
+ signed int temp = 0;
+
+ if (bj->dealer_total > 16 && bj->dealer_total < 22)
+ return;
+
+ while (bj->dealer_total < 17) {
+ bj->dealer_cards[bj->num_dealer_cards] = new_card();
+ bj->dealer_total += bj->dealer_cards[bj->num_dealer_cards].value;
+ bj->num_dealer_cards++;
+ }
+
+ while (bj->dealer_total > 21) {
+ temp = check_for_aces(bj->dealer_cards, bj->num_dealer_cards);
+ if(temp != -1) {
+ bj->dealer_cards[temp].is_soft_ace = false;
+ bj->dealer_total -= 10;
+ }
+ else
+ return;
+ }
+}
+
+/*****************************************************************************
+* finish_game() completes the game once player's turn is over.
+******************************************************************************/
+static void finish_game(struct game_context* bj) {
+ unsigned int rValue, w, h;
+ char str[19];
+
+ do {
+ finish_dealer(bj);
+ } while (bj->dealer_total < 17);
+
+ redraw_board(bj);
+ rValue = check_totals(bj);
+
+ if (rValue == 0) {
+ rb->snprintf(str, sizeof(str), " Bust! ");
+ bj->player_money -= bj->current_bet;
+ }
+ else if (rValue == 1) {
+ rb->snprintf(str, sizeof(str), " Sorry, you lost. ");
+ bj->player_money -= bj->current_bet;
+ }
+ else if (rValue == 2) {
+ rb->snprintf(str, sizeof(str), " Push ");
+ }
+ else if (rValue == 3) {
+ rb->snprintf(str, sizeof(str), " You won! ");
+ bj->player_money+= bj->current_bet;
+ }
+ else {
+ rb->snprintf(str, sizeof(str), " Blackjack! ");
+ bj->player_money += bj->current_bet * 3 / 2;
+ }
+ rb->lcd_getstringsize(str, &w, &h);
+
+#if LCD_HEIGHT <= 64
+ rb->lcd_set_drawmode(DRMODE_BG+DRMODE_INVERSEVID);
+ rb->lcd_fillrect(0, LCD_HEIGHT/2, LCD_WIDTH, LCD_HEIGHT/2);
+ rb->lcd_set_drawmode(DRMODE_SOLID);
+ rb->lcd_putsxy(LCD_WIDTH/2 - w/2, LCD_HEIGHT/2 + h, str);
+ rb->snprintf(str, 12, "You have %d", bj->player_total);
+ rb->lcd_getstringsize(str, &w, &h);
+ rb->lcd_putsxy(LCD_WIDTH/2 - w/2, LCD_HEIGHT/2, str);
+#else
+ rb->lcd_putsxy(LCD_WIDTH/2 - w/2, LCD_HEIGHT/2 - h/2, str);
+#endif
+ rb->lcd_update();
+}
+
+/*****************************************************************************
+* blackjack_recordscore() inserts a high score into the high scores list and
+* returns the high score position.
+******************************************************************************/
+static unsigned int blackjack_recordscore(struct game_context* bj) {
+ unsigned int i;
+ unsigned int position = 0;
+ signed short current, temp;
+
+ /* calculate total score */
+ current = bj->player_money;
+ if(current <= 10) return 0;
+
+ /* insert the current score into the high scores */
+ for(i=0; i<NUM_SCORES; i++) {
+ if(current >= bj->highscores[i]) {
+ if(!position) {
+ position = i+1;
+ bj->dirty = true;
+ }
+ temp = bj->highscores[i];
+ bj->highscores[i] = current;
+ current = temp;
+ }
+ }
+
+ return position;
+}
+
+/*****************************************************************************
+* blackjack_loadscores() loads the high scores saved file.
+******************************************************************************/
+static void blackjack_loadscores(struct game_context* bj) {
+ signed int fd;
+
+ bj->dirty = false;
+
+ /* clear high scores */
+ rb->memset(bj->highscores, 0, sizeof(bj->highscores));
+
+ /* open scores file */
+ fd = rb->open(SCORE_FILE, O_RDONLY);
+ if(fd < 0) return;
+
+ /* read in high scores */
+ if(rb->read(fd, bj->highscores, sizeof(bj->highscores)) <= 0) {
+ /* scores are bad, reset */
+ rb->memset(bj->highscores, 0, sizeof(bj->highscores));
+ }
+
+ rb->close(fd);
+}
+
+/*****************************************************************************
+* blackjack_savescores() saves the high scores saved file.
+******************************************************************************/
+static void blackjack_savescores(struct game_context* bj) {
+ unsigned int fd;
+
+ /* write out the high scores to the save file */
+ fd = rb->open(SCORE_FILE, O_WRONLY|O_CREAT);
+ rb->write(fd, bj->highscores, sizeof(bj->highscores));
+ rb->close(fd);
+ bj->dirty = false;
+}
+
+/*****************************************************************************
+* blackjack_loadgame() loads the saved game and returns load success.
+******************************************************************************/
+static bool blackjack_loadgame(struct game_context* bj) {
+ signed int fd;
+ bool loaded = false;
+
+ /* open game file */
+ fd = rb->open(SAVE_FILE, O_RDONLY);
+ if(fd < 0) return loaded;
+
+ /* read in saved game */
+ while(true) {
+ if(rb->read(fd, &bj->player_money, sizeof(bj->player_money)) <= 0) break;
+ if(rb->read(fd, &bj->player_total, sizeof(bj->player_total)) <= 0) break;
+ if(rb->read(fd, &bj->dealer_total, sizeof(bj->dealer_total)) <= 0) break;
+ if(rb->read(fd, &bj->num_player_cards, sizeof(bj->num_player_cards))<=0)
+ break;
+ if(rb->read(fd, &bj->num_dealer_cards, sizeof(bj->num_dealer_cards))<=0)
+ break;
+ if(rb->read(fd, &bj->current_bet, sizeof(bj->current_bet)) <= 0) break;
+ if(rb->read(fd, &bj->is_blackjack, sizeof(bj->is_blackjack)) <= 0) break;
+ if(rb->read(fd, &bj->split_status, sizeof(bj->split_status)) <= 0) break;
+ if(rb->read(fd, &bj->asked_insurance, sizeof(bj->asked_insurance)) <= 0)
+ break;
+ if(rb->read(fd, &bj->end_hand, sizeof(bj->end_hand)) <= 0) break;
+ if(rb->read(fd, &bj->player_cards, sizeof(bj->player_cards)) <= 0) break;
+ if(rb->read(fd, &bj->dealer_cards, sizeof(bj->dealer_cards)) <= 0) break;
+ bj->resume = true;
+ loaded = true;
+ break;
+ }
+
+ rb->close(fd);
+
+ /* delete saved file */
+ rb->remove(SAVE_FILE);
+ return loaded;
+}
+
+/*****************************************************************************
+* blackjack_savegame() saves the current game state.
+******************************************************************************/
+static void blackjack_savegame(struct game_context* bj) {
+ unsigned int fd;
+
+ /* write out the game state to the save file */
+ fd = rb->open(SAVE_FILE, O_WRONLY|O_CREAT);
+ rb->write(fd, &bj->player_money, sizeof(bj->player_money));
+ rb->write(fd, &bj->player_total, sizeof(bj->player_total));
+ rb->write(fd, &bj->dealer_total, sizeof(bj->dealer_total));
+ rb->write(fd, &bj->num_player_cards, sizeof(bj->num_player_cards));
+ rb->write(fd, &bj->num_dealer_cards, sizeof(bj->num_dealer_cards));
+ rb->write(fd, &bj->current_bet, sizeof(bj->current_bet));
+ rb->write(fd, &bj->is_blackjack, sizeof(bj->is_blackjack));
+ rb->write(fd, &bj->split_status, sizeof(bj->split_status));
+ rb->write(fd, &bj->asked_insurance, sizeof(bj->asked_insurance));
+ rb->write(fd, &bj->end_hand, sizeof(bj->end_hand));
+ rb->write(fd, &bj->player_cards, sizeof(bj->player_cards));
+ rb->write(fd, &bj->dealer_cards, sizeof(bj->dealer_cards));
+ rb->close(fd);
+
+ bj->resume = true;
+}
+
+/*****************************************************************************
+* blackjack_callback() is the default event handler callback which is called
+* on usb connect and shutdown.
+******************************************************************************/
+static void blackjack_callback(void* param) {
+ struct game_context* bj = (struct game_context*) param;
+ if(bj->dirty) {
+ rb->splash(HZ, true, "Saving high scores...");
+ blackjack_savescores(bj);
+ }
+}
+
+/*****************************************************************************
+* blackjack_get_yes_no() gets a yes/no answer from the user
+******************************************************************************/
+static unsigned int blackjack_get_yes_no(char message[20]) {
+ int button;
+ unsigned int w, h, b, choice = 0;
+ bool breakout = false;
+ char message_yes[24], message_no[24];
+
+ rb->strcpy(message_yes, message);
+ rb->strcpy(message_no, message);
+ rb->strcat(message_yes, " Yes");
+ rb->strcat(message_no, " No");
+ rb->lcd_getstringsize(message_yes, &w, &h);
+ const char *stg[] = {message_yes, message_no};
+
+#if LCD_HEIGHT <= 64
+ b = 2*h+1;
+#else
+ b = h-1;
+#endif
+
+#ifdef HAVE_LCD_COLOR
+ rb->lcd_fillrect(LCD_WIDTH/2 - w/2, LCD_HEIGHT/2 + b, w+1, h+3);
+ rb->lcd_set_foreground(LCD_BLACK);
+ rb->lcd_set_background(LCD_WHITE);
+#else
+ rb->lcd_set_drawmode(DRMODE_BG+DRMODE_INVERSEVID);
+ rb->lcd_fillrect(LCD_WIDTH/2 - w/2, LCD_HEIGHT/2 + b, w+1, h+3);
+ rb->lcd_set_drawmode(DRMODE_SOLID);
+#endif
+ rb->lcd_drawrect(LCD_WIDTH/2 - w/2 - 1, LCD_HEIGHT/2 + b - 1, w+3, h+4);
+
+ while(!breakout) {
+ rb->lcd_putsxy(LCD_WIDTH/2 - w/2, LCD_HEIGHT/2 + b +1, stg[choice]);
+ rb->lcd_update_rect(LCD_WIDTH/2 - w/2 - 1, LCD_HEIGHT/2 + b -1,
+ w+3, h+4);
+ button = rb->button_get(true);
+
+ switch(button) {
+ case BJACK_LEFT:
+ case (BJACK_LEFT|BUTTON_REPEAT):
+ case BJACK_RIGHT:
+ case (BJACK_RIGHT|BUTTON_REPEAT):
+ choice ^= 1;
+ break;
+ case BJACK_START: breakout = true;
+ break;
+ case BJACK_QUIT: breakout = true;
+ choice = BJ_QUIT;
+ break;
+ }
+ }
+
+#if LCD_DEPTH > 1
+ rb->lcd_set_foreground(FG_COLOR);
+ rb->lcd_set_background(BG_COLOR);
+#endif
+ return choice;
+}
+
+/*****************************************************************************
+* blackjack_get_amount() gets an amount from the player to be used
+******************************************************************************/
+static signed int blackjack_get_amount(char message[20], signed int lower_limit,
+ signed int upper_limit,
+ signed int start) {
+ int button;
+ char str[6];
+ bool changed = false;
+ unsigned int w, h;
+ signed int amount;
+
+ rb->lcd_getstringsize("A", &w, &h); /* find the size of one character */
+
+ if (start > upper_limit)
+ amount = upper_limit;
+ else if (start < lower_limit)
+ amount = lower_limit;
+ else
+ amount = start;
+
+#if LCD_DEPTH > 1
+ rb->lcd_set_background(LCD_WHITE);
+ rb->lcd_set_foreground(LCD_BLACK);
+#endif
+
+#if LCD_HEIGHT <= 64
+ rb->lcd_clear_display();
+ rb->lcd_puts(0, 1, message);
+ rb->snprintf(str, 9, "$%d", amount);
+ rb->lcd_puts(0, 2, str);
+ rb->lcd_puts(0, 3, "RIGHT: +1");
+ rb->lcd_puts(0, 4, "LEFT: -1");
+ rb->lcd_puts(0, 5, "UP: +10");
+ rb->lcd_puts(0, 6, "DOWN: -10");
+ rb->lcd_update();
+#else
+ rb->lcd_set_drawmode(DRMODE_BG+DRMODE_INVERSEVID);
+ rb->lcd_fillrect(LCD_WIDTH/2 - 9*w - 1, LCD_HEIGHT/2 - 4*h - 3, 37*w / 2,
+ 8*h -3);
+ rb->lcd_set_drawmode(DRMODE_SOLID);
+ rb->lcd_drawrect(LCD_WIDTH/2 - 9*w - 1, LCD_HEIGHT/2 - 4*h - 3, 37*w / 2,
+ 8*h -3);
+ rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 4*h - 1, message);
+ rb->snprintf(str, 9, "$%d", amount);
+ rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 3*h, str);
+#if (CONFIG_KEY == IPOD_3G_PAD) || (CONFIG_KEYPAD == IPOD_4G_PAD)
+ rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - h-2, " >>|: +1");
+ rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 1, " |<<: -1");
+ rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 + h, "SCROLL+: +10");
+ rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 + 2*h + 1, "SCROLL-: -10");
+#elif CONFIG_KEYPAD == IRIVER_H10_PAD
+ rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - h-2, "RIGHT: +1");
+ rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 1, "LEFT: -1");
+ rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 + h, "SCROLL+: +10");
+ rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 + 2*h + 1, "SCROLL-: -10");
+#else
+ rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - h-2, "RIGHT: +1");
+ rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 1, "LEFT: -1");
+ rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 + h, "UP: +10");
+ rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 + 2*h + 1, "DOWN: -10");
+#endif
+ rb->lcd_update_rect(LCD_WIDTH/2 - 9*w - 2, LCD_HEIGHT/2 - 9*h/2, 37*w/2 + 1,
+ 8*h-2);
+#endif
+
+ while(true) {
+ button = rb->button_get(true);
+
+ switch(button) {
+ case BJACK_UP:
+ case (BJACK_UP|BUTTON_REPEAT):
+ if (amount + 10 < upper_limit + 1) {
+ amount += 10;
+ changed = true;
+ }
+ break;
+ case BJACK_DOWN:
+ case (BJACK_DOWN|BUTTON_REPEAT):
+ if (amount - 10 > lower_limit - 1) {
+ amount -= 10;
+ changed = true;
+ }
+ break;
+ case BJACK_RIGHT:
+ case (BJACK_RIGHT|BUTTON_REPEAT):
+ if (amount + 1 < upper_limit + 1) {
+ amount++;
+ changed = true;
+ }
+ break;
+ case BJACK_LEFT:
+ case (BJACK_LEFT|BUTTON_REPEAT):
+ if (amount - 1 > lower_limit - 1) {
+ amount--;
+ changed = true;
+ }
+ break;
+ case BJACK_MAX :
+ amount = upper_limit;
+ changed = true;
+ break;
+ case BJACK_MIN :
+ amount = lower_limit;
+ changed = true;
+ break;
+ case BJACK_QUIT:
+ return 0;
+ case BJACK_START:
+#if LCD_DEPTH > 1
+ rb->lcd_set_foreground(FG_COLOR);
+ rb->lcd_set_background(BG_COLOR);
+#endif
+ rb->lcd_clear_display();
+ return amount;
+ }
+
+ if(changed) {
+ rb->snprintf(str, 9, "$%d", amount);
+#if LCD_HEIGHT <= 64
+ rb->lcd_puts(0, 2, str);
+ rb->lcd_update();
+#else
+ rb->lcd_set_drawmode(DRMODE_BG+DRMODE_INVERSEVID);
+ rb->lcd_fillrect(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 3*h, 5*w, h);
+ rb->lcd_set_drawmode(DRMODE_SOLID);
+ rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 3*h, str);
+ rb->lcd_update_rect(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 3*h, 5*w, h);
+#endif
+ changed = false;
+ }
+ }
+}
+
+/*****************************************************************************
+* blackjack_get_bet() gets the player's bet.
+******************************************************************************/
+static void blackjack_get_bet(struct game_context* bj) {
+ bj->current_bet = blackjack_get_amount("Please enter a bet", 10,
+ bj->player_money, bj->current_bet);
+}
+
+/*****************************************************************************
+* double_down() returns one final card then finishes the game
+******************************************************************************/
+static void double_down(struct game_context* bj) {
+ bj->current_bet *= 2;
+ bj->player_cards[0][bj->num_player_cards[0]] = new_card();
+ bj->player_total += bj->player_cards[0][bj->num_player_cards[0]].value;
+ bj->num_player_cards[0]++;
+}
+
+/*****************************************************************************
+* split() checks if the player wants to split and acts accordingly.
+* When bj->split_status is 1, no split occurred. 2 means the player split and 3
+* means a split has already occurred and the first hand is done.
+******************************************************************************/
+static void split(struct game_context* bj) {
+ if (blackjack_get_yes_no("Split?") == 1)
+ bj->split_status = 1;
+ else {
+ bj->split_status = 2;
+ bj->current_bet *= 2;
+ bj->num_player_cards[0] = 1;
+ bj->num_player_cards[1] = 1;
+ bj->player_cards[1][0] = bj->player_cards[0][1];
+ bj->player_total = bj->player_cards[0][0].value;
+ }
+}
+
+/*****************************************************************************
+* insurance() see if the player wants to buy insurance and how much.
+******************************************************************************/
+static unsigned int insurance(struct game_context* bj) {
+ unsigned int insurance, max_amount;
+
+ insurance = blackjack_get_yes_no("Buy Insurance?");
+ bj->asked_insurance = true;
+ max_amount = bj->current_bet < (unsigned int)bj->player_money ?
+ bj->current_bet/2 : (unsigned int)bj->player_money;
+ if (insurance == 1) return 0;
+
+ insurance = blackjack_get_amount("How much?", 0, max_amount, 0);
+ redraw_board(bj);
+ return insurance;
+}
+
+/*****************************************************************************
+* play_again() checks to see if the player wants to keep playing.
+******************************************************************************/
+static unsigned int play_again(void) {
+ return blackjack_get_yes_no("Play Again?");
+}
+
+/*****************************************************************************
+* blackjack_menu() is the initial menu at the start of the game.
+******************************************************************************/
+static unsigned int blackjack_menu(struct game_context* bj) {
+ int button;
+ char *title = "Blackjack";
+ char str[18];
+ unsigned int i, w, h;
+ bool breakout = false;
+ bool showscores = false;
+
+ while(true){
+#if LCD_DEPTH > 1
+ rb->lcd_set_background(BG_COLOR);
+ rb->lcd_set_foreground(FG_COLOR);
+#endif
+ rb->lcd_clear_display();
+
+ if(!showscores) {
+ /* welcome screen to display key bindings */
+ rb->lcd_getstringsize(title, &w, &h);
+ rb->lcd_putsxy((LCD_WIDTH-w)/2, 0, title);
+
+#if CONFIG_KEYPAD == RECORDER_PAD
+ rb->lcd_puts(0, 1, "ON: start");
+ rb->lcd_puts(0, 2, "OFF: exit");
+ rb->lcd_puts(0, 3, "F1: hit");
+ rb->lcd_puts(0, 4, "F2: stay");
+ rb->lcd_puts(0, 5, "F3: double down");
+ rb->lcd_puts(0, 6, "PLAY: save/resume");
+ rb->snprintf(str, 21, "High Score: $%d", bj->highscores[0]);
+ rb->lcd_puts(0, 7, str);
+#elif CONFIG_KEYPAD == ONDIO_PAD
+ rb->lcd_puts(0, 1, "MENU: start");
+ rb->lcd_puts(0, 2, "OFF: exit");
+ rb->lcd_puts(0, 3, "LEFT: hit");
+ rb->lcd_puts(0, 4, "RIGHT: stay");
+ rb->lcd_puts(0, 5, "UP: double down");
+ rb->lcd_puts(0, 6, "DOWN: save/resume");
+ rb->snprintf(str, 21, "High Score: $%d", bj->highscores[0]);
+ rb->lcd_puts(0, 7, str);
+#elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || (CONFIG_KEYPAD == IRIVER_H300_PAD)
+ rb->lcd_puts(0, 2, "PLAY to start & to hit");
+ rb->lcd_puts(0, 3, "STOP to exit");
+ rb->lcd_puts(0, 4, "REC to stay");
+ rb->lcd_puts(0, 5, "NAVI to double down ");
+ rb->lcd_puts(0, 6, " & to view highscores");
+ rb->lcd_puts(0, 7, "AB to save/resume");
+ rb->snprintf(str, 21, "High Score: $%d", bj->highscores[0]);
+ rb->lcd_puts(0, 8, str);
+#elif CONFIG_KEYPAD == IRIVER_H10_PAD
+ rb->lcd_puts(0, 2, "PLAY to start & hit");
+ rb->lcd_puts(0, 3, "POWER to exit");
+ rb->lcd_puts(0, 4, ">>| to stay");
+ rb->lcd_puts(0, 5, "|<< to double down");
+ rb->lcd_puts(0, 6, "LEFT to view scores");
+ rb->lcd_puts(0, 7, "RIGHT to save/resume");
+ rb->snprintf(str, 21, "High Score: $%d", bj->highscores[0]);
+ rb->lcd_puts(0, 8, str);
+
+#elif (CONFIG_KEYPAD == IPOD_3G_PAD) || (CONFIG_KEYPAD == IPOD_4G_PAD)
+#if LCD_WIDTH >=176
+ rb->lcd_puts(0, 2, "SELECT to start & to hit");
+ rb->lcd_puts(0, 3, "MENU to exit");
+ rb->lcd_puts(0, 4, ">>| to stay & to view highscores");
+ rb->lcd_puts(0, 5, "|<< to double down");
+ rb->lcd_puts(0, 6, "PLAY to save/resume");
+ rb->snprintf(str, 21, "High Score: $%d", bj->highscores[0]);
+ rb->lcd_puts(0, 7, str);
+#else
+ rb->lcd_puts(0, 2, "SELECT to start & to ");
+ rb->lcd_puts(0, 3, " hit");
+ rb->lcd_puts(0, 4, "MENU to exit");
+ rb->lcd_puts(0, 5, ">>| to stay & to view ");
+ rb->lcd_puts(0, 6, " highscores");
+ rb->lcd_puts(0, 7, "|<< to double down");
+ rb->lcd_puts(0, 8, "PLAY to save/resume");
+ rb->snprintf(str, 21, "High Score: $%d", bj->highscores[0]);
+ rb->lcd_puts(0, 9, str);
+#endif
+#elif CONFIG_KEYPAD == IAUDIO_X5_PAD
+ rb->lcd_puts(0, 2, "PLAY to start to hit");
+ rb->lcd_puts(0, 3, "POWER to exit");
+ rb->lcd_puts(0, 4, "SELECT to hit");
+ rb->lcd_puts(0, 5, "REC to stay");
+ rb->lcd_puts(0, 6, "PLAY to double down");
+ rb->lcd_puts(0, 7, "RIGHT to view highscores ");
+ rb->lcd_puts(0, 8, "DOWN to save/resume");
+ rb->snprintf(str, 21, "High Score: $%d", bj->highscores[0]);
+ rb->lcd_puts(0, 9, str);
+#elif CONFIG_KEYPAD == IRIVER_IFP7XX_PAD
+ rb->lcd_puts(0, 2, "AB to start & to");
+ rb->lcd_puts(0, 3, " stay");
+ rb->lcd_puts(0, 4, "EQ to hit");
+ rb->lcd_puts(0, 5, "PLAY to exit");
+ rb->lcd_puts(0, 6, "CLICK to double down");
+ rb->lcd_puts(0, 7, "& to view highscores");
+ rb->lcd_puts(0, 8, "AB+EQ to save/resume");
+ rb->snprintf(str, 21, "High Score: $%d", bj->highscores[0]);
+ rb->lcd_puts(0, 9, str);
+#elif CONFIG_KEYPAD == GIGABEAT_PAD
+ rb->lcd_puts(0, 2, "POWER to start");
+ rb->lcd_puts(0, 3, "A to exit");
+ rb->lcd_puts(0, 4, "VOL+ to hit");
+ rb->lcd_puts(0, 5, "VOL- to stay");
+ rb->lcd_puts(0, 6, "CENTER to double down");
+ rb->lcd_puts(0, 6, "RIGHT to view highscores ");
+ rb->lcd_puts(0, 8, "MENU to save/resume");
+ rb->snprintf(str, 21, "High Score: $%d", bj->highscores[0]);
+ rb->lcd_puts(0, 9, str);
+#elif (CONFIG_KEYPAD == SANSA_E200_PAD)
+ rb->lcd_puts(0, 2, "SELECT to start & to hit");
+ rb->lcd_puts(0, 3, "POWER to exit");
+ rb->lcd_puts(0, 4, "RIGHT to stay");
+ rb->lcd_puts(0, 5, "LEFT to double down");
+ rb->lcd_puts(0, 6, "REC to save/resume");
+ rb->lcd_puts(0, 7, "UP to view scores");
+ rb->snprintf(str, 21, "High Score: $%d", bj->highscores[0]);
+ rb->lcd_puts(0, 8, str);
+
+#endif
+ } else {
+ rb->snprintf(str, 12, "%s", "High Scores");
+ rb->lcd_getstringsize(str, &w, &h);
+ rb->lcd_putsxy((LCD_WIDTH-w)/2, 0, str);
+
+ /* print high scores */
+ for(i=0; i<NUM_SCORES; i++) {
+ rb->snprintf(str, 14, "#%02d: $%d", i+1, bj->highscores[i]);
+ rb->lcd_puts(0, i+1, str);
+ }
+ }
+
+ rb->lcd_update();
+
+ /* handle menu button presses */
+ button = rb->button_get(true);
+
+ switch(button) {
+ case BJACK_START: /* start playing */
+ breakout = true;
+ break;
+
+ case BJACK_QUIT: /* quit program */
+ if(showscores) {
+ showscores = 0;
+ break;
+ }
+ return BJ_QUIT;
+
+ case BJACK_RESUME:/* resume game */
+ if(!blackjack_loadgame(bj)) {
+ rb->splash(HZ*2, true, "Nothing to resume");
+ } else {
+ rb->splash(HZ*2, true, "Loading...");
+ breakout = true;
+ }
+ break;
+
+ case BJACK_SCORES:/* toggle high scores */
+ showscores = !showscores;
+ break;
+
+ default:
+ if(rb->default_event_handler_ex(button, blackjack_callback,
+ (void*) bj) == SYS_USB_CONNECTED)
+ return BJ_USB;
+ break;
+ }
+
+ if(breakout) break;
+ }
+
+ return(0);
+}
+
+/*****************************************************************************
+* blackjack() is the main game subroutine, it returns the final game status.
+******************************************************************************/
+static int blackjack(struct game_context* bj) {
+ int button;
+ unsigned int w, h, temp_var, done = 0, todo = 1;
+ signed int temp;
+ bool breakout = false;
+ bool dbl_down = false;
+
+ /* don't resume by default */
+ bj->resume = false;
+
+ /********************
+ * menu *
+ ********************/
+ temp_var = blackjack_menu(bj);
+ if (temp_var == BJ_QUIT || temp_var == BJ_USB)
+ return temp_var;
+
+
+ /********************
+ * init *
+ ********************/
+ blackjack_init(bj);
+ bj->current_bet=10;
+
+ /********************
+ * play *
+ ********************/
+
+ /* check for resumed game */
+ if(bj->resume) {
+ bj->resume = false;
+ redraw_board(bj);
+ if (bj->split_status == 2) {
+ todo=2;
+ player_x = bj->num_player_cards[0] * 10 + 4;
+ }
+ else if (bj->split_status == 3) {
+ player_x = bj->num_player_cards[1] * 10 + LCD_WIDTH/2 + 4;
+ todo=2;
+ done=1;
+ }
+
+ }
+ else {
+ bj->player_money = 1000;
+ blackjack_get_bet(bj);
+ if (bj->current_bet == 0)
+ return BJ_QUIT;
+ rb->lcd_clear_display();
+ deal_init_cards(bj);
+ blackjack_drawtable(bj);
+ }
+
+ rb->lcd_update();
+
+ breakout = false;
+
+ while(true){
+ if(bj->player_total == 21 && bj->num_player_cards[0] == 2) {
+ bj->is_blackjack = true;
+ bj->end_hand = true;
+ finish_game(bj);
+ }
+ else if(bj->dealer_cards[1].is_soft_ace && !breakout &&
+ !bj->asked_insurance) {
+ temp_var = insurance(bj);
+ if (bj->dealer_total == 21) {
+ rb->splash(HZ, true, "Dealer has blackjack");
+ bj->player_money += temp_var;
+ bj->end_hand = true;
+ breakout = true;
+ redraw_board(bj);
+ finish_game(bj);
+ }
+ else {
+ rb->splash(HZ, true, "Dealer does not have blackjack");
+ bj->player_money -= temp_var;
+ breakout = true;
+ redraw_board(bj);
+ rb->lcd_update();
+ }
+ }
+ if(bj->split_status == 0 &&
+ bj->player_cards[0][0].num == bj->player_cards[0][1].num) {
+ split(bj);
+ redraw_board(bj);
+ rb->lcd_update_rect(0, LCD_HEIGHT/2, LCD_WIDTH, LCD_HEIGHT/2);
+ if (bj->split_status == 2) {
+ todo++;
+ player_x = bj->num_player_cards[0] * 10 + 4;
+ }
+ }
+
+ while(done < todo) {
+ button = rb->button_get(true);
+
+ switch(button) {
+ case BJACK_HIT:
+ NEXT_CARD = new_card();
+ bj->player_total += NEXT_CARD.value;
+ draw_card(NEXT_CARD, true, player_x, player_y);
+ bj->num_player_cards[done]++;
+ if (bj->num_player_cards[done] == MAX_CARDS + 1) {
+ redraw_board(bj);
+ rb->lcd_update_rect(0, LCD_HEIGHT/2, LCD_WIDTH,
+ LCD_HEIGHT/2);
+ }
+ else if (bj->num_player_cards[done]>MAX_CARDS || todo > 1) {
+ rb->lcd_update_rect(player_x, player_y, CARD_WIDTH+2,
+ CARD_HEIGHT+2);
+ player_x += 10;
+ }
+ else {
+ rb->lcd_update_rect(player_x, player_y, CARD_WIDTH+2,
+ CARD_HEIGHT+2);
+ player_x += CARD_WIDTH + 4;
+ }
+ update_total(bj);
+
+ break;
+ case BJACK_STAY:
+ bj->end_hand = true;
+ break;
+ case BJACK_DOUBLEDOWN:
+ if ((signed int)bj->current_bet * 2 < bj->player_money + 1 &&
+ bj->num_player_cards[0]==2 && todo==1) {
+ double_down(bj);
+ dbl_down = true;
+ if (bj->player_total < 22) {
+ bj->end_hand = true;
+ finish_game(bj);
+ }
+ }
+ else if((signed int)bj->current_bet * 2 > bj->player_money) {
+ rb->splash(HZ, true, "Not enough money to double down.");
+ redraw_board(bj);
+ rb->lcd_update();
+ }
+ break;
+ case BJACK_RESUME: /* save and end game */
+ rb->splash(HZ, true, "Saving game...");
+ blackjack_savegame(bj);
+ /* fall through to BJACK_QUIT */
+
+ case BJACK_QUIT:
+ return BJ_END;
+ }
+
+ while (bj->player_total > 21 && !bj->end_hand) {
+ temp = check_for_aces(bj->player_cards[done],
+ bj->num_player_cards[done]);
+ if(temp != -1) {
+ bj->player_cards[done][temp].is_soft_ace = false;
+ bj->player_total -= 10;
+ update_total(bj);
+ if (dbl_down) {
+ bj->end_hand = true;
+ finish_game(bj);
+ }
+ }
+ else
+ bj->end_hand = true;
+ }
+
+ if (bj->end_hand) {
+ done++;
+ if(todo > 1) {
+ if (done == 2) {
+ temp = bj->player_total;
+ bj->player_total = temp_var;
+ temp_var = temp;
+ finish_game(bj);
+ rb->lcd_getstringsize(" Split 1 ", &w, &h);
+ rb->lcd_putsxy(LCD_WIDTH/2-w/2, LCD_HEIGHT/2-3*h/2,
+ " Split 1 ");
+ rb->lcd_update_rect(LCD_WIDTH/2-w/2, LCD_HEIGHT/2-3*h/2,
+ w,h);
+ bj->current_bet /= 2;
+ rb->lcd_update_rect(LCD_WIDTH/2-w/2, LCD_HEIGHT/2-3*h/2,
+ w,h);
+ rb->sleep(HZ*2);
+ bj->player_total = temp_var;
+ finish_game(bj);
+ rb->lcd_getstringsize(" Split 2 ", &w, &h);
+ rb->lcd_putsxy(LCD_WIDTH/2-w/2, LCD_HEIGHT/2-3*h/2,
+ " Split 2 ");
+ rb->lcd_update_rect(LCD_WIDTH/2-w/2, LCD_HEIGHT/2-3*h/2,
+ w,h);
+ rb->sleep(HZ*2);
+ }
+ else {
+ bj->end_hand = false;
+ bj->split_status = 3;
+ temp_var = bj->player_total;
+ bj->player_total = bj->player_cards[1][0].value;
+ update_total(bj);
+ redraw_board(bj);
+ player_x += 10;
+ rb->lcd_update();
+ }
+ }
+ else
+ finish_game(bj);
+ }
+ }
+
+ if (bj->player_money < 10) {
+ rb->sleep(HZ);
+ return BJ_LOSE;
+ }
+
+ if (bj->end_hand) { /* If hand is over */
+ if (play_again() != 0) /* User wants to quit */
+ return BJ_END;
+ else { /* User keeps playing */
+ breakout = false;
+ redraw_board(bj);
+ if(dbl_down) {
+ bj->current_bet /= 2;
+ dbl_down = false;
+ }
+ done = 0;
+ todo = 1;
+ blackjack_init(bj);
+ blackjack_get_bet(bj);
+ if (bj->current_bet == 0)
+ return BJ_END;
+ deal_init_cards(bj);
+ blackjack_drawtable(bj);
+ rb->lcd_update();
+ }
+ }
+ }
+ /* Never reached */
+ return PLUGIN_OK;
+}
+
+/*****************************************************************************
+* plugin entry point.
+******************************************************************************/
+enum plugin_status plugin_start(struct plugin_api* api, void* parameter) {
+ struct game_context bj;
+ bool exit = false;
+ unsigned int position;
+ char str[19];
+
+ (void)parameter;
+ rb = api;
+
+ /* load high scores */
+ blackjack_loadscores(&bj);
+
+ rb->lcd_setfont(FONT_SYSFIXED);
+
+ while(!exit) {
+ switch(blackjack(&bj)){
+ case BJ_LOSE:
+ rb->splash(HZ, true, "Not enough money to continue");
+ /* fall through to BJ_END */
+
+ case BJ_END:
+ if(!bj.resume) {
+ if((position = blackjack_recordscore(&bj))) {
+ rb->snprintf(str, 19, "New high score #%d!", position);
+ rb->splash(HZ*2, true, str);
+ }
+ }
+ break;
+
+ case BJ_USB:
+ rb->lcd_setfont(FONT_UI);
+ return PLUGIN_USB_CONNECTED;
+
+ case BJ_QUIT:
+ if(bj.dirty) {
+ rb->splash(HZ, true, "Saving high scores...");
+ blackjack_savescores(&bj);
+ }
+ exit = true;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ rb->lcd_setfont(FONT_UI);
+ return PLUGIN_OK;
+}
diff --git a/manual/plugins/blackjack.tex b/manual/plugins/blackjack.tex
new file mode 100644
index 0000000000..7a7caa491a
--- /dev/null
+++ b/manual/plugins/blackjack.tex
@@ -0,0 +1,81 @@
+\subsection{Blackjack}
+\screenshot{plugins/images/ss-blackjack}{Blackjack}{fig:blackjack}
+
+Blackjack, a game played in casinos around the world, is now available
+in the palm of your hand! The rules are simple: try to get as close to 21
+without going over or simply beat out the dealer for the best hand.
+Although this may not seem difficult, blackjack is a game renowned for the
+strategy involved. This version includes the ability to split, buy insurance,
+and double down.
+
+For the full set of rules to the game, and other facinating information
+visit\\
+\url{http://www.blackjackinfo.com/blackjack-rules.php}
+
+\begin{table}
+ \begin{btnmap}{}{}
+ \multicolumn{2}{c}{\textbf{In menu}}\\\hline
+ \opt{RECORDER_PAD,IRIVER_H100_PAD,IRIVER_H300_PAD}{\ButtonOn}
+ \opt{GIGABEAT_PAD}{\ButtonPower}
+ \opt{IAUDIO_X5_PAD,IRIVER_H10_PAD}{\ButtonPlay}
+ \opt{IPOD_4G_PAD,IPOD_3G_PAD,SANSA_E200_PAD}{\ButtonSelect}
+ \opt{ONDIO_PAD}{\ButtonMenu}
+ & Start new game\\
+ \opt{IRIVER_H100_PAD,IRIVER_H300_PAD}{\ButtonMode}
+ \opt{RECORDER_PAD,IPOD_4G_PAD,IPOD_3G_PAD}{\ButtonPlay}
+ \opt{ONDIO_PAD,IAUDIO_X5_PAD}{\ButtonDown}
+ \opt{IRIVER_H10_PAD}{\ButtonRight}
+ \opt{SANSA_E200_PAD}{\ButtonRec}
+ \opt{GIGABEAT_PAD}{\ButtonMenu}
+ & Resume saved game\\
+ \opt{IRIVER_H100_PAD,IRIVER_H300_PAD}{\ButtonSelect}
+ \opt{RECORDER_PAD,IAUDIO_X5_PAD,IPOD_4G_PAD,IPOD_3G_PAD,GIGABEAT_PAD}{\ButtonRight}
+ \opt{ONDIO_PAD,SANSA_E200_PAD}{\ButtonUp}
+ \opt{IRIVER_H10_PAD}{\ButtonLeft}
+ & Show high scores\\
+ \opt{RECORDER_PAD,ONDIO_PAD,IRIVER_H100_PAD,IRIVER_H300_PAD}{\ButtonOff}
+ \opt{IPOD_4G_PAD,IPOD_3G_PAD}{\ButtonMenu}
+ \opt{IAUDIO_X5_PAD,IRIVER_H10_PAD,SANSA_E200_PAD}{\ButtonPower}
+ \opt{GIGABEAT_PAD}{\ButtonA}
+ & Quit\\\hline
+ \multicolumn{2}{c}{\textbf{In game}}\\\hline
+ \ButtonLeft/\ButtonRight/\\
+ \opt{RECORDER_PAD,ONDIO_PAD,IRIVER_H100_PAD,IRIVER_H300_PAD,IAUDIO_X5_PAD,GIGABEAT_PAD}
+ {\ButtonUp/\ButtonDown}
+ \opt{IPOD_4G_PAD,IPOD_3G_PAD}{\ButtonScrollFwd/\ButtonScrollBack}
+ \opt{IRIVER_H10_PAD,SANSA_E200_PAD}{\ButtonScrollUp/\ButtonScrollDown}
+ & Enter betting amount\\
+ \opt{RECORDER_PAD}{\ButtonFOne}
+ \opt{IRIVER_H100_PAD,IRIVER_H300_PAD}{\ButtonOn}
+ \opt{IRIVER_H10_PAD}{\ButtonPlay}
+ \opt{IPOD_4G_PAD,IPOD_3G_PAD,IAUDIO_X5_PAD,SANSA_E200_PAD}{\ButtonSelect}
+ \opt{ONDIO_PAD}{\ButtonLeft}
+ \opt{GIGABEAT_PAD}{\ButtonVolUp}
+ & Hit (Draw new card)\\
+ \opt{RECORDER_PAD}{\ButtonFTwo}
+ \opt{IRIVER_H100_PAD,IRIVER_H300_PAD,IAUDIO_X5_PAD}{\ButtonRec}
+ \opt{IRIVER_H10_PAD}{\ButtonFF}
+ \opt{ONDIO_PAD,IPOD_4G_PAD,IPOD_3G_PAD,SANSA_E200_PAD}{\ButtonRight}
+ \opt{GIGABEAT_PAD}{\ButtonVolDown}
+ & Stay (End hand)\\
+ \opt{RECORDER_PAD}{\ButtonFThree}
+ \opt{IRIVER_H100_PAD,IRIVER_H300_PAD,GIGABEAT_PAD}{\ButtonSelect}
+ \opt{IAUDIO_X5_PAD}{\ButtonPlay}
+ \opt{IRIVER_H10_PAD}{\ButtonRew}
+ \opt{ONDIO_PAD}{\ButtonUp}
+ \opt{IPOD_4G_PAD,IPOD_3G_PAD,SANSA_E200_PAD}{\ButtonLeft}
+ & Double down\\
+ \opt{IRIVER_H100_PAD,IRIVER_H300_PAD}{\ButtonMode}
+ \opt{RECORDER_PAD,IPOD_4G_PAD,IPOD_3G_PAD}{\ButtonPlay}
+ \opt{ONDIO_PAD,IAUDIO_X5_PAD}{\ButtonDown}
+ \opt{IRIVER_H10_PAD}{\ButtonRight}
+ \opt{SANSA_E200_PAD}{\ButtonRec}
+ \opt{GIGABEAT_PAD}{\ButtonMenu}
+ & Save game\\
+ \opt{RECORDER_PAD,ONDIO_PAD,IRIVER_H100_PAD,IRIVER_H300_PAD}{\ButtonOff}
+ \opt{IPOD_4G_PAD,IPOD_3G_PAD}{\ButtonMenu}
+ \opt{IAUDIO_X5_PAD,IRIVER_H10_PAD,SANSA_E200_PAD}{\ButtonPower}
+ \opt{GIGABEAT_PAD}{\ButtonA}
+ & Return to menu or cancel\\\hline
+ \end{btnmap}
+\end{table}
diff --git a/manual/plugins/images/ss-blackjack-112x64x1.png b/manual/plugins/images/ss-blackjack-112x64x1.png
new file mode 100644
index 0000000000..851c80e7c6
--- /dev/null
+++ b/manual/plugins/images/ss-blackjack-112x64x1.png
Binary files differ
diff --git a/manual/plugins/images/ss-blackjack-128x128x16.png b/manual/plugins/images/ss-blackjack-128x128x16.png
new file mode 100644
index 0000000000..6fe59e22c3
--- /dev/null
+++ b/manual/plugins/images/ss-blackjack-128x128x16.png
Binary files differ
diff --git a/manual/plugins/images/ss-blackjack-138x110x2.png b/manual/plugins/images/ss-blackjack-138x110x2.png
new file mode 100644
index 0000000000..c1669b354e
--- /dev/null
+++ b/manual/plugins/images/ss-blackjack-138x110x2.png
Binary files differ
diff --git a/manual/plugins/images/ss-blackjack-160x128x16.png b/manual/plugins/images/ss-blackjack-160x128x16.png
new file mode 100644
index 0000000000..464b8f8114
--- /dev/null
+++ b/manual/plugins/images/ss-blackjack-160x128x16.png
Binary files differ
diff --git a/manual/plugins/images/ss-blackjack-160x128x2.png b/manual/plugins/images/ss-blackjack-160x128x2.png
new file mode 100644
index 0000000000..5a28aace39
--- /dev/null
+++ b/manual/plugins/images/ss-blackjack-160x128x2.png
Binary files differ
diff --git a/manual/plugins/images/ss-blackjack-176x132x16.png b/manual/plugins/images/ss-blackjack-176x132x16.png
new file mode 100644
index 0000000000..304373306f
--- /dev/null
+++ b/manual/plugins/images/ss-blackjack-176x132x16.png
Binary files differ
diff --git a/manual/plugins/images/ss-blackjack-176x220x16.png b/manual/plugins/images/ss-blackjack-176x220x16.png
new file mode 100644
index 0000000000..258e222dfa
--- /dev/null
+++ b/manual/plugins/images/ss-blackjack-176x220x16.png
Binary files differ
diff --git a/manual/plugins/images/ss-blackjack-220x176x16.png b/manual/plugins/images/ss-blackjack-220x176x16.png
new file mode 100644
index 0000000000..ea1237ae47
--- /dev/null
+++ b/manual/plugins/images/ss-blackjack-220x176x16.png
Binary files differ
diff --git a/manual/plugins/images/ss-blackjack-240x320x16.png b/manual/plugins/images/ss-blackjack-240x320x16.png
new file mode 100644
index 0000000000..7516ed9afc
--- /dev/null
+++ b/manual/plugins/images/ss-blackjack-240x320x16.png
Binary files differ
diff --git a/manual/plugins/images/ss-blackjack-320x240x16.png b/manual/plugins/images/ss-blackjack-320x240x16.png
new file mode 100644
index 0000000000..c26e4866b1
--- /dev/null
+++ b/manual/plugins/images/ss-blackjack-320x240x16.png
Binary files differ
diff --git a/manual/plugins/main.tex b/manual/plugins/main.tex
index a92c3e2a8c..2d10ffe81b 100644
--- a/manual/plugins/main.tex
+++ b/manual/plugins/main.tex
@@ -18,6 +18,8 @@ text files, chip8 games), or from the \setting{Open with} option on the
\opt{recorder,recorderv2fm,h1xx,h300,ipodcolor,ipodvideo,sansa}
{and Rockboy in \reference{ref:Rockboy}}.}
+\opt{HAVE_LCD_BITMAP}{\input{plugins/blackjack.tex}}
+
\opt{HAVE_LCD_BITMAP}{\input{plugins/brickmania.tex}}
\opt{HAVE_LCD_BITMAP}{\input{plugins/bubbles.tex}}