ftp.nice.ch/pub/next/games/card/NEXTVegas3.0.src.tar.gz#/NEXTVegas/VideoPoker/VideoPoker.m

This is VideoPoker.m in view mode; [Download] [Up]

#import "VideoPoker.h"
#import "../NEXTVegas/CardSet.subproj/cardset.h"
#import "prop.h"


#define VP_PAUSE 125000
#define VP_DOUBLEPAUSE 250000
#define VP_SEVOLUME .5

#define VP_NAMEFORDEFAULTS "NVVideoPoker"

void VPpayOutHandler(DPSTimedEntry teNumber, double now, void *userData)
{
	id obj = (id)userData;
	[obj payOneToCurrent];
}

void VPfastFlashHandler(DPSTimedEntry teNumber, double now, void *userData)
{
	id obj = (id)userData;
	[obj fastFlash];
}


@implementation VideoPoker
/***************************************************************************************
 *                                 Module Methods                                      *
 ***************************************************************************************/
+ initialize
{
    static NXDefaultsVector ourDefaults = {
        {"coinValue", "1"},
		{NULL, NULL}
    };
    
    NXRegisterDefaults(VP_NAMEFORDEFAULTS, ourDefaults);

	return self;
}

- awakeFromNib
{
 	int i;
	char path[MAXPATHLEN+1];

	// This may take a while, so lets inform the user
	[self say:"Pre-Drawing Cards..."];
	[Card drawCardImages];

	cardField[0].view = card1View;
	cardField[0].button = card1Button;
	cardField[1].view = card2View;
	cardField[1].button = card2Button;
 	cardField[2].view = card3View;
	cardField[2].button = card3Button;
 	cardField[3].view = card4View;
	cardField[3].button = card4Button;
 	cardField[4].view = card5View;
	cardField[4].button = card5Button;
	
	for(i=0; i<VP_NUMCARDS; i++)
	{
		cardField[i].pile = [cardField[i].view cardPile];
		[cardField[i].pile setCardSize:CS_LARGE];
		[cardField[i].button setEnabled:NO];
		[cardField[i].view setDrawOutline:NO];
		[cardField[i].view setCoversOthers:YES];
		[cardField[i].view setTag:i];
	}
	deckPile = [deckView cardPile];
	[deckPile setCardSize:CS_LARGE];
	
	maxCoins = VP_MAXCOINSDEFAULT;
		
	[coinsWonText setIntValue:0];
	[coinsPlayedText setIntValue:0];
	[creditText setIntValue:0];
	
	[self revertPreferences:self];

	[wonText setStringValue:""];
	[self newDeck];
	
	[self dealCards];
	
	// Create SoundEffects for the various sounds...
	if ([bundle getPath:path forResource:"Gliss" ofType:"snd"]) 
	{
		glissSound = [[SoundEffect allocFromZone:[self zone]] initFromSection:path];
	}
	if ([bundle getPath:path forResource:"DaDum" ofType:"snd"]) 
	{
		twoBeepSound = [[SoundEffect allocFromZone:[self zone]] initFromSection:path];
	}
	if ([bundle getPath:path forResource:"Beep" ofType:"snd"]) 
	{
		beepSound = [[SoundEffect allocFromZone:[self zone]] initFromSection:path];
	}
	if ([bundle getPath:path forResource:"BeepHigh2" ofType:"snd"]) 
	{
		beepHighSound = [[SoundEffect allocFromZone:[self zone]] initFromSection:path];
	}
	
	// Create NXImages for the various buttons...
	if ([bundle getPath:path forResource:"HoldButton" ofType:"tiff"]) 
	{
		holdButtonImage = [[NXImage allocFromZone:[self zone]] initFromFile:path];
	}
	if ([bundle getPath:path forResource:"HoldButtonH" ofType:"tiff"]) 
	{
		holdButtonImageH = [[NXImage allocFromZone:[self zone]] initFromFile:path];
	}
	if ([bundle getPath:path forResource:"CashOutButton" ofType:"tiff"]) 
	{
		cashOutButtonImage = [[NXImage allocFromZone:[self zone]] initFromFile:path];
	}
	if ([bundle getPath:path forResource:"CashOutButtonH" ofType:"tiff"]) 
	{
		cashOutButtonImageH = [[NXImage allocFromZone:[self zone]] initFromFile:path];
	}
	if ([bundle getPath:path forResource:"DrawButton" ofType:"tiff"]) 
	{
		drawButtonImage = [[NXImage allocFromZone:[self zone]] initFromFile:path];
	}
	if ([bundle getPath:path forResource:"DrawButtonH" ofType:"tiff"]) 
	{
		drawButtonImageH = [[NXImage allocFromZone:[self zone]] initFromFile:path];
	}
	if ([bundle getPath:path forResource:"BetOneButton" ofType:"tiff"]) 
	{
		oneCoinButtonImage = [[NXImage allocFromZone:[self zone]] initFromFile:path];
	}
	if ([bundle getPath:path forResource:"BetOneButtonH" ofType:"tiff"]) 
	{
		oneCoinButtonImageH = [[NXImage allocFromZone:[self zone]] initFromFile:path];
	}
	if ([bundle getPath:path forResource:"BetMaxButton" ofType:"tiff"]) 
	{
		maxCoinsButtonImage = [[NXImage allocFromZone:[self zone]] initFromFile:path];
	}
	if ([bundle getPath:path forResource:"BetMaxButtonH" ofType:"tiff"]) 
	{
		maxCoinsButtonImageH = [[NXImage allocFromZone:[self zone]] initFromFile:path];
	}

	if ([bundle getPath:path forResource:"VP1stCoin" ofType:"tiff"]) 
	{
		tableArea[0].image = [[NXImage allocFromZone:[self zone]] initFromFile:path];
	}
	if ([bundle getPath:path forResource:"VP2ndCoin" ofType:"tiff"]) 
	{
		tableArea[1].image = [[NXImage allocFromZone:[self zone]] initFromFile:path];
	}
	if ([bundle getPath:path forResource:"VP3rdCoin" ofType:"tiff"]) 
	{
		tableArea[2].image = [[NXImage allocFromZone:[self zone]] initFromFile:path];
	}
	if ([bundle getPath:path forResource:"VP4thCoin" ofType:"tiff"]) 
	{
		tableArea[3].image = [[NXImage allocFromZone:[self zone]] initFromFile:path];
	}
	if ([bundle getPath:path forResource:"VP5thCoin" ofType:"tiff"]) 
	{
		tableArea[4].image = [[NXImage allocFromZone:[self zone]] initFromFile:path];
	}
	if ([bundle getPath:path forResource:"VP1stCoinH" ofType:"tiff"]) 
	{
		tableArea[0].imageH = [[NXImage allocFromZone:[self zone]] initFromFile:path];
	}
	if ([bundle getPath:path forResource:"VP2ndCoinH" ofType:"tiff"]) 
	{
		tableArea[1].imageH = [[NXImage allocFromZone:[self zone]] initFromFile:path];
	}
	if ([bundle getPath:path forResource:"VP3rdCoinH" ofType:"tiff"]) 
	{
		tableArea[2].imageH = [[NXImage allocFromZone:[self zone]] initFromFile:path];
	}
	if ([bundle getPath:path forResource:"VP4thCoinH" ofType:"tiff"]) 
	{
		tableArea[3].imageH = [[NXImage allocFromZone:[self zone]] initFromFile:path];
	}
	if ([bundle getPath:path forResource:"VP5thCoinH" ofType:"tiff"]) 
	{
		tableArea[4].imageH = [[NXImage allocFromZone:[self zone]] initFromFile:path];
	}
	
	tableArea[0].button = tableButton1;
	tableArea[1].button = tableButton2;
	tableArea[2].button = tableButton3;
	tableArea[3].button = tableButton4;
	tableArea[4].button = tableButton5;
	
	[self setImages];	
	
	// Get ready for a new game
	[self endGame:self];
	
	return self;
}

