This is RedDog.m in view mode; [Download] [Up]
#import "RedDog.h"
#import "../NEXTVegas/CardSet.subproj/cardset.h"
#define RD_DRAWPAUSE 200000
#define RD_LONGPAUSE 999999
#define RD_LEFTPILE 1
#define RD_RIGHTPILE 3
#define RD_MIDDLEPILE 2
#define RD_DECKPILE 0
#define RD_WINNER 1
#define RD_LOSER 0
#define RD_BEFOREDEAL 2
#define RD_BEFORETHIRD 3
#define RD_NAMEFORDEFAULTS "NVRedDog"
@implementation RedDog
/***************************************************************************************
* Module Methods *
***************************************************************************************/
+ initialize
{
static NXDefaultsVector ourDefaults = {
{"numDecks", "8"},
{NULL, NULL}
};
NXRegisterDefaults(RD_NAMEFORDEFAULTS, ourDefaults);
return self;
}
- awakeFromNib
/*
Sent to every object instantiated in a nib file. A good place to perform some
initialization...
*/
{
// This may take a while, so lets inform the user
[self say:"Pre-Drawing Cards..."];
NXPing();
[Card drawCardImages];
pile1 = [pileView1 cardPile];
pile2 = [pileView2 cardPile];
pile3 = [pileView3 cardPile];
deckPile = [deckView cardPile];
//[[[deckView setCoversOthers:YES] setCardSize:CS_SMALL] setDrawOutline:NO];
[deckView setUseShoe:YES];
[[[pileView1 setCoversOthers:YES] setCardSize:CS_SMALL] setDrawOutline:NO];
[[[pileView2 setCoversOthers:YES] setCardSize:CS_SMALL] setDrawOutline:NO];
[[[pileView3 setCoversOthers:YES] setCardSize:CS_SMALL] setDrawOutline:NO];
[[[[[betView setNumCols:MAX_PLAYERS] setNumRows:1] positionChips]
setEnabled:YES] setSoundEnabled:YES];
handStatus = RD_BEFOREDEAL;
[self revertPreferences:self];
[self checkDeck];
won = 0;
lost = 0;
return self;
}
- (BOOL)anyBetsTooLowOrHigh
{
int i;
char buf[512];
for(i=0; i<MAX_PLAYERS; i++)
{
if([betView amountAtRow:0 col:i] &&
[betView amountAtRow:0 col:i] < [self tableMin])
{
sprintf(buf, "%s, your bet is below the table minimum!",
[[PBoss() playerAt:i] playerName]);
[PBoss() playSound:NV_WARNSOUND];
[self say:buf];
return YES;
}
if([betView amountAtRow:0 col:i] &&
[betView amountAtRow:0 col:i] > [self tableMax])
{
sprintf(buf, "%s, your bet is above the table maximum!",
[[PBoss() playerAt:i] playerName]);
[PBoss() playSound:NV_WARNSOUND];
[self say:buf];
return YES;
}
}
return NO;
}
- deal:sender
{
if(handStatus == RD_BEFOREDEAL)
{
[self dealFirstTwo];
}
else if(handStatus == RD_BEFORETHIRD)
{
[self dealThird];
}
return self;
}
- dealFirstTwo
{
int i;
// Make sure wager is above table min, and below table max
if([self anyBetsTooLowOrHigh]) return self;
[dealButton setEnabled:NO];
for(i=0; i<MAX_PLAYERS; i++)
doubledAlready[i] = NO;
[self checkDeck];
[self dealCardToPile:RD_LEFTPILE];
[self dealCardToPile:RD_RIGHTPILE];
[self setPayoff];
if(spread == 0) // two cards are the same
{
[self say:"The two cards are the same, dealing third card...."];
NXPing();
usleep(RD_LONGPAUSE);
return [self dealThird];
}
else if(spread == 1) // two cards are consecutive
{
[self say:"The two cards are the consecutive, dealing again...."];
NXPing();
usleep(RD_LONGPAUSE);
return [self dealFirstTwo];
}
[self say:"You can double your bet now, if you wish. Press 'Continue' when ready..."];
handStatus = RD_BEFORETHIRD;
[dealButton setTitle:"Continue"];
[self enableDealButtonIfNecessary];
return self;
}
- dealThird
{
[dealButton setEnabled:NO];
[self dealCardToPile:RD_MIDDLEPILE];
usleep(RD_LONGPAUSE);
[self checkHand];
[self say:"New game... Place your bets!"];
handStatus = RD_BEFOREDEAL;
[dealButton setTitle:"Deal"];
[self enableDealButtonIfNecessary];
return self;
}
- dealCardToPile:(int)pileNum
{
id card, pile=deckPile, view=deckView;
switch(pileNum)
{
case RD_LEFTPILE: pile = pile1; view = pileView1; break;
case RD_RIGHTPILE: pile = pile3; view = pileView3; break;
case RD_MIDDLEPILE: pile = pile2; view = pileView2; break;
default: return nil;
}
card = [deckPile cardAt:CS_TOP];
[card setFaceUp:YES];
[pile addCard:card];
[deckPile removeCard:card];
[deckView display];
[view display];
NXPing();
[PBoss() playSound:NV_CARDSOUND];
usleep(RD_DRAWPAUSE);
return self;
}
- checkDeck
{
[pile1 empty];
[pile2 empty];
[pile3 empty];
[pileView1 display];
[pileView2 display];
[pileView3 display];
if([deckPile cardCount] < 4)
{
[self newDeck:self];
}
return self;
}
- checkHand
{
if([[pile1 cardAt:CS_TOP] userValue] < [[pile2 cardAt:CS_TOP] userValue] &&
[[pile2 cardAt:CS_TOP] userValue] < [[pile3 cardAt:CS_TOP] userValue])
{
handStatus = RD_WINNER;
}
else if([[pile1 cardAt:CS_TOP] userValue] > [[pile2 cardAt:CS_TOP] userValue] &&
[[pile2 cardAt:CS_TOP] userValue] > [[pile3 cardAt:CS_TOP] userValue])
{
handStatus = RD_WINNER;
}
else if([[pile1 cardAt:CS_TOP] userValue] == [[pile2 cardAt:CS_TOP] userValue] &&
[[pile2 cardAt:CS_TOP] userValue] == [[pile3 cardAt:CS_TOP] userValue])
{
handStatus = RD_WINNER;
}
else
{
handStatus = RD_LOSER;
}
if(handStatus == RD_WINNER)
{
[self say:"Hand Wins! Paying Line Bets!"];
NXPing();
[betView payBets];
[wonText setIntValue:++won];
}
else
{
[self say:"Hand Loses! Clearing Line Bets!"];
NXPing();
[betView clearBets];
[lostText setIntValue:++lost];
}
[PBoss() playSound:NV_CHIPSOUND];
NXPing();
usleep(RD_LONGPAUSE);
return self;
}
- enableDealButtonIfNecessary
{
int i;
BOOL shouldEnable = NO;
for(i=0; i<MAX_PLAYERS; i++)
{
if([betView amountAtRow:0 col:i])
shouldEnable = YES;
}
if(shouldEnable)
[dealButton setEnabled:YES];
else
[dealButton setEnabled:NO];
return self;
}
- newDeck:sender
{
id theMatrix;
int numDecks;
theMatrix = [[deckPrefButton target] itemList];
numDecks = [[theMatrix selectedCell] tag];
if(numDecks == 0) numDecks = 1;
[self newDeck:numDecks forView:deckView];
[self setUserValueForPile:deckPile aceHigh:YES];
return self;
}
- setPayoff
{
spread = abs([[pile1 cardAt:CS_TOP] userValue] - [[pile3 cardAt:CS_TOP] userValue]);
switch(spread)
{
case 0: [betView setPayoff:15 cost:1]; break;
case 1: return nil;
case 2: [betView setPayoff:7 cost:1]; break;
case 3: [betView setPayoff:5 cost:1]; break;
case 4: [betView setPayoff:3 cost:1]; break;
case 5: [betView setPayoff:2 cost:1]; break;
default: [betView setPayoff:1 cost:1]; break;
}
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;
if(handStatus != RD_BEFORETHIRD)
{
total = [betView collectBetAtRow:0 col:playerNum];
[betView display];
[self enableDealButtonIfNecessary];
}
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.
*/
{
return self;
}
- playerDidJoin:player
{
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.
*/
{
if(RD_BEFORETHIRD) return NO;
return YES;
}
- (BOOL)playerWillJoin:sender
{
return YES;
}
/***************************************************************************************
* Table Methods *
***************************************************************************************/
- view:aView wasLoadedOnTable:tableObject
{
table = tableObject;
[self say:"Welcome to Red Dog! Place Your Bets!"];
return self;
}
- revertPreferences:sender
{
int numDecks = atoi(NXGetDefaultValue(RD_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(RD_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.
*/
{
[self setPreferences:self];
return self;
}
@end
@implementation RedDog(BetViewDelegate)
- player:aPlayer willBet:(int)betType onView:sender
{
int amount, prevAmount, tag = [aPlayer tag];
char buf[128];
if(aPlayer != nil)
{
amount = [aPlayer selectedChip];
prevAmount = [sender amountAtRow:0 col:tag];
switch(betType)
{
case NV_BET:
if(amount == DEFAULT)
{
amount = [self tableMin];
}
if(handStatus == RD_BEFORETHIRD)
{
if(doubledAlready[tag]) return nil;
amount = [betView amountAtRow:0 col:tag];
}
if(amount > [aPlayer 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:tag];
[aPlayer removeChip:amount];
sprintf(buf, "Dealer accepts %s's $%d wager.",
[aPlayer playerName], prevAmount+amount);
[self say:buf];
if(handStatus == RD_BEFORETHIRD)
doubledAlready[tag] = YES;
break;
case NV_REMOVEBET:
if(handStatus == RD_BEFORETHIRD) return nil;
if(prevAmount == 0) return nil;
if(amount == DEFAULT)
amount = prevAmount;
if(amount > prevAmount)
{
amount = prevAmount;
}
[sender removeBet:amount atRow:0 col:tag];
[aPlayer 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(handStatus == RD_BEFORETHIRD) return nil;
if(prevAmount == 0) return nil;
amount = prevAmount;
[sender removeBet:amount atRow:0 col:tag];
[aPlayer 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 enableDealButtonIfNecessary];
return self;
}
- (BOOL)playerWillDragChipAtRow:(int)row andCol:(int)col fromView:sender
{
// dont allow players to drag chips when game is in progress
if(handStatus == RD_BEFORETHIRD)
return NO;
else
return YES;
}
- playerDraggedChipAtRow:(int)row andCol:(int)col fromView:sender
{
[self enableDealButtonIfNecessary];
return self;
}
- (BOOL)playerWillDropChipAtRow:(int *)row andCol:(int *)col InView:sender;
{
// dont allow players to drag chips when game is in progress
if(handStatus == RD_BEFORETHIRD)
return NO;
else
return YES;
}
- playerDroppedChipAtRow:(int)row andCol:(int)col inView:sender
{
[self enableDealButtonIfNecessary];
return self;
}
@end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.