/*************************************************************************** * __________ __ ___. * Open \______ \ ____ ____ | | _\_ |__ _______ ___ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ * \/ \/ \/ \/ \/ * $Id$ * * Copyright (C) 2006 Tom Ross * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ****************************************************************************/ #include "plugin.h" #include "pluginbitmaps/card_deck.h" #include "pluginbitmaps/card_back.h" PLUGIN_HEADER /* save files */ #define SCORE_FILE PLUGIN_GAMES_DIR "/blackjack.score" #define SAVE_FILE PLUGIN_GAMES_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_4G_PAD) || \ (CONFIG_KEYPAD == IPOD_3G_PAD) || \ (CONFIG_KEYPAD == IPOD_1G2G_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_X5M5_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_A #define BJACK_QUIT BUTTON_POWER #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_DOWN #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 == SANSA_FUZE_PAD #define BJACK_START BUTTON_SELECT #define BJACK_QUIT (BUTTON_HOME|BUTTON_REPEAT) #define BJACK_MAX (BUTTON_SELECT|BUTTON_UP) #define BJACK_MIN (BUTTON_SELECT|BUTTON_DOWN) #define BJACK_HIT (BUTTON_SELECT|BUTTON_REL) #define BJACK_STAY BUTTON_RIGHT #define BJACK_DOUBLEDOWN BUTTON_LEFT #define BJACK_SCORES BUTTON_DOWN #define BJACK_RESUME BUTTON_UP #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 == SANSA_C200_PAD #define BJACK_START BUTTON_SELECT #define BJACK_QUIT BUTTON_POWER #define BJACK_MAX BUTTON_VOL_UP #define BJACK_MIN BUTTON_VOL_DOWN #define BJACK_HIT BUTTON_SELECT #define BJACK_STAY BUTTON_RIGHT #define BJACK_DOUBLEDOWN BUTTON_LEFT #define BJACK_SCORES BUTTON_REC #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 == SANSA_CLIP_PAD #define BJACK_START BUTTON_SELECT #define BJACK_QUIT BUTTON_POWER #define BJACK_MAX BUTTON_VOL_UP #define BJACK_MIN BUTTON_VOL_DOWN #define BJACK_HIT BUTTON_SELECT #define BJACK_STAY BUTTON_RIGHT #define BJACK_DOUBLEDOWN BUTTON_LEFT #define BJACK_SCORES BUTTON_HOME #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 == SANSA_M200_PAD #define BJACK_START (BUTTON_SELECT | BUTTON_REL) #define BJACK_QUIT BUTTON_POWER #define BJACK_MAX BUTTON_VOL_UP #define BJACK_MIN BUTTON_VOL_DOWN #define BJACK_HIT (BUTTON_SELECT | BUTTON_REL) #define BJACK_STAY BUTTON_RIGHT #define BJACK_DOUBLEDOWN BUTTON_LEFT #define BJACK_SCORES (BUTTON_SELECT | 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 == 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 #elif CONFIG_KEYPAD == GIGABEAT_S_PAD #define BJACK_START BUTTON_PLAY #define BJACK_QUIT BUTTON_BACK #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 == MROBE100_PAD #define BJACK_START BUTTON_SELECT #define BJACK_QUIT BUTTON_POWER #define BJACK_MAX BUTTON_MENU #define BJACK_MIN BUTTON_DISPLAY #define BJACK_HIT BUTTON_MENU #define BJACK_STAY BUTTON_DISPLAY #define BJACK_DOUBLEDOWN BUTTON_DOWN #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 == IAUDIO_M3_PAD #define BJACK_START BUTTON_RC_PLAY #define BJACK_QUIT BUTTON_RC_REC #define BJACK_MAX (BUTTON_RC_PLAY|BUTTON_RC_VOL_UP) #define BJACK_MIN (BUTTON_RC_PLAY|BUTTON_RC_VOL_DOWN) #define BJACK_HIT BUTTON_RC_PLAY #define BJACK_STAY BUTTON_RC_FF #define BJACK_DOUBLEDOWN BUTTON_RC_REW #define BJACK_SCORES BUTTON_RC_MENU #define BJACK_RESUME BUTTON_RC_MODE #define BJACK_UP BUTTON_RC_VOL_UP #define BJACK_DOWN BUTTON_RC_VOL_DOWN #define BJACK_RIGHT BUTTON_RC_FF #define BJACK_LEFT BUTTON_RC_REW #elif CONFIG_KEYPAD == COWOND2_PAD #define BJACK_QUIT BUTTON_POWER #define BJACK_DOUBLEDOWN BUTTON_MINUS #define BJACK_SCORES BUTTON_MENU #elif CONFIG_KEYPAD == CREATIVEZVM_PAD #define BJACK_START BUTTON_SELECT #define BJACK_QUIT BUTTON_BACK #define BJACK_MAX (BUTTON_CUSTOM|BUTTON_UP) #define BJACK_MIN (BUTTON_CUSTOM|BUTTON_DOWN) #define BJACK_HIT BUTTON_UP #define BJACK_STAY BUTTON_DOWN #define BJACK_DOUBLEDOWN BUTTON_CUSTOM #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 == PHILIPS_HDD1630_PAD #define BJACK_START BUTTON_MENU #define BJACK_QUIT BUTTON_POWER #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_VIEW #define BJACK_UP BUTTON_UP #define BJACK_DOWN BUTTON_DOWN #define BJACK_RIGHT BUTTON_RIGHT #define BJACK_LEFT BUTTON_LEFT #elif CONFIG_KEYPAD == ONDAVX747_PAD #define BJACK_QUIT BUTTON_POWER #define BJACK_DOUBLEDOWN BUTTON_VOL_DOWN #define BJACK_SCORES BUTTON_MENU #elif CONFIG_KEYPAD == MROBE500_PAD #define BJACK_QUIT BUTTON_POWER #else #error No keymap defined! #endif #ifdef HAVE_TOUCHSCREEN #ifndef BJACK_DOUBLEDOWN #define BJACK_DOUBLEDOWN BUTTON_MIDLEFT #endif #ifndef BJACK_SCORES #define BJACK_SCORES BUTTON_MIDRIGHT #endif #ifndef BJACK_START #define BJACK_START BUTTON_CENTER #endif #ifndef BJACK_HIT #define BJACK_HIT BUTTON_CENTER #endif #ifndef BJACK_MAX #define BJACK_MAX BUTTON_TOPRIGHT #endif #ifndef BJACK_MIN #define BJACK_MIN BUTTON_TOPLEFT #endif #ifndef BJACK_RESUME #define BJACK_RESUME BUTTON_BOTTOMRIGHT #endif #ifndef BJACK_STAY #define BJACK_STAY BUTTON_BOTTOMLEFT #endif #ifndef BJACK_UP #define BJACK_UP BUTTON_TOPMIDDLE #endif #ifndef BJACK_DOWN #define BJACK_DOWN BUTTON_BOTTOMMIDDLE #endif #ifndef BJACK_RIGHT #define BJACK_RIGHT BUTTON_MIDRIGHT #endif #ifndef BJACK_LEFT #define BJACK_LEFT BUTTON_MIDLEFT #endif #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_card_back #define CARD_HEIGHT BMPHEIGHT_card_back /* This is the max amount of cards onscreen before condensing */ #define MAX_CARDS LCD_WIDTH/(CARD_WIDTH+4) extern const fb_data card_deck[]; extern const fb_data card_back[]; #define NEXT_CARD bj->player_cards[done][bj->num_player_cards[done]] /* 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(card_deck, CARD_WIDTH*temp_card.num, CARD_HEIGHT*temp_card.suit, BMPWIDTH_card_deck, x+1, y+1, CARD_WIDTH, CARD_HEIGHT); else rb->lcd_bitmap(card_back, 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, "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_KEYPAD == IPOD_4G_PAD) || \ (CONFIG_KEYPAD == IPOD_3G_PAD) || \ (CONFIG_KEYPAD == IPOD_1G2G_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_4G_PAD) || \ (CONFIG_KEYPAD == IPOD_3G_PAD) || \ (CONFIG_KEYPAD == IPOD_1G2G_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_X5M5_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, "A to start"); rb->lcd_puts(0, 3, "POWER to exit"); rb->lcd_puts(0, 4, "VOL+ to hit"); rb->lcd_puts(0, 5, "VOL- to stay"); rb->lcd_puts(0, 6, "SELECT to double down"); rb->lcd_puts(0, 7, "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 == GIGABEAT_S_PAD rb->lcd_puts(0, 2, "PLAY to start"); rb->lcd_puts(0, 3, "BACK to exit"); rb->lcd_puts(0, 4, "VOL+ to hit"); rb->lcd_puts(0, 5, "VOL- to stay"); rb->lcd_puts(0, 6, "SELECT to double down"); rb->lcd_puts(0, 7, "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 == MROBE100_PAD rb->lcd_puts(0, 2, "SELECT to start"); rb->lcd_puts(0, 3, "POWER to exit"); rb->lcd_puts(0, 4, "MENU to hit"); rb->lcd_puts(0, 5, "DISPLAY to stay"); rb->lcd_puts(0, 6, "DOWN to double down"); rb->lcd_puts(0, 7, "RIGHT to view highscores "); 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); #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); #elif (CONFIG_KEYPAD == SANSA_C200_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, "DOWN to save/resume"); rb->lcd_puts(0, 7, "REC to view scores"); rb->snprintf(str, 21, "High Score: $%d", bj->highscores[0]); rb->lcd_puts(0, 9, str); #elif CONFIG_KEYPAD == IAUDIO_M3_PAD rb->lcd_puts(0, 2, "PLAY to start & to"); rb->lcd_puts(0, 3, " hit"); rb->lcd_puts(0, 4, "REC to exit"); rb->lcd_puts(0, 5, "FF to stay"); rb->lcd_puts(0, 6, "REW to double down"); rb->lcd_puts(0, 7, "MODE to save/resume"); rb->lcd_puts(0, 8, "MENU to view scores"); rb->snprintf(str, 21, "High Score: $%d", bj->highscores[0]); rb->lcd_puts(0, 10, str); #elif CONFIG_KEYPAD == COWOND2_PAD rb->lcd_puts(0, 6, "POWER to exit"); rb->lcd_puts(0, 7, "MINUS to double down"); rb->lcd_puts(0, 8, "MENU to view scores"); rb->snprintf(str, 21, "High Score: $%d", bj->highscores[0]); rb->lcd_puts(0, 10, str); #endif #ifdef HAVE_TOUCHSCREEN rb->lcd_puts(0, 2, "LCD CENTRE to start & to hit"); rb->lcd_puts(0, 3, "LCD BOTTOMLEFT to stay"); rb->lcd_puts(0, 4, "LCD BOTTOMRIGHT to save/resume"); #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, "Nothing to resume"); } else { rb->splash(HZ*2, "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, "Dealer has blackjack"); bj->player_money += temp_var; bj->end_hand = true; breakout = true; redraw_board(bj); finish_game(bj); } else { rb->splash(HZ, "Dealer does not have blackjack"); bj->player_money -= temp_var; breakout = true; redraw_board(bj); rb->lcd_update(); } } if(!bj->end_hand && 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(!bj->end_hand && 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, "Not enough money to double down."); redraw_board(bj); rb->lcd_update(); } break; case BJACK_RESUME: /* save and end game */ rb->splash(HZ, "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(const void* parameter) { struct game_context bj; bool exit = false; unsigned int position; char str[19]; (void)parameter; #if LCD_DEPTH > 1 rb->lcd_set_backdrop(NULL); #endif /* load high scores */ blackjack_loadscores(&bj); rb->lcd_setfont(FONT_SYSFIXED); while(!exit) { switch(blackjack(&bj)){ case BJ_LOSE: rb->splash(HZ, "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, str); } } break; case BJ_USB: rb->lcd_setfont(FONT_UI); return PLUGIN_USB_CONNECTED; case BJ_QUIT: if(bj.dirty) { rb->splash(HZ, "Saving high scores..."); blackjack_savescores(&bj); } exit = true; break; default: break; } } rb->lcd_setfont(FONT_UI); return PLUGIN_OK; }