- newDeck
/*
	Empty the deck, add a new one, and shuffle it.
*/
{
	[[[deckPile empty] addDeck] shuffle];

	return self;
}

- setImages
/*
	Sets the initial images for the various buttons...
*/
{
	int i;
	
	for(i=0; i<VP_NUMCARDS; i++)
	{
		[cardField[i].button setImage:holdButtonImage];
	}
	
	[cashOutButton setImage:cashOutButtonImage];
	[drawButton setImage:drawButtonImage];
	[maxCoinsButton setImage:maxCoinsButtonImage];
	[oneCoinButton setImage:oneCoinButtonImage];
	
	return self;
}

- setCoinValue:sender
{
	//if([coinsPlayedText intValue] > 0 || [creditText intValue] > 0)
	if(!isFirstCoin || [creditText intValue] > 0)
	{
		[self say:"Can't the change coin value while you have coins in the machine!"];
		NXPing();
		NXBeep();
		[self selectCellWithTag:coinValue forPopUpButton:coinValueButton];
	}
	else
	{
		coinValue = [[sender selectedCell] tag];
	
		[coinValueText setIntValue:coinValue];
	}
	
	return self;
}
/***************************************************************************************
 *                                Game Flow Methods                                    *
 ***************************************************************************************/
- startGame:sender
/*
	Free cardFields.  If deck has less than 15 cards, get a new deck
*/
{
	int i;
	
	[wonText setStringValue:""];
	
	[oneCoinButton setEnabled:NO];
	[maxCoinsButton setEnabled:NO];
	[[oneCoinButton setImage:oneCoinButtonImage] display];
	[[maxCoinsButton setImage:maxCoinsButtonImage] display];

	[coinsWonText setIntValue:0];
	
	[cashOutButton setEnabled:NO];
	[[cashOutButton setImage:cashOutButtonImage] display];
		
	for(i=0; i<VP_NUMCARDS; i++)
	{
		[cardField[i].button setEnabled:YES];
	}
	
	// if we've exhausted the deck, get a new one
	if([deckPile cardCount] < 15)
		[self newDeck];
	
	return self;
}

