This is TableView.m in view mode; [Download] [Up]
#import "TableView.h"
#import "crapswraps.h"
#import "props.h"
@implementation TableView
- initializePropositions
{
int i;
window = [dealer table];
for(i=0; i<MAX_PLAYERS; i++)
{
bets[i].amount = 0;
bets[i].odds = 0;
bets[i].isOn = YES;
}
if((displayFont = [Font newFont:"Helvetica" size:8 matrix:NX_IDENTITYMATRIX]) == nil)
NXRunAlertPanel("Font Error", "Unable to find font", "Okay", NULL, NULL);
puckFont = [Font newFont:"Times-Roman" size:10 matrix:NX_IDENTITYMATRIX];
for(i=0; i<MAX_PLAYERS; i++)
{
chip[i].textColor = (i+1<(MAX_PLAYERS/2)) ? NX_BLACK : NX_WHITE;
chip[i].chipColor = NX_WHITE - NX_WHITE/((float)MAX_PLAYERS/((float)i+1.0));
}
return self;
}
- initializeChipPlacement
{
int i, numPlayers;
float width = NX_WIDTH(&bounds), section, center;
numPlayers = [dealer numPlayers];
section = (width)/numPlayers;
center = section/2;
for(i=0; i<numPlayers; i++)
{
chip[i].r = 10.0;
chip[i].x = (section*i)+center;
chip[i].y = chip[i].r + 2.0;
}
return self;
}
- setTag:(int)aTag
{
tag = aTag;
return self;
}
- setTrackingRectForWindow:aWindow
{
NXRect aRect;
//window = aWindow;
[self getFrame:&aRect];
[superview convertRect:&aRect toView:nil];
[window setTrackingRect:&aRect
inside:NO
owner:self
tag:tag
left:NO
right:NO];
return self;
}
- (int)tag
{
return tag;
}
/***********************
* Betting Methods *
***********************/
- bet:(int)units forPlayer:player num:(int)playerNum
{
int point = [dealer point];
char buf[256];
if(player == nil) return nil;
// Things player can't bet on directly...
if((tag == COME_FOUR || tag == COME_FIVE || tag == COME_SIX || tag == COME_EIGHT ||
tag == COME_NINE || tag == COME_TEN || tag == DONT_COME_FOUR ||
tag == DONT_COME_FIVE || tag == DONT_COME_SIX || tag == DONT_COME_EIGHT ||
tag == DONT_COME_NINE || tag == DONT_COME_TEN))
{
[dealer playSound:WARNSOUND];
sprintf(buf, "Can't bet on %s directly...", prop[tag].name);
[dealer say:buf];
return self;
}
// Do not allow a bet on PASS or DONT_PASS if point has been established.
if(point != 0 && (tag == PASS || tag == DONT_PASS))
{
[dealer playSound:WARNSOUND];
sprintf(buf, "Can't bet on %s after the point has been established...", prop[tag].name);
[dealer say:buf];
return nil;
}
// use default bet if user wants
if(units == DEFAULT)
units = (prop[tag].cost > [dealer tableMin]) ? prop[tag].cost : [dealer tableMin];
// special case HORN
if(tag == HORN)
units = prop[tag].cost * [dealer tableMin];
// if this bet is more than the player has in chips, or if units would put
// the bet above the table maximum, do not allow it.
if(units > [player amountInBank])
{
[dealer playSound:WARNSOUND];
sprintf(buf, "Can't bet more than you have!");
[dealer say:buf];
return nil;
}
if(((units+bets[playerNum].amount+bets[playerNum].odds) > [dealer tableMax]))
{
[dealer playSound:WARNSOUND];
sprintf(buf, "Betting $%d on %s would put your bet over the table max!",
units, prop[tag].name);
[dealer say:buf];
return nil;
}
[dealer playSound:CHIPSOUND];
// add units to bet, subtract from players bank
bets[playerNum].amount += units;
bets[playerNum].isOn = YES;
[player addToBank:-units];
[self displayFromOpaqueAncestor:&bounds :1 :YES];
sprintf(buf, "House accepts %s's $%d bet on %s.", [player playerName], bets[playerNum].amount, prop[tag].name);
[dealer say:buf];
return self;
}
- removeBet:(int)units forPlayer:player num:(int)playerNum
{
int point = [dealer point];
char buf[256];
if(player == nil) return nil;
// Things player can't bet on directly...
if((tag == COME_FOUR || tag == COME_FIVE || tag == COME_SIX || tag == COME_EIGHT ||
tag == COME_NINE || tag == COME_TEN || tag == DONT_COME_FOUR ||
tag == DONT_COME_FIVE || tag == DONT_COME_SIX || tag == DONT_COME_EIGHT ||
tag == DONT_COME_NINE || tag == DONT_COME_TEN))
{
[dealer playSound:WARNSOUND];
sprintf(buf, "Can't bet on %s directly...", prop[tag].name);
[dealer say:buf];
return nil;
}
// do not allow a player to remove a PASS, DONT_PASS, COME, or DONT_COME bet once
// point has been established.
if(point != 0 && (tag == PASS || tag == DONT_PASS))
{
[dealer playSound:WARNSOUND];
sprintf(buf, "Can't remove %s bets after the point has been established!",
prop[tag].name);
[dealer say:buf];
return nil;
}
else if(tag >= COME_FOUR && tag <= COME_TEN)
{
[dealer playSound:WARNSOUND];
sprintf(buf, "Can't remove %s bets after the point has been established!",
prop[tag].name);
[dealer say:buf];
return nil;
}
else if(tag >= DONT_COME_FOUR && tag <= DONT_COME_TEN)
{
[dealer playSound:WARNSOUND];
sprintf(buf, "Can't remove %s bets after the point has been established!",
prop[tag].name);
[dealer say:buf];
return nil;
}
if(units == DEFAULT)
units = bets[playerNum].amount;
// dont allow a player to subtract more than he has bet
if(units > bets[playerNum].amount)
{
[dealer playSound:WARNSOUND];
sprintf(buf, "Can't remove more than you've bet!");
[dealer say:buf];
return nil;
}
[dealer playSound:CHIPSOUND];
// subtract units from bet, add that amount to player's bank.
bets[playerNum].amount -= units;
[player addToBank:units];
[self displayFromOpaqueAncestor:&bounds :1 :YES];
return self;
}
- layOdds:(int)units forPlayer:player num:(int)playerNum
{
int point = [dealer point];
char buf[256];
if(player == nil) return nil;
// only allow odds on props that allow odds, and only on PASS and DONT_PASS after
// point has been established.
if(!prop[tag].allowsOdds)
{
[dealer playSound:WARNSOUND];
sprintf(buf, "Odds bets aren't allowed on %s!", prop[tag].name);
[dealer say:buf];
return nil;
}
if(point == 0 && (tag == PASS || tag == DONT_PASS))
{
[dealer playSound:WARNSOUND];
sprintf(buf, "Can't buy odds on %s before the point has been established!", prop[tag].name);
[dealer say:buf];
return nil;
}
if(units == DEFAULT)
units = bets[playerNum].amount;
// dont allow any more odds if units is greater than players bank, or if
// adding units to odds would make the bet greater than table max.
if(units > [player amountInBank] || bets[playerNum].amount == 0 )
{
[dealer playSound:WARNSOUND];
[dealer say:"You don't have enough money for that bet!"];
return nil;
}
if(((units+bets[playerNum].amount+bets[playerNum].odds) > [dealer tableMax]))
{
[dealer playSound:WARNSOUND];
sprintf(buf, "Laying odds on %s now would put your bet over the table max!", prop[tag].name);
[dealer say:buf];
return nil;
}
// don't allow more than [dealer tableOdds] times odds
if(((bets[playerNum].odds+units) / bets[playerNum].amount) > [dealer tableOdds])
{
[dealer playSound:WARNSOUND];
sprintf(buf, "Can't have more than %dX odds on bets!", [dealer tableOdds]);
[dealer say:buf];
return nil;
}
[dealer playSound:CHIPSOUND];
// add odds to bet, subtract amount from bank.
bets[playerNum].odds += units;
bets[playerNum].isOn = YES;
[player addToBank:-units];
[self displayFromOpaqueAncestor:&bounds :1 :YES];
return self;
}
- removeOdds:(int)units forPlayer:player num:(int)playerNum
{
char buf[256];
if(player == nil) return nil;
if(units == DEFAULT)
units = bets[playerNum].odds;
// don't allow removal of more odds than player has bet
if(units > bets[playerNum].odds)
{
[dealer playSound:WARNSOUND];
sprintf(buf, "Can't remove more odds than you've bet!");
[dealer say:buf];
return nil;
}
[dealer playSound:CHIPSOUND];
bets[playerNum].odds -= units;
[player addToBank:units];
[self displayFromOpaqueAncestor:&bounds :1 :YES];
return self;
}
/**************************************
* Manipulating Bets *
**************************************/
- payOutForRoll:(int)roll
{
int player, amount=0, odds=0, profit=0, cost=0;
for(player = 0; player < MAX_PLAYERS; player++)
{
if(bets[player].amount > 0 && bets[player].isOn)
{
if(tag == FIELD && (roll == 2 || roll == 12)) // special case FIELD
{
amount = 2 * prop[tag].payoff * (int) (bets[player].amount /
prop[tag].cost);
}
else
{
amount = prop[tag].payoff * (int) (bets[player].amount / prop[tag].cost);
}
amount = amount + (int)(bets[player].amount % prop[tag].cost);
amount = amount + bets[player].amount;
// special case HORN. Payout is 1/4 the bet times the payout for TWO
// THREE, ELEVEN, or TWELVE, depending on what is rolled.
if(tag == HORN)
{
switch(roll)
{
case 2:
amount = prop[TWO].payoff *
(int) (bets[player].amount/4/prop[TWO].cost);
amount = amount + (int)((bets[player].amount/4) %
prop[TWO].cost);
break;
case 3:
amount = prop[THREE].payoff *
(int) (bets[player].amount/4/prop[THREE].cost);
amount = amount + (int)((bets[player].amount/4) %
prop[THREE].cost);
break;
case 11:
amount = prop[ELEVEN].payoff *
(int) (bets[player].amount/4/prop[ELEVEN].cost);
amount = amount + (int)((bets[player].amount/4) %
prop[ELEVEN].cost);
break;
case 12:
amount = prop[TWELVE].payoff *
(int) (bets[player].amount/4/prop[TWELVE].cost);
amount = amount + (int)((bets[player].amount/4) %
prop[TWELVE].cost);
break;
}
amount = amount + (bets[player].amount/4);
}
// get odds for roll if needed
if(prop[tag].allowsOdds && bets[player].odds > 0)
{
switch(tag)
{
case PASS:
[dealer trueOdds:&profit for:&cost forRoll:roll];
break;
case COME_FOUR:
[dealer trueOdds:&profit for:&cost forRoll:roll];
break;
case COME_FIVE:
[dealer trueOdds:&profit for:&cost forRoll:roll];
break;
case COME_SIX:
[dealer trueOdds:&profit for:&cost forRoll:roll];
break;
case COME_EIGHT:
[dealer trueOdds:&profit for:&cost forRoll:roll];
break;
case COME_NINE:
[dealer trueOdds:&profit for:&cost forRoll:roll];
break;
case COME_TEN:
[dealer trueOdds:&profit for:&cost forRoll:roll];
break;
// odds on the DONTs are opposite
case DONT_PASS:
[dealer trueOdds:&profit for:&cost forRoll:-[dealer point]];
break;
case DONT_COME_FOUR:
[dealer trueOdds:&profit for:&cost forRoll:-4];
break;
case DONT_COME_FIVE:
[dealer trueOdds:&profit for:&cost forRoll:-5];
break;
case DONT_COME_SIX:
[dealer trueOdds:&profit for:&cost forRoll:-6];
break;
case DONT_COME_EIGHT:
[dealer trueOdds:&profit for:&cost forRoll:-8];
break;
case DONT_COME_NINE:
[dealer trueOdds:&profit for:&cost forRoll:-9];
break;
case DONT_COME_TEN:
[dealer trueOdds:&profit for:&cost forRoll:-10];
break;
}
odds = profit * (int)(bets[player].odds / cost);
odds = odds + (int)(bets[player].odds % cost);
odds = odds + bets[player].odds;
bets[player].odds = 0;
}
bets[player].amount = amount + odds;
}
}
[self displayFromOpaqueAncestor:&bounds :1 :YES];
return self;
}
- clearBets
{
int i;
for(i=0; i<MAX_PLAYERS; i++)
{
if(bets[i].isOn)
{
bets[i].amount = 0;
bets[i].odds = 0;
}
}
[self displayFromOpaqueAncestor:&bounds :1 :YES];
return self;
}
- getBetsFrom:otherView
{
int i;
for(i=0; i<MAX_PLAYERS; i++)
{
[otherView getBet:&bets[i].amount odds:&bets[i].odds forPlayer:i];
[otherView setBet:0 odds:0 forPlayer:i];
}
[self displayFromOpaqueAncestor:&bounds :1 :YES];
return self;
}
- addBetsFrom:otherView
{
int i, bet, odds;
for(i=0; i<MAX_PLAYERS; i++)
{
[otherView getBet:&bet odds:&odds forPlayer:i];
[otherView setBet:0 odds:0 forPlayer:i];
bets[i].amount = bets[i].amount + bet;
bets[i].odds = bets[i].odds + odds;
}
[self displayFromOpaqueAncestor:&bounds :1 :YES];
return self;
}
- getBet:(int *)bet odds:(int *)odds forPlayer:(int)playerNum
{
*bet = bets[playerNum].amount;
*odds = bets[playerNum].odds;
return self;
}
- setBet:(int)bet odds:(int)odds forPlayer:(int)playerNum
{
bets[playerNum].amount = bet;
bets[playerNum].odds = odds;
[self displayFromOpaqueAncestor:&bounds :1 :YES];
return self;
}
- switchBetOnOffForPlayer:(int) playerNum
{
if(bets[playerNum].isOn == NO)
bets[playerNum].isOn = YES;
else
bets[playerNum].isOn = NO;
[self displayFromOpaqueAncestor:&bounds :1 :YES];
return self;
}
- tradeBetsWith:otherView
{
int i, bet, odds;
for(i=0; i<MAX_PLAYERS; i++)
{
[otherView getBet:&bet odds:&odds forPlayer:i];
[otherView setBet:bets[i].amount odds:bets[i].odds forPlayer:i];
bets[i].amount = bet;
bets[i].odds = odds;
}
[self displayFromOpaqueAncestor:&bounds :1 :YES];
return self;
}
- drawSelf:(const NXRect *)rects :(int)rectCount
{
int i;
float width;
char bet[20];
int point = [dealer point];
BOOL doPuckSound = NO;
// draw puck if needed
if((point==4 && tag==COME_FOUR) || (point==5 && tag==COME_FIVE) ||
(point==6 && tag==COME_SIX) || (point==8 && tag==COME_EIGHT) ||
(point==9 && tag==COME_NINE) || (point==10 && tag==COME_TEN))
{
[puckFont set];
drawChip(NX_WIDTH(&bounds)/2, NX_HEIGHT(&bounds)/2+15, 15.0, NX_BLACK);
width = [displayFont getWidthOf:"Point"];
drawText("Point", NX_WIDTH(&bounds)/2-(width/2)-2, NX_HEIGHT(&bounds)/2+12, NX_WHITE);
// play sound if we this is the first time we draw the puck
if(!drawingPuck)
{
//[dealer playSound:PUCKSOUND];
doPuckSound = YES;
drawingPuck = YES;
}
}
else
drawingPuck = NO;
for(i=0; i<MAX_PLAYERS; i++)
{
if(bets[i].amount>0)
{
[displayFont set];
drawChip(chip[i].x, chip[i].y, chip[i].r, chip[i].chipColor);
if(bets[i].isOn)
sprintf(bet, "%d", bets[i].amount);
else
sprintf(bet, "OFF");
width = [displayFont getWidthOf:bet];
drawText(bet, chip[i].x-(width/2), chip[i].y-4, chip[i].textColor);
if(bets[i].odds > 0)
{
drawChip(chip[i].x, chip[i].y+4, chip[i].r, chip[i].chipColor);
if(bets[i].isOn)
sprintf(bet, "%d", bets[i].amount+bets[i].odds);
else
sprintf(bet, "OFF");
width = [displayFont getWidthOf:bet];
drawText(bet, chip[i].x-(width/2), chip[i].y, chip[i].textColor);
}
}
}
if(doPuckSound) [dealer playSound:PUCKSOUND];
return self;
}
- (BOOL)acceptsFirstMouse
{
return YES;
}
- mouseDown:(NXEvent *)theEvent
/*
* player has moused down in our view, indicating that they wish to bet here.
*
* if no key is down -- Bet
* if shift is down -- remove bet
* if alternate key is down - lay odds
* if alternate+shift is down -- remove odds
* if control+shift -- turn off/on
*/
{
id player = [dealer currentPlayer];
if(theEvent->flags & NX_ALTERNATEMASK)
{
if(theEvent->flags & NX_SHIFTMASK)
[self removeOdds:[player selectedChip] forPlayer:player num:[player tag]];
else
[self layOdds:[player selectedChip] forPlayer:player num:[player tag]];
}
else if(theEvent->flags & NX_SHIFTMASK)
{
[self removeBet:[player selectedChip] forPlayer:player num:[player tag]];
}
else if(theEvent->flags & NX_CONTROLMASK)
{
[self switchBetOnOffForPlayer:[player tag]];
} else {
[self bet:[player selectedChip] forPlayer:player num:[player tag]];
}
return self;
}
- mouseEntered:(NXEvent *)theEvent
{
[dealer mouseEnteredView:tag];
return self;
}
- mouseExited:(NXEvent *)theEvent
{
return self;
}
@end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.