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.