- dealCards
/*
	Deal the VP_NUMCARDS: one to each field.  Play a sound too.
*/
{
	int i;
	id newCard;
	
	// turn over cards first (just for effect...)
	for(i=0; i<VP_NUMCARDS; i++)
	{
		[[cardField[i].pile cardAt:CS_TOP] setFaceUp:NO];
		[cardField[i].view display];
	}
	
	// Take one card from the deck, and put it in the field
	for(i=0; i<VP_NUMCARDS; i++)
	{
		[cardField[i].pile empty];
		newCard = [deckPile cardAt:CS_TOP];
		[deckPile removeCard:newCard];
		[newCard setFaceUp:YES];
		[cardField[i].pile addCard:newCard];
		
		[cardField[i].view display];
		NXPing();
		[beepSound play:VP_SEVOLUME pan:0.0];
		usleep(VP_DOUBLEPAUSE);
	}
	
	return self;
}

- replaceDiscards
/*
	Replace the cards that haven't been selected to "hold".
*/
{
	int i;
	id newCard;
	
	// if button not pressed turn over card
	for(i=0; i<VP_NUMCARDS; i++)
	{
		if(![cardField[i].button state])
		{
			[[cardField[i].button setImage:holdButtonImage] display];
			
			[[cardField[i].pile cardAt:CS_TOP] setFaceUp:NO];
			[cardField[i].view display];
		}
	}
	
	// if button is not pressed, replace card there
	for(i=0; i<VP_NUMCARDS; i++)
	{
		// if button not pressed turn over card
		if(![cardField[i].button state])
		{
			newCard = [deckPile cardAt:CS_TOP];
			[newCard setFaceUp:YES];
			[deckPile removeCard:newCard];
			[cardField[i].pile empty];
			[cardField[i].pile addCard:newCard];
			
			[cardField[i].view display];
			NXPing();
			[beepSound play:VP_SEVOLUME pan:0.0];
			usleep(VP_DOUBLEPAUSE);
		}
	}
	
	return self;
}

- (PokerHand)checkForWin
/*
	Accumulate cards from each field into a pile, then check that pile for a win.
	Check from greatest to lowest possible winning hand.
*/
{
	int i;
	id	holdingPile;
	
	holdingPile = [[CardPile alloc] init];
	
	// accumulate the top card in each pile into holdingPile
	for(i=0; i<VP_NUMCARDS; i++)
	{
		[holdingPile addCard:[cardField[i].pile cardAt:CS_TOP]];
	}
	
	[holdingPile setAceHigh:YES];
	
	return [holdingPile pokerHand];

}

