From 913fea27fcecd907e9432f6c87970cd08b8aea28 Mon Sep 17 00:00:00 2001 From: Tom Ross Date: Tue, 16 Jan 2007 21:05:15 +0000 Subject: t! Initial version of a Blackjack plugin for bitmap-screen targets. Also includes the changes to the manual. Cross your fingers... git-svn-id: svn://svn.rockbox.org/rockbox/trunk@12030 a1c6a512-1295-4272-9138-f99709370657 --- apps/plugins/SOURCES | 1 + apps/plugins/blackjack.c | 1442 +++++++++++++++++++++ manual/plugins/blackjack.tex | 81 ++ manual/plugins/images/ss-blackjack-112x64x1.png | Bin 0 -> 476 bytes manual/plugins/images/ss-blackjack-128x128x16.png | Bin 0 -> 2047 bytes manual/plugins/images/ss-blackjack-138x110x2.png | Bin 0 -> 816 bytes manual/plugins/images/ss-blackjack-160x128x16.png | Bin 0 -> 2376 bytes manual/plugins/images/ss-blackjack-160x128x2.png | Bin 0 -> 871 bytes manual/plugins/images/ss-blackjack-176x132x16.png | Bin 0 -> 2433 bytes manual/plugins/images/ss-blackjack-176x220x16.png | Bin 0 -> 2722 bytes manual/plugins/images/ss-blackjack-220x176x16.png | Bin 0 -> 4134 bytes manual/plugins/images/ss-blackjack-240x320x16.png | Bin 0 -> 4574 bytes manual/plugins/images/ss-blackjack-320x240x16.png | Bin 0 -> 8600 bytes manual/plugins/main.tex | 2 + 14 files changed, 1526 insertions(+) create mode 100644 apps/plugins/blackjack.c create mode 100644 manual/plugins/blackjack.tex create mode 100644 manual/plugins/images/ss-blackjack-112x64x1.png create mode 100644 manual/plugins/images/ss-blackjack-128x128x16.png create mode 100644 manual/plugins/images/ss-blackjack-138x110x2.png create mode 100644 manual/plugins/images/ss-blackjack-160x128x16.png create mode 100644 manual/plugins/images/ss-blackjack-160x128x2.png create mode 100644 manual/plugins/images/ss-blackjack-176x132x16.png create mode 100644 manual/plugins/images/ss-blackjack-176x220x16.png create mode 100644 manual/plugins/images/ss-blackjack-220x176x16.png create mode 100644 manual/plugins/images/ss-blackjack-240x320x16.png create mode 100644 manual/plugins/images/ss-blackjack-320x240x16.png 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= 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; isnprintf(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 Binary files /dev/null and b/manual/plugins/images/ss-blackjack-112x64x1.png 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 Binary files /dev/null and b/manual/plugins/images/ss-blackjack-128x128x16.png 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 Binary files /dev/null and b/manual/plugins/images/ss-blackjack-138x110x2.png 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 Binary files /dev/null and b/manual/plugins/images/ss-blackjack-160x128x16.png 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 Binary files /dev/null and b/manual/plugins/images/ss-blackjack-160x128x2.png 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 Binary files /dev/null and b/manual/plugins/images/ss-blackjack-176x132x16.png 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 Binary files /dev/null and b/manual/plugins/images/ss-blackjack-176x220x16.png 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 Binary files /dev/null and b/manual/plugins/images/ss-blackjack-220x176x16.png 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 Binary files /dev/null and b/manual/plugins/images/ss-blackjack-240x320x16.png 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 Binary files /dev/null and b/manual/plugins/images/ss-blackjack-320x240x16.png 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}} -- cgit v1.2.3