/* * Jack v2.1 * $VER: jack.c 2.1 (08.20.94) * * written by John Corigliano with SAS/C 6.51 * * Copyright 1994 John Corigliano * * internet: j.corigliano@genie.geis.com * mopp@bix.com * j_mopp@delphi.com * * GEnie: J.CORIGLIANO * bix: mopp * Delphi: j_mopp * */ #define __USE_SYSBASE /* SAS/C - use Absolute Exec Base = 4 */ long __oslibversion = 37L; /* SAS/C - auotinit, WB 2.04 please */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "jack.h" /* Holds card image structures */ #ifdef LATTICE int CXBRK(void) { return(0); } int chkabort(void) { return(0); } #endif /* Macros */ #define GAD_BUF(X) ((struct StringInfo *)X->SpecialInfo)->Buffer #define GAD_OFF(X) if (!(X->Flags & GFLG_DISABLED)) \ GT_SetGadgetAttrs(X,win,NULL,GA_Disabled,TRUE,TAG_END) #define GAD_ON(X) if (X->Flags & GFLG_DISABLED) \ GT_SetGadgetAttrs(X,win,NULL,GA_Disabled,FALSE,TAG_END) #define MASK 0x0F #define REQ_OK 0 #define REQ_ASK 1 /* Gadget IDs */ #define HIT_GAD 0 #define STICK_GAD 1 #define DD_GAD 2 #define SUR_GAD 3 #define DEAL_GAD 4 #define BET_GAD 5 #define MAX_CARDS 416 /* 8 decks */ #define A_DECK 52 /* 52 cards per deck */ #define BOX_WIDTH 146 /* decks gauge x-size */ #define BOX_HEIGHT 9 /* decks gauge y-size */ #define BOX_LEFT 179 /* decks gauge left edge */ #define BOX_TOP (114 + win_offset) #define P_ROW (4 + win_offset) #define D_ROW (66 + win_offset) #define COL_1 13 /* Col to put first card */ #define COL_2 74 /* Col to put second cards */ #define CARD_WIDTH 60 /* Pixels */ #define CARD_HEIGHT 40 /* Pixels */ #define PLAYER 0x0 /* An ID */ #define DEALER 0x1 /* An ID */ #define FIRST 0x2 /* Playing dealer's hole card */ #define BACK 0x3 /* Playing split card */ /* My function prototypes */ VOID openWindow(VOID); BOOL checkBet(VOID); VOID doIDCMP(VOID); VOID closer(VOID); VOID printBank(VOID); VOID gauge(VOID); VOID drawCard(struct Card *, UWORD, UWORD); VOID allocDeck(VOID); VOID shuffle(VOID); BOOL initDeal(VOID); VOID addScore(UBYTE, UBYTE *); VOID addCard(VOID); VOID printScore(VOID); VOID printWins(VOID); VOID dealsTurn(VOID); VOID wText(UBYTE *); VOID playBack(VOID); VOID openStatWin(VOID); VOID safeCloseWin(struct Window *); VOID refreshStatWin(VOID); VOID showStats(VOID); BOOL putReq(UBYTE *, UBYTE *, BYTE); UBYTE ver[] = {"$VER: Jack 2.1 (08.20.94"}; struct Card **deck = NULL, *hole_card, *backcard; UWORD dealt = 0, p_cord; UBYTE num_decks = 1, old_decks = 1, t_decks = 0; UBYTE p_score, p_score2, d_score; UBYTE p_crd[13], d_crd[13], p_hand[16], d_hand[16]; FLOAT bank = 100, betA = 10, betB = 0, ins = 0, bet_main = 10, win_p = 0; UBYTE win_offset; UWORD ySize, hands = 0, winners = 0; BOOL start_stats = FALSE, use_delay = TRUE; struct Window *win = NULL, *stat_win = NULL; struct Gadget *glist = NULL, *gads[6]; struct TextAttr Topaz80 = {"topaz.font", 8, 0, 0,}; struct TextFont *wFont = NULL; VOID *vi = NULL; struct Menu *strip; struct MsgPort *mport = NULL; /* *main() proccesses the args, opens the window, * and calls the IDCMP loop. */ main(int argc, char **argv) { /* If run from WB, SAS/C handles startup and sets these values */ if (!argc) { argc = _WBArgc; argv = _WBArgv; } /* Parse args */ while (--argc) { if (!strcmp("STATS", argv[argc])) start_stats = TRUE; else if (!strncmp("BANK=", argv[argc], 5)) { bank = atof(&argv[argc][5]); if (bank < 0.10) bank = 100.00; if (bank > (FLT_MAX / 2)) bank = 100; } else if (!strncmp("DECKS=", argv[argc], 6)) num_decks = old_decks = atoi(&argv[argc][6]); else if (!strcmp("NODELAY", argv[argc])) use_delay = FALSE; } openWindow(); doIDCMP(); closer(); } /* * Clean up routine that can be called at any point in the program. It * frees memory, closes the window, frees menus and gadgets, removes * the message port. */ VOID closer(VOID) { if (deck) FreeMem(deck, sizeof(struct Card *) * A_DECK * num_decks); if (strip) { ClearMenuStrip(win); FreeMenus(strip); } if (stat_win) safeCloseWin(stat_win); if (win) safeCloseWin(win); if (wFont) CloseFont(wFont); if (vi) FreeVisualInfo(vi); if (mport) DeletePort(mport); if (glist) FreeGadgets(glist); exit(0); } /* * Open the window with gadgets and menus. Note: the window has no IDCMP * flags set. This is done so that Intuition will not create a message * port for this window. doIDCMP() creates the port for this win. */ VOID openWindow(VOID) { struct NewMenu nm[] = { { NM_TITLE, "Game", 0,0,0,0,}, { NM_ITEM, "Decks", 0,0,0,0,}, { NM_SUB, "1", 0,CHECKIT,~1,0,}, { NM_SUB, "2", 0,CHECKIT,~2,0,}, { NM_SUB, "4", 0,CHECKIT,~4,0,}, { NM_SUB, "8", 0,CHECKIT,~8,0,}, { NM_ITEM, "Stats", 0,0,0,0,}, { NM_SUB, "On", 0,CHECKIT,~1,0,}, { NM_SUB, "Off", 0,CHECKIT,~2,0,}, { NM_ITEM, NM_BARLABEL, 0,0,0,0,}, { NM_ITEM, "Quit", 0,0,0,0,}, { NM_END, NULL, 0,0,0,0,}, }; struct Screen *scn; struct Gadget *gad; struct NewGadget ng; UWORD win_left; if (!(scn = LockPubScreen(NULL))) closer(); vi = GetVisualInfo(scn, TAG_END); win_offset = 1 + scn->WBorTop + scn->Font->ta_YSize; switch (num_decks ) { case 1: nm[2].nm_Flags |= CHECKED; break; case 2: nm[3].nm_Flags |= CHECKED; break; case 4: nm[4].nm_Flags |= CHECKED; break; case 8: nm[5].nm_Flags |= CHECKED; break; default: num_decks = old_decks = 1; nm[2].nm_Flags |= CHECKED; break; } if (start_stats) nm[7].nm_Flags |= CHECKED; else nm[8].nm_Flags |= CHECKED; gad = CreateContext(&glist); ng.ng_LeftEdge = 127; ng.ng_TopEdge = 113 + win_offset; ng.ng_Width = 49; ng.ng_Height = 13; ng.ng_GadgetText = "Hit"; ng.ng_TextAttr = &Topaz80; ng.ng_GadgetID = HIT_GAD; ng.ng_Flags = NULL; ng.ng_VisualInfo = vi; ng.ng_UserData = NULL; gads[HIT_GAD] = gad = CreateGadget(BUTTON_KIND, gad, &ng, GA_Disabled, TRUE, TAG_END); ng.ng_LeftEdge = 78; ng.ng_TopEdge = 126 + win_offset; ng.ng_GadgetText = "DD"; ng.ng_GadgetID = DD_GAD; gads[DD_GAD] = gad = CreateGadget(BUTTON_KIND, gad, &ng, GA_Disabled, TRUE, TAG_END); ng.ng_LeftEdge = 127; ng.ng_TopEdge = 126 + win_offset; ng.ng_GadgetText = "Stick"; ng.ng_GadgetID = STICK_GAD; gads[STICK_GAD] = gad = CreateGadget(BUTTON_KIND, gad, &ng, GA_Disabled, TRUE, TAG_END); ng.ng_LeftEdge = 78; ng.ng_TopEdge = 113 + win_offset; ng.ng_GadgetText = "Srndr"; ng.ng_GadgetID = SUR_GAD; gads[SUR_GAD] = gad = CreateGadget(BUTTON_KIND, gad, &ng, GA_Disabled, TRUE, TAG_END); ng.ng_TopEdge = 126 + win_offset; ng.ng_LeftEdge = 177; ng.ng_Width = 150; ng.ng_GadgetText = "Deal"; ng.ng_GadgetID = DEAL_GAD; gads[DEAL_GAD] = gad = CreateGadget(BUTTON_KIND, gad, &ng, TAG_END); ng.ng_LeftEdge = 227; ng.ng_TopEdge = 141 + win_offset; ng.ng_Width = 100; ng.ng_GadgetText = "Wager:"; ng.ng_Flags = PLACETEXT_LEFT; ng.ng_GadgetID = BET_GAD; gads[BET_GAD] = gad = CreateGadget(STRING_KIND, gad, &ng, STRINGA_Justification, GACT_STRINGRIGHT, GTST_String, "10.00", TAG_END); if (!start_stats) win_left = (scn->Width - 332) / 2; else win_left = (scn->Width - 462) / 2; if (win = OpenWindowTags(NULL, WA_Left, win_left, WA_Top, (scn->Height - (166 + win_offset)) / 2, WA_Width, 332, WA_Height, 166 + win_offset, WA_Activate, TRUE, WA_CloseGadget, TRUE, WA_DepthGadget, TRUE, WA_DragBar, TRUE, WA_Gadgets, glist, WA_IDCMP, NULL, WA_PubScreen, scn, WA_Title, "©1994 John Corigliano", WA_ScreenTitle, "Black Jack!", TAG_END)) { GT_RefreshWindow(win, NULL); /* Set the window font to "topaz.font", 8 */ wFont = OpenFont(&Topaz80); SetFont(win->RPort, wFont); ySize = win->IFont->tf_YSize; /* Attach menu strip */ strip = CreateMenus(nm, TAG_END); LayoutMenus(strip, vi, TAG_END); SetMenuStrip(win, strip); /* Use GadTools for beveled boxes */ DrawBevelBox(win->RPort, 5, 2 + win_offset, 322, 46, GT_VisualInfo, vi, GTBB_Recessed, TRUE, TAG_END); DrawBevelBox(win->RPort, 5, 50 + win_offset, 322, 12, GT_VisualInfo, vi, GTBB_Recessed, TRUE, TAG_END); DrawBevelBox(win->RPort, 5, 64 + win_offset, 322, 46, GT_VisualInfo, vi, GTBB_Recessed, TRUE, TAG_END); DrawBevelBox(win->RPort, 5, 113 + win_offset, 70, 26, GT_VisualInfo, vi, GTBB_Recessed, TRUE, TAG_END); DrawBevelBox(win->RPort, 177, 113 + win_offset, 150, 12, GT_VisualInfo, vi, GTBB_Recessed, TRUE, TAG_END); SetAPen(win->RPort, 1); Move(win->RPort, 10, 123 + win_offset); Text(win->RPort, "You:", 4); Move(win->RPort, 10, 133 + win_offset); Text(win->RPort, "Deal:", 5); printBank(); printWins(); } UnlockPubScreen(NULL, scn); if (!win) closer(); return; } /* * Checks to make sure bet is in the proper format (i.e 1.00) * Also makes sure that the player can cover the bet */ BOOL checkBet(VOID) { UBYTE bet_str[32], str[32], i; BOOL format = FALSE; strcpy(bet_str, GAD_BUF(gads[BET_GAD])); if (strlen(bet_str) < 3) format = TRUE; if (!format) { for (i = 0; i < (strlen(bet_str) - 3); i++) if (!(isdigit(bet_str[i]))) format = TRUE; if (bet_str[i++] != '.') format = TRUE; if (!(isdigit(bet_str[i++]))) format = TRUE; if (!(isdigit(bet_str[i]))) format = TRUE; } if (format) { DisplayBeep(win->WScreen); sprintf(str, "Bad format: %s", bet_str); wText(str); bet_main = betA = 0; ActivateGadget(gads[BET_GAD], win, NULL); return(FALSE); } bet_main = betA = atof(bet_str); return(TRUE); } /* * Main message processing loop. Note: it creates a message port for the * two windows to share. This way the program can have two windows open * but only checks for messages at one message port! */ VOID doIDCMP(VOID) { struct IntuiMessage *imsg; struct Gadget *work = NULL; struct Window *temp_win; struct MenuItem *item; BOOL done = FALSE, inp = FALSE; UWORD mnum, inum, snum, code; ULONG class; allocDeck(); /* Create a message port and attatch it to the window */ if (!(mport = CreatePort(0,0))) closer(); win->UserPort = mport; ModifyIDCMP(win,IDCMP_GADGETUP|IDCMP_MENUPICK|IDCMP_CLOSEWINDOW); if (start_stats) openStatWin(); while (!done) { Wait(1L << mport->mp_SigBit); while (imsg = GT_GetIMsg(win->UserPort)) { class = imsg->Class; code = imsg->Code; temp_win = imsg->IDCMPWindow; /* Which window? */ if (class == IDCMP_GADGETUP) work = (struct Gadget *)imsg->IAddress; GT_ReplyIMsg(imsg); if (class == IDCMP_REFRESHWINDOW) if (stat_win) { refreshStatWin(); showStats(); } if (class == IDCMP_CLOSEWINDOW) { if (temp_win == win) done = TRUE; else { safeCloseWin(stat_win); stat_win = NULL; Forbid(); ClearMenuStrip(win); item = strip->FirstItem->NextItem->SubItem; item->Flags &= ~CHECKED; item->NextItem->Flags |= CHECKED; ResetMenuStrip(win, strip); Permit(); } } else if (class == IDCMP_GADGETUP) { wText("Okay..."); if ((work->GadgetID == DEAL_GAD) && checkBet()){ if ((bank == 0) && (putReq("Your broke!","Want a $100 loan?",REQ_ASK))) { bank = 100; printBank(); } else if ((betA > 0) && (betA <= bank)) { bank -= betA; printBank(); if (dealt > ((num_decks * A_DECK) - 15)) shuffle(); if (initDeal()) { if (p_score < 21) { GAD_OFF(gads[DEAL_GAD]); GAD_OFF(gads[BET_GAD]); GAD_ON(gads[HIT_GAD]); GAD_ON(gads[STICK_GAD]); if ((bank >= (betA / 2)) && !backcard) GAD_ON(gads[SUR_GAD]); if (bank >= betA) GAD_ON(gads[DD_GAD]); inp = TRUE; } else dealsTurn(); } } else if (betA <= 0) { DisplayBeep(win->WScreen); wText("You must make a bet first!!"); } else { DisplayBeep(win->WScreen); wText("You don't have enough money."); } } else if (work->GadgetID == BET_GAD) checkBet(); else if (work->GadgetID == HIT_GAD) { GAD_OFF(gads[DD_GAD]); GAD_OFF(gads[SUR_GAD]); addCard(); if (p_score >= 21) { if (backcard) { putReq("Ready for", "second hand...", REQ_OK); playBack(); } else { GAD_OFF(gads[HIT_GAD]); GAD_OFF(gads[STICK_GAD]); dealsTurn(); inp = FALSE; } } } else if (work->GadgetID == STICK_GAD) { if (backcard) playBack(); else { GAD_OFF(gads[DD_GAD]); GAD_OFF(gads[SUR_GAD]); GAD_OFF(gads[HIT_GAD]); GAD_OFF(gads[STICK_GAD]); dealsTurn(); inp = FALSE; } } else if (work->GadgetID == SUR_GAD) { bank -= betA / 2; printBank(); p_hand[0] = p_hand[1] = p_score = 0; p_cord = COL_2 + CARD_WIDTH + 1; drawCard(deck[dealt], COL_1, P_ROW); addScore(PLAYER, p_hand); drawCard(deck[dealt], COL_2, P_ROW); addScore(PLAYER, p_hand); if (p_score == 21) { p_score = 0xFE; GAD_OFF(gads[DD_GAD]); GAD_OFF(gads[SUR_GAD]); GAD_OFF(gads[HIT_GAD]); GAD_OFF(gads[STICK_GAD]); dealsTurn(); } else { if (bank < (betA / 2)) GAD_OFF(gads[SUR_GAD]); if (bank < betA) GAD_OFF(gads[DD_GAD]); } } else if(work->GadgetID == DD_GAD) { GAD_OFF(gads[DD_GAD]); GAD_OFF(gads[SUR_GAD]); bank -= betA; betA += betA; printBank(); addCard(); if (backcard) { putReq("Ready for", "second hand...", REQ_OK); playBack(); } else { GAD_OFF(gads[HIT_GAD]); GAD_OFF(gads[STICK_GAD]); dealsTurn(); inp = FALSE; } } if (stat_win) showStats(); } else if (class == IDCMP_MENUPICK) { mnum = MENUNUM(code); inum = ITEMNUM(code); snum = SUBNUM(code); if (mnum == 0) { if (!inum) { t_decks = 1 << snum; if (t_decks == num_decks) t_decks = 0; else if (!inp) { num_decks = t_decks; t_decks = 0; allocDeck(); } } else if (inum == 1) { if (!snum) { if (!stat_win) openStatWin(); } else { if (stat_win) { safeCloseWin(stat_win); stat_win = NULL; } } } else if (inum == 3) done = TRUE; } } } } return; } /* * Simply prints the players bank */ VOID printBank(VOID) { UBYTE st[] = {" "}; /* Use floating point notation? */ if (bank > 9999999999999.99) sprintf(st, "Bank: $%-11.2e", bank); else sprintf(st, "Bank: $%-13.2f", bank); st[strlen(st)] = 32; SetAPen(win->RPort, 1); Move(win->RPort, 10, 150 + win_offset); Text(win->RPort, st, 19); return; } /* * Prints players win percentage */ VOID printWins(VOID) { UBYTE str[] = {" "}; UBYTE perc = 0; if (hands) perc = 100 * ((FLOAT)winners / (FLOAT)hands); sprintf(str, "Wins: %d/%d = %d%%", winners, hands, perc); str[strlen(str)] = 32; Move(win->RPort, 10, 160 + win_offset); Text(win->RPort, str, 29); } /* * Updates the decks gauge to refect the amount of cards dealt. */ VOID gauge(VOID) { LONG offset; FLOAT per; per = ((FLOAT)dealt + 1) / ((FLOAT)num_decks * A_DECK); if (dealt == 0) { SetAPen(win->RPort, 3); RectFill(win->RPort, BOX_LEFT, BOX_TOP, BOX_LEFT + BOX_WIDTH, BOX_TOP + BOX_HEIGHT); DrawBevelBox(win->RPort, BOX_LEFT, BOX_TOP, BOX_WIDTH + 1, BOX_HEIGHT + 1, GT_VisualInfo, vi, TAG_DONE); return; } offset = BOX_WIDTH - ((LONG)(per * BOX_WIDTH)); SetAPen(win->RPort, 0); RectFill(win->RPort, BOX_LEFT + offset + 1, BOX_TOP, BOX_LEFT + BOX_WIDTH, BOX_TOP + BOX_HEIGHT); SetAPen(win->RPort, 1); Move(win->RPort, BOX_LEFT + offset - 1, BOX_TOP + 1); Draw(win->RPort, BOX_LEFT + offset - 1, BOX_TOP + BOX_HEIGHT); Move(win->RPort, BOX_LEFT + offset, BOX_TOP); Draw(win->RPort, BOX_LEFT + offset, BOX_TOP + BOX_HEIGHT); return; } /* * Draws a card at x, y (see "jack.h" for the declaration of the Card * structure and the Image structures). */ VOID drawCard(struct Card *c, UWORD x, UWORD y) { UBYTE ct; struct Image *suit; if (c->Flags & HEARTS) suit = &heart; else if (c->Flags & DIAMONDS) suit = ⋄ else if (c->Flags & SPADES) suit = &spade; else suit = &club; SetAPen(win->RPort, 2); RectFill(win->RPort, x, y, x+CARD_WIDTH, y+CARD_HEIGHT); if ((c->Flags & SPADES) || (c->Flags & CLUBS)) SetAPen(win->RPort, 1); else SetAPen(win->RPort, 3); SetBPen(win->RPort, 2); /* Draw the card ID - "2", "3", "4", etc. */ Move(win->RPort, x+1, y+ySize-2); if (strlen(c->Name) != 2) { Text(win->RPort, c->Name, 1); Move(win->RPort, x+52, y+(CARD_HEIGHT-ySize)+7); Text(win->RPort, c->Name, 1); } else { Text(win->RPort, c->Name, 2); Move(win->RPort, x+44, y+(CARD_HEIGHT-ySize)+7); Text(win->RPort, c->Name, 2); } /* Draw the suits and face cards (if needed) */ if (c->Face) { DrawImage(win->RPort, suit, x+11, y+1); DrawImage(win->RPort, c->Face, x+c->Cords[0],y+c->Cords[1]); DrawImage(win->RPort, suit, x+40, y+32); } else { for (ct = 0; ct < ((c->Flags & 0xF) * 2); ct += 2) DrawImage(win->RPort, suit, x+c->Cords[ct],y+c->Cords[ct+1]); } SetAPen(win->RPort, 1); Move(win->RPort, x, y); Draw(win->RPort, x+CARD_WIDTH, y); Draw(win->RPort, x+CARD_WIDTH, y+CARD_HEIGHT); Draw(win->RPort, x, y+CARD_HEIGHT); Draw(win->RPort, x, y); gauge(); SetBPen(win->RPort, 0); if (use_delay) Delay(5); return; } /* * Allocates memory for the deck. Also, frees memory if the deck already * existed. */ VOID allocDeck(VOID) { SetAPen(win->RPort, 0); RectFill(win->RPort, COL_1, P_ROW, 324, P_ROW + CARD_HEIGHT); RectFill(win->RPort, COL_1, D_ROW, 324, D_ROW + CARD_HEIGHT); if (deck) FreeMem(deck, sizeof(struct Card *) * A_DECK * old_decks); deck = AllocMem(sizeof(struct Card *) * A_DECK * num_decks, MEMF_ANY | MEMF_CLEAR); old_decks = num_decks; shuffle(); return; } /* * This routine is called when a fresh deal is needed. It deals the first * four cards, checks for Black Jacks and possible splits and insurance * bets. */ BOOL initDeal(VOID) { UBYTE s[32], t1; /* Initialize data */ betB = ins = p_score = d_score = p_score2 = 0; p_cord = COL_2 + CARD_WIDTH + 1; backcard = NULL; for (t1 = 0; t1 < 16; t1++) p_hand[t1] = d_hand[t1] = 0; /* Erase old cards */ SetAPen(win->RPort, 0); RectFill(win->RPort, COL_1, P_ROW, 324, P_ROW + CARD_HEIGHT); RectFill(win->RPort, COL_1, D_ROW, 324, D_ROW + CARD_HEIGHT); drawCard(deck[dealt], COL_1, P_ROW); addScore(PLAYER, p_hand); drawCard(deck[dealt], COL_1, D_ROW); addScore(DEALER, d_hand); drawCard(deck[dealt], COL_2, P_ROW); addScore(PLAYER, p_hand); if (p_score == 21) p_score = 0xFE; /* Dealer has an Ace */ if ((d_hand[0] == 1) && (p_score != 0xFE) && (bank >= (betA / 2))) { if (putReq("Would you like", "an Insurance bet?", REQ_ASK)) { ins = betA / 2; bank -= ins; printBank(); if (ins > 9999999999999.99) sprintf(s, "Insurance bet = $%11.2e", ins); else sprintf(s, "Insurance bet = $%.2f", ins); wText(s); } } DrawImage(win->RPort, &hole, COL_2, D_ROW); hole_card = deck[dealt++]; /* Dealer has Black Jack */ if ((((hole_card->Flags & MASK) == 0x1) && (d_score == 10)) || (((hole_card->Flags & MASK) > 0x9) && (d_score == 11))) { drawCard(hole_card, COL_2, D_ROW); addScore(FIRST, d_hand); d_score = 0xFE; printScore(); if (ins) bank += ins * 3; if (p_score == 0xFE) { wText("We both have Black Jack!"); bank += betA; } else { if (ins) wText("At least you won the insurance!"); else wText("Black Jack! You lose!!"); } printBank(); hands++; printWins(); return(FALSE); } /* Player can split */ if ((deck[dealt-2]->Flags & MASK) == (deck[dealt-4]->Flags & MASK)) { if (bank >= betA) { if (putReq("Do you", "want to Split?", REQ_ASK)) { backcard = deck[dealt-2]; if (p_hand[1] == 1) p_score -= 11; else p_score -= p_hand[1]; p_hand[1] = 0; printScore(); drawCard(deck[dealt], COL_2, P_ROW); addScore(PLAYER, p_hand); bank -= betA; printBank(); GAD_OFF(gads[SUR_GAD]); wText("Playing first hand..."); if (p_score == 21) { p_score = 0xFE; putReq("First hand is", "a Black Jack!", REQ_OK); playBack(); if (p_score == 0xFE) return(FALSE); /* 2 BJacks! */ } } } } return(TRUE); } /* * Deciphers the point value of a card from its Flags. */ VOID addScore(UBYTE who, UBYTE *array) { UBYTE score, i, hard = 0, aces = 0; if (who == FIRST) score = hole_card->Flags & MASK; else if (who == BACK) score = backcard->Flags & MASK; else score = deck[dealt]->Flags & MASK; if (score == 0x1) { aces++; if (who == PLAYER) p_crd[12]++; else if (who != BACK) d_crd[12]++; } else { if (who == PLAYER) p_crd[score - 2]++; else if (who != BACK) d_crd[score - 2]++; } if (score > 0x9) score = 0xA; for (i = 0; i < 16; i++) { if (array[i] == 0) break; if (array[i] != 1) hard += array[i]; else { hard += 11; aces++; } } array[i] = score; if (score == 1) hard += 11; else hard += score; for (i = 0; i < aces; i++) { if (hard <= 21) break; else hard -= 10; } if (who == PLAYER) p_score = hard; else if (who != BACK) d_score = hard; if ((who != FIRST) && (who != BACK)) dealt++; printScore(); return; } /* * The player wants another card */ VOID addCard(VOID) { drawCard(deck[dealt], p_cord, P_ROW); addScore(PLAYER, p_hand); if (p_cord >= 254) p_cord -= 225; else p_cord += 61; return; } /* * Prints both scores. If score == 0xFE its a Black Jack */ VOID printScore(VOID) { UBYTE s1[3], s2[3]; if (p_score == 0xFE) strcpy(s1, "BJ"); else sprintf(s1, "%2d", p_score); if (d_score == 0xFE) strcpy(s2, "BJ"); else sprintf(s2, "%2d", d_score); SetAPen(win->RPort, 2); Move(win->RPort, 50, 123 + win_offset); Text(win->RPort, s1, 2); Move(win->RPort, 50, 133 + win_offset); Text(win->RPort, s2, 2); return; } /* * The dealer takes his cards and determines the winner and payoffs */ VOID dealsTurn(VOID) { UWORD d_cord; BOOL okay = TRUE; BYTE h1 = 0, h2 = 0, say[32], *res[] = {"Won", "Lost", "Push"}; d_cord = COL_2 + CARD_WIDTH + 1; drawCard(hole_card, COL_2, D_ROW); addScore(FIRST, d_hand); if (d_score >= 17) okay = FALSE; while (okay) { drawCard(deck[dealt], d_cord, D_ROW); addScore(DEALER, d_hand); if (d_cord >= 254) d_cord -= 225; else d_cord += 61; if (d_score >= 17) okay = FALSE; } if (p_score == 0xFE) { /* Black Jack */ bank += betA * 2.5; p_score = 21; wText("You win with Black Jack!!"); winners++; } else if (p_score > 21) { /* Player tap */ wText("You've tapped out."); h1 = 1; } else if (d_score > 21) { /* Dealer Tap */ bank += betA * 2; wText("Dealer tapped - You win!"); winners++; } else if (p_score == d_score) { /* Push */ bank += betA; wText("It's a Push - No winners"); h1 = 2; } else if (p_score > d_score) { /* Winner */ bank += betA * 2; wText("You win!!"); winners++; } else { /* d_score > p_score */ wText("The Dealer wins."); h1 = 1; } if (p_score2) { /* Player split */ hands++; if (p_score2 == 0xFE) { /* Black Jack */ bank += betB * 2.5; p_score2 = 21; winners++; } else if (p_score2 > 21) /* Player tap */ h2 = 1; else if (d_score > 21) { /* Dealer tap */ bank += betB * 2; winners++; } else if (p_score2 == d_score) { /* Push */ h2 = 2; bank += betB; } else if (p_score2 > d_score) { /* Player wins */ bank += betB * 2; winners++; } else /* Player tap and */ h2 = 1; /* d_score > p_score2 */ sprintf(say, "%s: %d <> %s: %d", res[h2],p_score2,res[h1],p_score); wText(say); } printBank(); hands++; printWins(); if (t_decks) { /* Check to see if player changed the */ num_decks = t_decks; /* number od decks while the hand was */ t_decks = 0; /* in progress. */ allocDeck(); } GAD_ON(gads[BET_GAD]); GAD_ON(gads[DEAL_GAD]); return; } /* * Centers a string and prints it */ VOID wText(UBYTE *s) { UBYTE len; UWORD offs; struct TextExtent texex; len = strlen(s); SetAPen(win->RPort,0); RectFill(win->RPort, 7, 51 + win_offset, 323, 60 + win_offset); SetAPen(win->RPort, 1); Move(win->RPort, 0, 0); TextExtent(win->RPort, s, len, &texex); offs = 5 + ((322 - texex.te_Extent.MaxX) / 2); Move(win->RPort, offs, 58 + win_offset); Text(win->RPort, s, len); return; } /* * The player has 'Split' */ VOID playBack(VOID) { UBYTE i; p_cord = COL_2 + CARD_WIDTH; SetAPen(win->RPort, 0); RectFill(win->RPort, COL_1, P_ROW, 324, P_ROW + CARD_HEIGHT); GAD_ON(gads[DD_GAD]); GAD_OFF(gads[SUR_GAD]); p_score2 = p_score; p_score = 0; betB = betA; betA = bet_main; for (i = 0; i < 16; i++) p_hand[i] = 0; wText("Playing second hand, now..."); drawCard(backcard, COL_1, P_ROW); addScore(BACK, p_hand); drawCard(deck[dealt], COL_2, P_ROW); addScore(PLAYER, p_hand); backcard = NULL; if (p_score == 21) { p_score = 0xFE; GAD_OFF(gads[DD_GAD]); GAD_OFF(gads[HIT_GAD]); GAD_OFF(gads[STICK_GAD]); dealsTurn(); } return; } /* * Open the Statistics window */ VOID openStatWin(VOID) { UWORD xwin; WORD wzoom[] = {0,0,130,0}; if ((win->LeftEdge + 332) > (win->WScreen->Width - 130)) xwin = win->LeftEdge - 130; else xwin = win->LeftEdge + 332; wzoom[0] = xwin; wzoom[1] = win->TopEdge; wzoom[3] = win_offset; if (!(stat_win = OpenWindowTags(NULL, WA_Left, xwin, WA_Top, win->TopEdge, WA_Width, 130, WA_Height, 166 + win_offset, WA_CloseGadget, TRUE, WA_DepthGadget, TRUE, WA_Zoom, wzoom, WA_DragBar, TRUE, WA_IDCMP, NULL, WA_SmartRefresh,TRUE, WA_RMBTrap, TRUE, WA_PubScreen, win->WScreen, WA_ScreenTitle, win->ScreenTitle, WA_Title, "Stats", TAG_END))) return; if (wFont) SetFont(stat_win->RPort, wFont); stat_win->UserPort = mport; ModifyIDCMP(stat_win, IDCMP_CLOSEWINDOW|IDCMP_REFRESHWINDOW); refreshStatWin(); showStats(); return; } /* * Since the two windows share an IDCMP port, must make sure that there * are no more messages for that window before trying to close it. */ VOID safeCloseWin(struct Window *w) { struct IntuiMessage *msg; struct Node *succ; Forbid(); msg = (struct IntuiMessage *)mport->mp_MsgList.lh_Head; while(succ = msg->ExecMessage.mn_Node.ln_Succ) { if (msg->IDCMPWindow == w) { Remove((struct Node *)msg); ReplyMsg((struct Message *)msg); } msg = (struct IntuiMessage *)succ; } w->UserPort = NULL; ModifyIDCMP(w, NULL); Permit(); CloseWindow(w); return; } /* * Redraw the Statistics window graphics */ VOID refreshStatWin(VOID) { static UBYTE *sc[] = { " 2", " 3", " 4", " 5", " 6", " 7", " 8", " 9", "10", " J", " Q", " K", " A" }; static UBYTE title[] = {" P D %"}; UBYTE row = 22, col = 7, x; if (!stat_win) return; SetAPen(stat_win->RPort, 3); RectFill(stat_win->RPort, 4, win_offset, 125, 162 + win_offset); SetAPen(stat_win->RPort, 0); RectFill(stat_win->RPort, 28, 13 + win_offset, 117, 146 + win_offset); DrawBevelBox(stat_win->RPort, 28, 13 + win_offset, 89 + 1, 133 + 1, GT_VisualInfo, vi, TAG_END); SetAPen(stat_win->RPort, 1); SetDrMd(stat_win->RPort, JAM1); Move(stat_win->RPort, 6, 9 + win_offset); Text(stat_win->RPort, title, 13); SetAPen(stat_win->RPort, 2); Move(stat_win->RPort, 4, 8 + win_offset); Text(stat_win->RPort, title, 13); SetAPen(stat_win->RPort, 1); for (x = 0; x < 13; x++) { Move(stat_win->RPort, col, row + win_offset); Text(stat_win->RPort, sc[x], 2); row += 10; } row = 21; col = 5; SetAPen(stat_win->RPort, 2); for (x = 0; x < 13; x++) { Move(stat_win->RPort, col, row + win_offset); Text(stat_win->RPort, sc[x], 2); row += 10; } SetDrMd(stat_win->RPort, JAM2); return; } /* * My own version of EasyRequest(). I use Nico François' RT_Patch - it * puts all system requesters at the pointer. I am emulating that * here for people who don't have RT_Patch */ BOOL putReq(UBYTE *stra, UBYTE *strb, BYTE flag) { struct IntuiMessage *im; struct Window *req_win; BOOL done = FALSE, ans; WORD le, te, gl, offa, offb, lena, lenb, left_off = 100; struct Gadget *rgad, *rlist; struct NewGadget rng; struct Requester req; struct TextExtent texe; gl = (flag) ? 10 : 51; rgad = CreateContext(&rlist); rng.ng_LeftEdge = gl; rng.ng_TopEdge = 28 + win_offset; rng.ng_Width = 80; rng.ng_Height = 14; rng.ng_GadgetText = "Okay"; rng.ng_TextAttr = &Topaz80; rng.ng_GadgetID = 1; rng.ng_Flags = NULL; rng.ng_VisualInfo = vi; rng.ng_UserData = NULL; rgad = CreateGadget(BUTTON_KIND, rgad, &rng, TAG_END); if (flag) { left_off = 137; rng.ng_LeftEdge = 95; rng.ng_GadgetText = "Cancel"; rng.ng_GadgetID = 0; rgad = CreateGadget(BUTTON_KIND, rgad, &rng, TAG_END); } InitRequester(&req); Request(&req, win); le = ((win->MouseX + win->LeftEdge) < left_off) ? 0 : (win->MouseX + win->LeftEdge - left_off); te = ((win->MouseY + win->TopEdge) < 47) ? 0 : (win->MouseY + win->TopEdge - 47); if (req_win = OpenWindowTags(NULL, WA_Left, le, WA_Top, te, WA_Width, 182, WA_Height, 45 + win_offset, WA_Gadgets, rlist, WA_IDCMP, IDCMP_GADGETUP, WA_DepthGadget, TRUE, WA_DragBar, TRUE, WA_Activate, TRUE, WA_RMBTrap, TRUE, WA_Title, "Jack Note:", WA_ScreenTitle, win->ScreenTitle, WA_PubScreen, win->WScreen, TAG_END)) { if (wFont) SetFont(req_win->RPort, wFont); DrawBevelBox(req_win->RPort, 9, 2 + win_offset, 166, 10 + win_offset, GT_VisualInfo, vi, GTBB_Recessed, TRUE, TAG_END); lena = strlen(stra); lenb = strlen(strb); SetAPen(req_win->RPort, 1); Move(req_win->RPort, 0, 0); TextExtent(req_win->RPort, stra, lena, &texe); offa = (182 - texe.te_Extent.MaxX) / 2; Move(req_win->RPort, offa, 11 + win_offset); Text(req_win->RPort, stra, lena); Move(req_win->RPort, 0, 0); TextExtent(req_win->RPort, strb, lenb, &texe); offb = (182 - texe.te_Extent.MaxX) / 2; Move(req_win->RPort, offb, 20 + win_offset); Text(req_win->RPort, strb, lenb); while (!done) { Wait(1L << req_win->UserPort->mp_SigBit); while (im = (struct IntuiMessage *)GetMsg(req_win->UserPort)) { if (im->Class == IDCMP_GADGETUP) { ans = ((struct Gadget *)im->IAddress)->GadgetID; done = TRUE; } ReplyMsg((struct Message *)im); } } CloseWindow(req_win); } FreeGadgets(rlist); EndRequest(&req, win); return(ans); }