- endGame:sender
/*
	Do everything that needs to be done before a new game
*/
{
	int i;
	
	for(i=0; i<VP_NUMCARDS; i++)
	{
		[cardField[i].button setState:0];
		[cardField[i].button setEnabled:NO];
		[[cardField[i].button setImage:holdButtonImage] display];
	}
	
	for(i=0; i<5; i++)
	{
		[tableArea[i].button setImage:tableArea[i].image];
	}
	
	//[coinsPlayedText setIntValue:0];
	isFirstCoin = YES;
	
	if([PBoss() currentPlayer] && [[PBoss() currentPlayer] amountInBank]>0 && !payOutTE)
	{
		[oneCoinButton setEnabled:YES];
		[maxCoinsButton setEnabled:YES];
	}
	else
	{
		[oneCoinButton setEnabled:NO];
		[[oneCoinButton setImage:oneCoinButtonImage] display];
		[maxCoinsButton setEnabled:NO];
		[[maxCoinsButton setImage:maxCoinsButtonImage] display];
	}
	
	[drawButton setEnabled:NO];
	[[drawButton setImage:drawButtonImage] display];
	
	// can't cash out if we don't have credit, and if there's no current player
	if([creditText intValue] > 0 && [PBoss() currentPlayer])
		[cashOutButton setEnabled:YES];
	else
	{
		[cashOutButton setEnabled:NO];
		[[cashOutButton setImage:cashOutButtonImage] display];
	}
	
	[self say:"New Game... Place Your Bets!"];
	
	return self;
}

/***************************************************************************************
 *                                 Pay Out Methods                                     *
 ***************************************************************************************/
- payOut:(PokerHand)winType
/*
	pay the winning amount.  If this is a jackpot, pay it.  Start a timed entry
	to do the paying, one unit at a time...
*/
{  
	int amountBet;
	char buf[256];
	
	if(winType != CS_NOPOKERHAND)
	{
		sprintf(buf, "WINNER!  %s:  %s.", prop[winType].name, prop[winType].description);
		[self say:buf];
		[wonText setStringValue:prop[winType].name];
		NXPing();
		
		// play winning sound
		[glissSound play:VP_SEVOLUME pan:0.0];
		sleep(2);
		
		amountBet = [coinsPlayedText intValue];
		payOutAmount = amountBet * prop[winType].payoff;
		
		// if player hit the royal flush with max coins played, then pay out the 
		// jackpot (amount * VP_JACKPOTMULT)
		if(winType == CS_ROYALFLUSH && [coinsPlayedText intValue] == maxCoins)
			payOutAmount *= VP_JACKPOTMULT;
		
		if(payOutTE)
			DPSRemoveTimedEntry(payOutTE);
			
		payOutTE = DPSAddTimedEntry(.1, (DPSTimedEntryProc)VPpayOutHandler, self, NX_BASETHRESHOLD);
	}
	else
	{
		// Play losing sound
		[self say:""];
		NXPing();
		[twoBeepSound play:VP_SEVOLUME pan:0.0];
	}
	
	return self;
}

- payOneToCurrent
/*
	Target of VPpayOutHandler, this method just adds one unit to creditText and to
	coinsWonText.
*/
{
	if(payOutAmount)
	{
		[coinsWonText setIntValue:[coinsWonText intValue]+1];
		[creditText setIntValue:[creditText intValue]+1];
		NXPing();
		[beepHighSound play:VP_SEVOLUME pan:0.0];
		payOutAmount--;
	}
	else
	{
		// We're done, so remove timed entry
		DPSRemoveTimedEntry(payOutTE);
		payOutTE = 0;
		[self endGame:self];
	}
	
	return self;
}



/***************************************************************************************
 *                              Target/Action Methods                                  *
 ***************************************************************************************/
- cashOut:sender
/*
	Send all credits in creditText to current player
*/
{
	int amount;
	
	amount = [creditText intValue];
	[creditText setIntValue:0];
	[[PBoss() currentPlayer] addChip:amount*coinValue];
	NXPing();
	[twoBeepSound play:VP_SEVOLUME pan:0.0];

	[cashOutButton setEnabled:NO];
	[[cashOutButton setImage:cashOutButtonImage] display];
	
	[self endGame:self];
	
	[cashOutButton setState:0];
	
	return self;
}

- draw:sender
/*
	Target of the drawButton.  Either the game is in progress (i.e. cards have already
	been dealt) and we're going to discard those that aren't selected to be held, or
	this is a new game, and we just deal the cards.
*/
{

	if(handInProgress)
	// this means discard and get new cards...
	{
		[self replaceDiscards];
		
		[self payOut:[self checkForWin]];
		
		[self endGame:self];
		handInProgress = NO;
	}
	else
	// this means start game
	{
		[self say:"Dealing Cards..."];
		handInProgress = YES;
		[coinPlayDepText setStringValue:"Coins Played:"];
		[self startGame:self];
		[self dealCards];
		[self say:"Press 'Hold' button to keep cards, then 'Draw' to replace the rest."];
	}

	[drawButton setState:0];
	
	return self;
}

