This is Baccarat.m in view mode; [Download] [Up]
#import "Baccarat.h" #define BCT_NUMDECKS 8 #define BCT_BANKERHAND 0 #define BCT_PLAYERHAND 1 #define BCT_PLAYERVIEW 0 #define BCT_BANKVIEW 1 #define BCT_TIEVIEW 2 #define BCT_DRAWPAUSE 200000 #define BCT_LONGPAUSE 999999 #define BCT_MAXPLAYERS 4 #define BCT_PLAYERTAG 0 #define BCT_TIETAG 10 #define BCT_BANKTAG 20 #define BCT_NAMEFORDEFAULTS "NVBaccarat" void BCT_RunGame(DPSTimedEntry teNumber, double now, void *userData) { id obj = (id)userData; [obj runGame]; } @implementation Baccarat /*************************************************************************************** * Module Methods * ***************************************************************************************/ + initialize { static NXDefaultsVector ourDefaults = { {"numDecks", "8"}, {NULL, NULL} }; NXRegisterDefaults(BCT_NAMEFORDEFAULTS, ourDefaults); return self; } - awakeFromNib /* Sent to every object instantiated in a nib file. A good place to perform some initialization... */ { int i; // This may take a while, so lets inform the user [self say:"Pre-Drawing Cards..."]; NXPing(); [Card drawCardImages]; player[0].tieView = p1TieView; player[1].tieView = p2TieView; player[2].tieView = p3TieView; player[3].tieView = p4TieView; player[0].bankView = p1BankerView; player[1].bankView = p2BankerView; player[2].bankView = p3BankerView; player[3].bankView = p4BankerView; player[0].playerView = p1PlayerView; player[1].playerView = p2PlayerView; player[2].playerView = p3PlayerView; player[3].playerView = p4PlayerView; player[0].nameText = p1NameText; player[1].nameText = p2NameText; player[2].nameText = p3NameText; player[3].nameText = p4NameText; pile[BCT_BANKERHAND].view = bankerCardView; [[[bankerCardView setOffset:60.0 :0.0] setCoversOthers:YES] setDrawOutline:NO]; pile[BCT_BANKERHAND].pile = [bankerCardView cardPile]; pile[BCT_BANKERHAND].text = bankerTotalText; pile[BCT_BANKERHAND].title = "Banker"; pile[BCT_PLAYERHAND].view = playerCardView; [[[playerCardView setOffset:60.0 :0.0] setCoversOthers:YES] setDrawOutline:NO]; pile[BCT_PLAYERHAND].pile = [playerCardView cardPile]; pile[BCT_PLAYERHAND].text = playerTotalText; pile[BCT_PLAYERHAND].title = "Player"; for(i=0; i<BCT_MAXPLAYERS; i++) { [[[[[[[[player[i].tieView setNumRows:1] setNumCols:1] positionChips] setSoundEnabled:YES] setEnabled:YES] setPayoff:9 cost:1] setTag:i+BCT_TIETAG] setViewType:BCT_TIEVIEW]; [[[[[[[player[i].bankView setNumRows:1] setNumCols:1] positionChips] setSoundEnabled:YES] setEnabled:YES] setTag:i+BCT_BANKTAG] setViewType:BCT_BANKVIEW]; [[[[[[[player[i].playerView setNumRows:1] setNumCols:1] positionChips] setSoundEnabled:YES] setEnabled:YES] setTag:i+BCT_PLAYERTAG] setViewType:BCT_PLAYERVIEW]; } [self revertPreferences:self]; deckPile = [deckView cardPile]; [deckView setUseShoe:YES]; [bankerText setStringValue:""]; [playerText setStringValue:""]; [self checkPiles]; [self getPlayers]; [self enableDealButton]; return self; } - (BOOL)checkBets { int i, tmax = [self tableMax], tmin = [self tableMin], amount; char buf[256]; for(i=0; i<BCT_MAXPLAYERS; i++) { amount = [player[i].tieView amountAtRow:0 col:0]; if(amount > tmax) { sprintf(buf, "%s, your $%d bet on TIE is over the $%d table maximum!", [player[i].player playerName], amount, tmax); [self say:buf]; NXPing(); [PBoss() playSound:NV_WARNSOUND]; return NO; } if(amount > 0 && amount < tmin) { sprintf(buf, "%s, your $%d bet on TIE is under the $%d table minimum!", [player[i].player playerName], amount, tmin); [self say:buf]; NXPing(); [PBoss() playSound:NV_WARNSOUND]; return NO; } amount = [player[i].bankView amountAtRow:0 col:0]; if(amount > tmax) { sprintf(buf, "%s, your $%d bet on BANKER is over the $%d table maximum!", [player[i].player playerName], amount, tmax); [self say:buf]; NXPing(); [PBoss() playSound:NV_WARNSOUND]; return NO; } if(amount > 0 && amount < tmin) { sprintf(buf, "%s, your $%d bet on BANKER is under the $%d table minimum!", [player[i].player playerName], amount, tmin); [self say:buf]; NXPing(); [PBoss() playSound:NV_WARNSOUND]; return NO; } amount = [player[i].playerView amountAtRow:0 col:0]; if(amount > tmax) { sprintf(buf, "%s, your $%d bet on PLAYER is over the $%d table maximum!", [player[i].player playerName], amount, tmax); [self say:buf]; NXPing(); [PBoss() playSound:NV_WARNSOUND]; return NO; } if(amount > 0 && amount < tmin) { sprintf(buf, "%s, your $%d bet on PLAYER is under the $%d table minimum!", [player[i].player playerName], amount, tmin); [self say:buf]; NXPing(); [PBoss() playSound:NV_WARNSOUND]; return NO; } } return YES; } - checkPiles { if([deckPile cardCount] < 10) { [self newDeck:self]; } [pile[BCT_BANKERHAND].pile empty]; [pile[BCT_BANKERHAND].view display]; [pile[BCT_BANKERHAND].text setIntValue:0]; [pile[BCT_PLAYERHAND].pile empty]; [pile[BCT_PLAYERHAND].view display]; [pile[BCT_PLAYERHAND].text setIntValue:0]; NXPing(); return self; } - deal:sender { if(dealTE) DPSRemoveTimedEntry(dealTE); if([self checkBets]) { [dealButton setEnabled:NO]; dealTE = DPSAddTimedEntry(.1, (DPSTimedEntryProc)BCT_RunGame, self, NX_BASETHRESHOLD); } return self; } - dealCardToHand:(int)hand { id card; char buf[128]; sprintf(buf, "Card For %s...", pile[hand].title); [self say:buf]; NXPing(); usleep(BCT_DRAWPAUSE); card = [deckPile cardAt:CS_TOP]; [card setFaceUp:YES]; [pile[hand].pile addCard:card]; [deckPile removeCard:card]; [deckView display]; [pile[hand].view display]; [self totalHand:hand]; NXPing(); [PBoss() playSound:NV_CARDSOUND]; usleep(BCT_DRAWPAUSE); return self; } - enableDealButton { int i; for(i=0; i<BCT_MAXPLAYERS; i++) { if([player[i].bankView amountAtRow:0 col:0] || [player[i].playerView amountAtRow:0 col:0] || [player[i].tieView amountAtRow:0 col:0]) { [dealButton setEnabled:YES]; return self; } } [dealButton setEnabled:NO]; return self; } - getPlayers { int i; id thePlayer; for(i=0; i<BCT_MAXPLAYERS; i++) { if((thePlayer = [PBoss() playerAt:i]) != nil) { [player[i].nameText setStringValue:[thePlayer playerName]]; player[i].player = thePlayer; } else { [player[i].nameText setStringValue:""]; player[i].player = nil; } } return self; } - newDeck:sender { id theMatrix, card; int numDecks, i; theMatrix = [[deckPrefButton target] itemList]; numDecks = [[theMatrix selectedCell] tag]; if(numDecks == 0) numDecks = 1; [self newDeck:numDecks forView:deckView]; for(i=0; i<[deckPile cardCount]; i++) { card = [deckPile cardAt:i]; switch([card value]) { case CS_TEN: [card setUserValue:0]; break; case CS_JACK: [card setUserValue:0]; break; case CS_QUEEN: [card setUserValue:0]; break; case CS_KING: [card setUserValue:0]; break; default: [card setUserValue:[card value]+1]; break; } } return self; } - runGame { int ptotal, btotal, pthirdCard=-1, i; BOOL playerDrewThird=NO; DPSRemoveTimedEntry(dealTE); dealTE=0; [bankerText setStringValue:""]; [playerText setStringValue:""]; // reset piles, initialize deck if needed... [self checkPiles]; // Deal two cards to each hand [self dealCardToHand:BCT_PLAYERHAND]; [self dealCardToHand:BCT_BANKERHAND]; [self dealCardToHand:BCT_PLAYERHAND]; [self dealCardToHand:BCT_BANKERHAND]; // Get the total for each hand ptotal = pile[BCT_PLAYERHAND].total; btotal = pile[BCT_BANKERHAND].total; // See if player needs third card if(btotal != 8 && btotal != 9) { if(ptotal==1 || ptotal==2 || ptotal==3 || ptotal==4 || ptotal==5 || ptotal==0) { [self dealCardToHand:BCT_PLAYERHAND]; playerDrewThird = YES; pthirdCard = [[pile[BCT_PLAYERHAND].pile cardAt:CS_TOP] userValue]; } } // See if banker needs third card if(ptotal != 8 && ptotal != 9) { if(btotal==0 || btotal==1 || btotal==2) { [self dealCardToHand:BCT_BANKERHAND]; } else if(btotal==3 || btotal==4 || btotal==5 || btotal==6) { switch(btotal) { case 3: if(!playerDrewThird || pthirdCard != 8) { [self dealCardToHand:BCT_BANKERHAND]; } break; case 4: if(!playerDrewThird || (pthirdCard != 0 && pthirdCard != 1 && pthirdCard != 8 && pthirdCard != 9)) { [self dealCardToHand:BCT_BANKERHAND]; } break; case 5: if(!playerDrewThird || (pthirdCard != 0 && pthirdCard != 1 && pthirdCard != 2 && pthirdCard != 3 && pthirdCard != 8 && pthirdCard != 9)) { [self dealCardToHand:BCT_BANKERHAND]; } break; case 6: if(!playerDrewThird || (pthirdCard == 6 || pthirdCard == 7)) { [self dealCardToHand:BCT_BANKERHAND]; } break; } } } // Get the total for each hand ptotal = pile[BCT_PLAYERHAND].total; btotal = pile[BCT_BANKERHAND].total; // Now see which hand won, and pay accordingly... if(btotal > ptotal) { [self say:"Banker Hand Wins!"]; NXPing(); usleep(BCT_LONGPAUSE); for(i=0; i<BCT_MAXPLAYERS; i++) { [bankerText setStringValue:"Winner!"]; [player[i].bankView payBets]; // 5% commission... [player[i].bankView multiplyBetsBy:.95]; [player[i].playerView clearBets]; [player[i].tieView clearBets]; } [self updateWinText:BCT_BANKVIEW]; } else if(ptotal > btotal) { [self say:"Player Hand Wins!"]; NXPing(); usleep(BCT_LONGPAUSE); for(i=0; i<BCT_MAXPLAYERS; i++) { [playerText setStringValue:"Winner!"]; [player[i].bankView clearBets]; [player[i].playerView payBets]; [player[i].tieView clearBets]; } [self updateWinText:BCT_PLAYERVIEW]; } else if(ptotal == btotal) { [self say:"Tie Game!"]; NXPing(); usleep(BCT_LONGPAUSE); for(i=0; i<BCT_MAXPLAYERS; i++) { [bankerText setStringValue:"Tie"]; [playerText setStringValue:"Tie"]; [player[i].tieView payBets]; } [self updateWinText:BCT_TIEVIEW]; } [PBoss() playSound:NV_CHIPSOUND]; [self say:"New Game... Place Your Bets!"]; [self enableDealButton]; return self; } - totalHand:(int)hand { int i, total=0; for(i=0; i<[pile[hand].pile cardCount]; i++) { total += [[pile[hand].pile cardAt:i] userValue]; } if(total >=20) total -=20; else if(total >= 10) total -= 10; pile[hand].total = total; [pile[hand].text setIntValue:total]; return self; } - updateWinText:(int)viewToUpdate { id view = nil; switch(viewToUpdate) { case BCT_PLAYERVIEW: view = playerWinText; break; case BCT_BANKVIEW: view = bankWinText; break; case BCT_TIEVIEW: view = tieText; break; } [view setIntValue:[view intValue]+1]; return self; } /*************************************************************************************** * Inspector And Rules Methods * ***************************************************************************************/ - (BOOL)hasRules /* NO if the module does not have a Rules Window, YES if it does. The default method returns NO. */ { return YES; } - inspectorWillBeRemoved:sender /* Sent when this module's inspector is about to be replace with another one. */ { return self; } - inspectorWasInstalled:sender /* Sent just after this module's inspector has been installed. */ { return self; } /*************************************************************************************** * Player Methods * ***************************************************************************************/ - (int)collectAllBetsForPlayer:(int)playerNum { int total=0; total = [player[playerNum].tieView collectBetAtRow:0 col:0]; total += [player[playerNum].bankView collectBetAtRow:0 col:0]; total += [player[playerNum].playerView collectBetAtRow:0 col:0]; [self enableDealButton]; return total; } - playerDidBet:aPlayer { return self; } - playerDidClose:aPlayer /* * Sent after a player has closed and is no longer part of the game. No messages * should be sent to aPlayer. This method should just do some internal cleanup * if necessary. */ { [self getPlayers]; return self; } - playerDidJoin:player { [self getPlayers]; return self; } - (BOOL)playerWillClose:aPlayer /* * Should return YES if it is okay to close this player, NO if it is not. The * default implementation returns YES. */ { return YES; } - (BOOL)playerWillJoin:sender { return YES; } /*************************************************************************************** * Table Methods * ***************************************************************************************/ - view:aView wasLoadedOnTable:tableObject { int i; [super view:aView wasLoadedOnTable:tableObject]; [self say:"Welcome to Baccarat! Place Your Bets!"]; for(i=0; i<BCT_MAXPLAYERS; i++) { [player[i].tieView setTrackingRectForWindow:[PBoss() tableWindow]]; [player[i].bankView setTrackingRectForWindow:[PBoss() tableWindow]]; [player[i].playerView setTrackingRectForWindow:[PBoss() tableWindow]]; } return self; } - revertPreferences:sender { int numDecks = atoi(NXGetDefaultValue(BCT_NAMEFORDEFAULTS, "numDecks")); [self selectCellWithTag:numDecks forPopUpButton:deckPrefButton]; return self; } - setPreferences:sender { static NXDefaultsVector newDefaults = { {"numDecks", "8"}, {NULL, NULL} }; int numDecks = [[[[deckPrefButton target] itemList] selectedCell] tag]; newDefaults[0].value = alloca(256); sprintf(newDefaults[0].value, "%d", numDecks); NXWriteDefaults(BCT_NAMEFORDEFAULTS, newDefaults); return self; } /*************************************************************************************** * Other Misc. Methods * ***************************************************************************************/ - finishSessionAndClose /* This message is sent when a new game is being loaded. If there is any clean up to do, this is where to do it. */ { int i; for(i=0; i<BCT_MAXPLAYERS; i++) { [player[i].tieView discardTrackingRect]; [player[i].bankView discardTrackingRect]; [player[i].playerView discardTrackingRect]; } [self setPreferences:self]; return self; } @end @implementation Baccarat(BetViewDelegate) - player:aPlayer willBet:(int)betType onView:sender { int amount, prevAmount, pnum=-1; char buf[128]; id thePlayer; switch([sender viewType]) { case BCT_PLAYERVIEW: pnum = [sender tag] - BCT_PLAYERTAG; break; case BCT_BANKVIEW: pnum = [sender tag] - BCT_BANKTAG; break; case BCT_TIEVIEW: pnum = [sender tag] - BCT_TIETAG; break; } thePlayer = [PBoss() playerAt:pnum]; if(thePlayer != nil) { amount = [thePlayer selectedChip]; prevAmount = [sender amountAtRow:0 col:0]; switch(betType) { case NV_BET: if(amount == DEFAULT) { amount = [self tableMin]; } if(amount > [thePlayer amountInBank]) { NXBeep(); [self say:"You can't wager more than you have!"]; return nil; } if(prevAmount+amount > [self tableMax]) { NXBeep(); [self say:"That bet would put you over the table max!"]; return nil; } [sender bet:amount atRow:0 col:0]; [thePlayer removeChip:amount]; sprintf(buf, "Dealer accepts %s's $%d wager.", [thePlayer playerName], prevAmount+amount); [self say:buf]; break; case NV_REMOVEBET: if(prevAmount == 0) return nil; if(amount == DEFAULT) amount = prevAmount; if(amount > prevAmount) { amount = prevAmount; } [sender removeBet:amount atRow:0 col:0]; [thePlayer addChip:amount]; if(prevAmount-amount > 0) { sprintf(buf, "Dealer accepts %s's $%d.", [aPlayer playerName], prevAmount-amount); } else sprintf(buf, "Player %s removed his wager", [aPlayer playerName]); [self say:buf]; break; case NV_REMOVEOTHER: if(prevAmount == 0) return nil; amount = prevAmount; [sender removeBet:amount atRow:0 col:0]; [thePlayer addChip:amount]; if(prevAmount-amount > 0) { sprintf(buf, "Dealer accepts %s's $%d.", [aPlayer playerName], prevAmount-amount); } else sprintf(buf, "Player %s removed his wager", [aPlayer playerName]); [self say:buf]; break; default: NXBeep(); [self say:"That action is not allowed in this game..."]; break; } } [self enableDealButton]; return self; } - mouseEnteredView:sender { char buf[256], wintext[96], ownertext[96]; int pnum = [sender tag]; switch([sender viewType]) { case BCT_BANKVIEW: strcpy(wintext, "the Banker will WIN"); pnum -= BCT_BANKTAG; break; case BCT_PLAYERVIEW: strcpy(wintext, "the Player will WIN"); pnum -= BCT_PLAYERTAG; break; case BCT_TIEVIEW: strcpy(wintext, "the Banker and Player will TIE"); pnum -= BCT_TIETAG; break; } if(player[pnum].player) strcpy(ownertext, [player[pnum].player playerName]); else sprintf(ownertext, "Player #%d", pnum+1); sprintf(buf, "This is %s's area to bet that %s.", ownertext, wintext); [self say:buf]; return self; } - mouseExitedView:sender { return self; } - (BOOL)playerWillDragChipAtRow:(int)row andCol:(int)col fromView:sender { return YES; } - playerDraggedChipAtRow:(int)row andCol:(int)col fromView:sender { [self enableDealButton]; return self; } - (BOOL)playerWillDropChipAtRow:(int *)row andCol:(int *)col InView:sender; { return YES; } - playerDroppedChipAtRow:(int)row andCol:(int)col inView:sender { [self enableDealButton]; return self; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.