- hold:sender
/*
	Target of each holdButton.  Just change the image of the button.
*/
{
	if([sender state])
		[[sender setImage:holdButtonImageH] display];
	else
		[[sender setImage:holdButtonImage] display];
		
	return self;
}

- playOne:sender
/*
	Target of playOneButton.  Incremement number of coins played in coinsPlayedText
 */
{
	int coinsPlayed = [coinsPlayedText intValue];
	
	if(isFirstCoin)
	{
		coinsPlayed = 0;
		[coinPlayDepText setStringValue:"Coins Deposited:"];
		isFirstCoin = NO;
	}
	
	if([[PBoss() currentPlayer] amountInBank] < coinValue)
	{
		[PBoss() playSound:NV_WARNSOUND];
		[self say:"Can't play more coins than you have!"];
		return self;
	}
	
	if(coinsPlayed < maxCoins)
	{
		if(coinsPlayed > 0)
			[tableArea[coinsPlayed-1].button setImage:tableArea[coinsPlayed-1].image];
		[tableArea[coinsPlayed].button setImage:tableArea[coinsPlayed].imageH];
		
		[twoBeepSound play:VP_SEVOLUME pan:0.0];
		
		[coinsPlayedText setIntValue:coinsPlayed+1];
		if([creditText intValue] >= 1)
			[creditText setIntValue:[creditText intValue]-1];
		else
			[[PBoss() currentPlayer] removeChip:coinValue];
		NXPing();
		
		[drawButton setEnabled:YES];
		
		if([coinsPlayedText intValue] == maxCoins)
		{
			[maxCoinsButton setEnabled:NO];
			[[maxCoinsButton setImage:maxCoinsButtonImage] display];
			[oneCoinButton setEnabled:NO];
			[[oneCoinButton setImage:oneCoinButtonImage] display];
		}
	}
	else
	{
		[PBoss() playSound:NV_WARNSOUND];
		[self say:"Can't play more coins than max!"];
		NXPing();
	}
	
	// make sure we still have credit
	if([creditText intValue] == 0)
	{
		[cashOutButton setEnabled:NO];
		[[cashOutButton setImage:cashOutButtonImage] display];
	}
	
	[oneCoinButton setState:0];
	
	return self;
}

- playMax:sender
/*
	Target of maxCoinsButton.  Add maxCoins to coinsPlayedText, and subtract that
	amount from player's bank.
*/
{
	int coinsPlayed = [coinsPlayedText intValue];
	int	diff;
	
	if(isFirstCoin)
	{
		coinsPlayed = 0;
		[coinPlayDepText setStringValue:"Coins Deposited:"];
		isFirstCoin = NO;
	}
	
	diff = maxCoins - coinsPlayed;
	
	if([[PBoss() currentPlayer] amountInBank] < diff*coinValue)
	{
		[PBoss() playSound:NV_WARNSOUND];
		[self say:"Can't play more coins than you have!"];
		return self;
	}

	if(coinsPlayed > 0)
		[tableArea[coinsPlayed-1].button setImage:tableArea[coinsPlayed-1].image];
	[tableArea[4].button setImage:tableArea[4].imageH];
		
	[twoBeepSound play:VP_SEVOLUME pan:0.0];

	[coinsPlayedText setIntValue:maxCoins];
	if([creditText intValue] >= diff)
		[creditText setIntValue:[creditText intValue]-diff];
	else
		[[PBoss() currentPlayer] removeChip:diff*coinValue];
		
	[drawButton setEnabled:YES];
	[maxCoinsButton setEnabled:NO];
	[[maxCoinsButton setImage:maxCoinsButtonImage] display];
	[oneCoinButton setEnabled:NO];
	[[oneCoinButton setImage:oneCoinButtonImage] display];
	
	NXPing();
	
	// make sure we still have credit
	if([creditText intValue] == 0)
	{
		[cashOutButton setEnabled:NO];
		[[cashOutButton setImage:cashOutButtonImage] display];
	}
	
	[maxCoinsButton setState:0];
	
	[drawButton performClick:self];
	
	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;
}

- revertPreferences:sender
{
	coinValue = atoi(NXGetDefaultValue(VP_NAMEFORDEFAULTS, "coinValue"));

	[coinValueText setIntValue:coinValue];
	
	[self selectCellWithTag:coinValue forPopUpButton:coinValueButton];
	
	return self;
}

- setPreferences:sender
{
    static NXDefaultsVector newDefaults = {
        {"coinValue", "1"},
		{NULL, NULL}
    };
	
	coinValue = [self tagOfSelectedCellInPopUpButton:coinValueButton];

    newDefaults[0].value = alloca(256);

	sprintf(newDefaults[0].value, "%d", coinValue);

    NXWriteDefaults(VP_NAMEFORDEFAULTS, newDefaults);
    
	return self;
}
/***************************************************************************************
 *                                  Player Methods                                     *
 ***************************************************************************************/
- (int)collectAllBetsForPlayer:(int)playerNum
{
	if([cashOutButton isEnabled])
	{
		[PBoss() setCurrentPlayer:[PBoss() playerAt:playerNum]];
		[self cashOut:self];
	}
	
	return 0;
}

- 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 endGame:self];
	
	return self;
}

- playerDidJoin:player
{
	if(!handInProgress)
		[self endGame:self];
	
	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;
}


/***************************************************************************************
 *                               Other Misc. Methods                                   *
 ***************************************************************************************/
- fastFlash
/*
	Toggle images for the buttons, if they are enabled.
*/
{
	int i;
	id	image;
	
	image = (isHighlight) ? holdButtonImage : holdButtonImageH;
	for(i=0; i<VP_NUMCARDS; i++)
	{
		if([cardField[i].button isEnabled] && ![cardField[i].button state])
			[[cardField[i].button setImage:image] display];
	}
	
	image = (isHighlight) ? oneCoinButtonImage : oneCoinButtonImageH;
	if([oneCoinButton isEnabled] && ![oneCoinButton state])
		[[oneCoinButton setImage:image] display];

	image = (isHighlight) ? maxCoinsButtonImage : maxCoinsButtonImageH;
	if([maxCoinsButton isEnabled] && ![oneCoinButton state])
		[[maxCoinsButton setImage:image] display];

	image = (isHighlight) ? drawButtonImage : drawButtonImageH;
	if([drawButton isEnabled] && ![drawButton state])
		[[drawButton setImage:image] display];

	image = (isHighlight) ? cashOutButtonImage : cashOutButtonImageH;
	if([cashOutButton isEnabled] && ![cashOutButton state])
		[[cashOutButton setImage:image] display];

	isHighlight = (isHighlight) ? NO : YES ;
	
	return self;
}

- 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.
*/
{
	if(fastFlashTE)
		DPSRemoveTimedEntry(fastFlashTE);
	fastFlashTE = 0;
	
	[self setPreferences:self];

	return self;
}

- view:aView wasLoadedOnTable:tableObject
{
	[super view:aView wasLoadedOnTable:tableObject];
	
	// timed entry for button flashing
	fastFlashTE = DPSAddTimedEntry(.35, (DPSTimedEntryProc)VPfastFlashHandler, self, NX_BASETHRESHOLD);
	
	[self say:"Welcome to VideoPoker!  Place Your Bets!"];
	
	return self;
}

/***************************************************************************************
 *                                Debugging Methods                                    *
 ***************************************************************************************/
- getNextCard:sender
{
	int pos = [sender tag];
	id nextCard;
 	
	[cardField[pos].pile empty];
	nextCard = [deckPile cardAt:CS_TOP];
	[nextCard setFaceUp:YES];
	[cardField[pos].pile addCard:nextCard];
	[deckPile removeCard:nextCard];
	[cardField[pos].view display];
	
	return self;
}

- checkHand:sender
{
	[self checkForWin];
	
	return self;
}

- cardValues:sender
{
	int i;
	
	for(i=0; i<5; i++)
	{
		fprintf(stderr, "(%d, %d) ", [[cardField[i].pile cardAt:CS_TOP] value],
			[[cardField[i].pile cardAt:CS_TOP] userValue]);
	}
	fprintf(stderr, "\n");
	
	return self;
}

- clickedCard:aCard in:aCardPileView
/*
	This is a delegate method from CardPileView
*/
{
	if(aCard != nil)
	{
		int tag = [aCardPileView tag];
		
		[cardField[tag].button performClick:self];
		
	}
	
	return self;
}

- getOffset:(float *)xOffset :(float *)yOffset
{
	*xOffset = 0.0;
	*yOffset = 0.0;
	
	return self;
}
 
@end

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.