This is PitBoss.m in view mode; [Download] [Up]
#import "PitBoss.h" #import "MiscMailApp-WStrings.h" static id _PitBoss; #define NV_WELCOMETEXT "Welcome High Roller! Choose your game..." // Handle to the this object extern id PBoss(void) { return _PitBoss; } // Handle to the current module's controlling object extern id Dealer(void) { return [_PitBoss dealer]; } static id _PrefController; extern id Prefs(void) { return _PrefController; } @implementation PitBoss + initialize { static NXDefaultsVector ourDefaults = { {"houseMin", "2"}, {"houseMax", "500"}, {"soundOn", "1"}, {"PlayerDir", "/LocalLibrary/NEXTVegas/Players"}, {"gameType", "Blackjack"}, {"openLast", "0"}, {"openLastPlayer", "0"}, {"lastPlayer", ""}, {NULL, NULL} }; NXRegisterDefaults([NXApp appName], ourDefaults); return self; } - appWillInit:sender { _PitBoss = self; welcomeView = [tableView contentView]; [[OpenPanel new] setDirectory:NXGetDefaultValue([NXApp appName], "PlayerDir")]; [[SavePanel new] setDirectory:NXGetDefaultValue([NXApp appName], "PlayerDir")]; [casino loadBrowser:self]; [self setCurrentPlayer:nil]; [self setHouseMin:atoi(NXGetDefaultValue([NXApp appName], "houseMin"))]; [self setHouseMax:atoi(NXGetDefaultValue([NXApp appName], "houseMax"))]; [SoundEffect setSoundEnabled:YES]; soundEnabled = YES; [SoundEffect setMaxSoundStreams:MAX_SOUNDS]; soundEffect[NV_WINSOUND] = [[SoundEffect allocFromZone:[self zone]] initFromSection:WINSOUND]; soundEffect[NV_LOSESOUND] = [[SoundEffect allocFromZone:[self zone]] initFromSection:LOSESOUND]; soundEffect[NV_WARNSOUND] = [[SoundEffect allocFromZone:[self zone]] initFromSection:WARNSOUND]; soundEffect[NV_CHIPSOUND] = [[SoundEffect allocFromZone:[self zone]] initFromSection:CHIPSOUND]; soundEffect[NV_REMOVECHIPSOUND] = [[SoundEffect allocFromZone:[self zone]] initFromSection:REMOVECHIPSOUND]; soundEffect[NV_CARDSOUND] = [[SoundEffect allocFromZone:[self zone]] initFromSection:CARDSOUND]; soundEffect[NV_SHUFFLESOUND] = [[SoundEffect allocFromZone:[self zone]] initFromSection:SHUFFLESOUND]; return self; } - appDidInit:sender { BOOL openNewPlayer = YES; pMenu[0] = pmenu1; pMenu[1] = pmenu2; pMenu[2] = pmenu3; pMenu[3] = pmenu4; [dealerText setStringValue:NV_WELCOMETEXT]; [table orderFront:self]; if(atoi(NXGetDefaultValue([NXApp appName], "openLast"))) [casino openLastModule]; // If we should open last player if(atoi(NXGetDefaultValue([NXApp appName], "openLastPlayer")) && strcmp(NXGetDefaultValue([NXApp appName], "lastPlayer"), "") != 0 && strstr(NXGetDefaultValue([NXApp appName], "lastPlayer"), PFILE_EXTENSION) != NULL) { [self addPlayerFromFile:NXGetDefaultValue([NXApp appName], "lastPlayer")]; openNewPlayer = NO; } if(numPlayers == 0 && openNewPlayer) [self newPlayer:self]; return self; } /********************************************************************************** * Player Methods * **********************************************************************************/ - newPlayer:sender /* Create a new player if we have less than MAX_PLAYERS open already. New players must do the following to be created: 1. Specify their name 2. Select a PIN 3. Specify a file to save to If any of these things are canceled, this method returns nil and a new player isn't created. */ { int nextSlot = [self nextPlayerSlot]; char buf[100]; id playerWindow; NXRect winframe; // if we've exceeded MAX_PLAYERS, don't create new player if(nextSlot == MAX_PLAYERS) { [self playSound:NV_WARNSOUND]; [dealerText setStringValue:"Too many players open already!"]; return nil; } // make sure its okay with the dealer to add a player at this time if(dealer && ![dealer playerWillJoin:self]) return nil; if(!newPlayerNameWindow) { [NXApp loadNibSection:"newPlayerName.nib" owner:self]; } sprintf(buf, "Player%d", nextSlot+1); [newPlayerNameText setStringValue:buf]; [newPlayerNameText selectText:self]; // start a modal window to get the player's name, return nil if aborted if([NXApp runModalFor:newPlayerNameWindow] == NX_RUNABORTED) { [newPlayerNameWindow orderOut:self]; return nil; } [newPlayerNameWindow orderOut:self]; [NXApp loadNibSection:"player.nib" owner:self]; [newPlayer setPName:[newPlayerNameText stringValue]]; // Get the PIN for the new player. If not successful, return nil. if([self runATMForPlayer:newPlayer pinOnly:NO] == nil) { //[self playSound:NV_WARNSOUND]; NXBeep(); [dealerText setStringValue:"Can't create a player without a PIN!"]; [newPlayer free]; newPlayer = nil; return nil; } // Get the save file for the new player. If not successful, return nil. if([self savePlayer:newPlayer] == nil) { [newPlayer free]; newPlayer = nil; return nil; } // Make player's file readable by everyone... sprintf(buf, "chmod a+r,a+w %s", [newPlayer saveFile]); system(buf); // Place the new player's window playerWindow = [newPlayer window]; [playerWindow getFrame:&winframe]; NX_X(&winframe) += ((float)nextSlot*96.0); NX_Y(&winframe) -= ((float)nextSlot*24.0); [playerWindow makeKeyAndOrderFront:self]; // add newPlayer to our playerList numPlayers++; playerList[nextSlot] = newPlayer; //[[pMenu[nextSlot] setTitle:[newPlayer playerName]] setEnabled:YES]; [self updatePlayerMenuAt:nextSlot]; // Notify the dealer that a new player has joined [dealer playerDidJoin:newPlayer]; newPlayer = nil; return self; } - addPlayerIfNecessary /* Add a new player if we don't have any open at the moment */ { if(numPlayers == 0) [self newPlayer:self]; return self; } - addPlayerFromFile:(const char *)filename /* Open a player file and load it. Players must be able to specify their PIN in order for the file to be opened and usable by the player. If not, then the file is closed and the new player isn't created, and nil is returned. */ { NXTypedStream *typedStream; int nextPlayerNum, i; // Make sure file isn't open already for(i=0; i<MAX_PLAYERS; i++) { if(playerList[i] != nil && strcmp(filename, [playerList[i] saveFile]) == 0) { // file was already opened, so bring it to the front. [[playerList[i] window] makeKeyAndOrderFront:self]; return nil; } } if([NXApp loadNibSection:"player.nib" owner:self] == nil) { return nil; } typedStream = NXOpenTypedStreamForFile(filename, NX_READONLY); if(typedStream == NULL) { NXRunAlertPanel("File i/o Error", "Unable to open typed stream for file: %s", "Okay", NULL, NULL, filename); return nil; } [newPlayer loadFromTypedStream:typedStream]; NXCloseTypedStream(typedStream); // verify that this is the new player by asking them for their PIN if([self runATMForPlayer:newPlayer pinOnly:YES] == nil) { //[self playSound:NV_WARNSOUND]; NXBeep(); [dealerText setStringValue:"Can't open player without a PIN"]; [newPlayer free]; // if this file is the lastOpenedPlayer that we're trying to load, // since the user canceled, we'll remove the lastPlayer default... // (I'm not sure if this is a good thing to do...) if(strcmp(NXGetDefaultValue([NXApp appName], "lastPlayer"), filename) == 0) { NXWriteDefault([NXApp appName], "lastPlayer", ""); } return nil; } nextPlayerNum = [self nextPlayerSlot]; [newPlayer setSaveFile:filename isFirstTime:NO]; [[newPlayer window] setDocEdited:NO]; [[newPlayer window] makeKeyAndOrderFront:self]; [newPlayer setTag:nextPlayerNum]; playerList[nextPlayerNum] = newPlayer; numPlayers++; //[[pMenu[nextPlayerNum] setTitle:[newPlayer playerName]] setEnabled:YES]; [self updatePlayerMenuAt:nextPlayerNum]; NXWriteDefault([NXApp appName], "lastPlayer", filename); [dealer playerDidJoin:newPlayer]; newPlayer = nil; return self; } - currentPlayer { return currentPlayer; } - (char *)nameOfPlayer:(int)playerNum { return [playerList[playerNum] playerName]; } - (int)nextPlayerSlot /* Returns the next available slot in playerList */ { int i; for(i=0; i<MAX_PLAYERS; i++) { if(playerList[i] == nil) return i; } return MAX_PLAYERS; } - (int)numPlayers { return numPlayers; } - openPlayer:sender /* Target of "Open Player" menu item. Bring up open panel to get the file to load, then call addPlayerFromFile to actually do the loading. */ { char *types[2] = {"nvp", 0}; id panel; const char *fileToLoad; if(numPlayers == MAX_PLAYERS) { [self playSound:NV_WARNSOUND]; [dealerText setStringValue:"Too many players open already!"]; return nil; } if(dealer && ![dealer playerWillJoin:self]) return nil; panel = [OpenPanel new]; [panel setTitle:"Load Player..."]; if([panel runModalForTypes:types]) { fileToLoad = [panel filename]; } else return nil; if([self addPlayerFromFile:fileToLoad] == nil) return nil; return self; } - playerAt:(int)tag /* Returns the id of the player at tag. */ { return playerList[tag]; } - removePlayer:sender /* Removes the player from the game... sender is either a player or the "Remove Player" menu cell. If sender is the menu cell, then we remove the current player, else we remove sender. */ { id playerToRemove; int playerTag; playerToRemove = ([sender isKindOf:[Player class]]) ? sender : currentPlayer; playerTag = [playerToRemove tag]; if([[playerToRemove window] isDocEdited]) [self savePlayer:playerToRemove]; playerList[playerTag] = nil; [[playerToRemove window] orderOut:self]; [dealer playerDidClose:playerToRemove]; if(playerToRemove == currentPlayer) { [currentPlayerText setStringValue:"No Current Player"]; currentPlayer = nil; } [playerToRemove free]; numPlayers--; //[[pMenu[playerTag] setTitle:"Closed"] setEnabled:NO]; [self updatePlayerMenuAt:playerTag]; return self; } - savePlayer:sender /* Sender is either the player to save or the "Save Player" menu cell. If sender is the menu cell, then we save the current player, else we save sender. */ { char *playerFile; NXTypedStream *typedStream; id playerToSave; playerToSave = ([sender isKindOf:[Player class]]) ? sender : currentPlayer; playerFile = [playerToSave saveFile]; if(playerFile == NULL) return [self savePlayerAs:playerToSave]; typedStream = NXOpenTypedStreamForFile(playerFile, NX_WRITEONLY); if(typedStream == NULL) { NXRunAlertPanel("File i/o Error", "Unable to open typed stream for file: %s", "Okay", NULL, NULL, playerFile); return nil; } [playerToSave saveToTypedStream:(NXTypedStream *)typedStream]; NXCloseTypedStream(typedStream); [[playerToSave window] setDocEdited:NO]; return self; } - savePlayerAs:sender /* Gets a new file name to save the player under. Then calls savePlayer to actually do the saving. */ { SavePanel *panel; const char *dir; char *file, *playerFile; id playerToSave; playerToSave = ([sender isKindOf:[Player class]]) ? sender : currentPlayer; /* prompt user for file name and save to that file */ panel = [SavePanel new]; playerFile = [playerToSave saveFile]; if(playerFile == 0) { /* no playerFile; set up defaults */ dir = [panel directory]; file = [playerToSave playerName]; } else { file = rindex(playerFile, '/'); if(file) { dir = playerFile; *file = 0; file++; } else { dir = playerFile; file = [playerToSave playerName]; } } [panel setTitle:"Save Player..."]; [panel setRequiredFileType: "nvp"]; if([panel runModalForDirectory:dir file:file] == NX_OKTAG) { [playerToSave setSaveFile:[panel filename] isFirstTime:YES]; return [self savePlayer:playerToSave]; } return nil; } - setCurrentPlayer:player { currentPlayer = player; if(currentPlayer == nil) [currentPlayerText setStringValue:"No Current Player"]; else { [currentPlayerText setStringValue:[currentPlayer playerName]]; } return self; } - changeCurrentPlayer:sender { [[playerList[[[sender selectedCell] tag]] window] makeKeyAndOrderFront:self]; return self; } /********************************************************************************** * ATM Methods * **********************************************************************************/ - runATM:sender { if(currentPlayer == nil) return nil; return [self runATMForPlayer:currentPlayer pinOnly:NO]; } - runATMForPlayer:aPlayer pinOnly:(BOOL)flag { if(!atm) { [NXApp loadNibSection:"atm.nib" owner:self]; } if(flag) { if(![atm getPINOnlyFor:aPlayer]) return nil; } else { return [atm runATMFor:aPlayer]; } return self; } /********************************************************************************** * Game Methods * **********************************************************************************/ - newGame:controller named:(const char *)gamename /* Sender is the Casino object when it has successfully loaded a game module. Controller is the "dealer" object for the module. */ { id gameView = [controller gameView]; dealer = controller; [dealer setTableMax:atoi(NXGetDefaultValue([NXApp appName], "houseMax"))]; [dealer setTableMin:atoi(NXGetDefaultValue([NXApp appName], "houseMin"))]; [self insertGameView:gameView]; [table setTitle:gamename]; if([dealer hasRules]) [rulesMenuCell setEnabled:YES]; if([dealer inspector:self]) [prefController allowModuleInspector:YES]; [tableView display]; [dealer view:gameView wasLoadedOnTable:table]; return self; } - closeGame:sender { return [self closeGameAndBringBackWelcome:YES]; } - closeGameAndBringBackWelcome:(BOOL)flag { [rulesMenuCell setEnabled:NO]; [dealer finishSessionAndClose]; dealer = nil; if(flag) { [casino moduleWasClosed]; [prefController allowModuleInspector:NO]; [self insertGameView:welcomeView]; } [table setTitle:"NEXTVegas"]; [dealerText setStringValue:NV_WELCOMETEXT]; [tableView display]; return self; } - insertGameView:gameView /* Inserts gameView into tableView, and centers it. */ { NXRect boxRect, viewRect; [tableView getFrame:&boxRect]; [gameView getFrame:&viewRect]; [tableView setContentView:gameView]; NX_X(&viewRect) = (NX_WIDTH(&boxRect) - NX_WIDTH(&viewRect)) / 2.0; NX_Y(&viewRect) = (NX_HEIGHT(&boxRect) - NX_HEIGHT(&viewRect)) / 2.0; [gameView setFrame:&viewRect]; return self; } - (BOOL)gameWillLoad:(const char *)gamename /* Sender is the Casino object, just before it loads a game. */ { char buf[512]; sprintf(buf, "Loading %s....", gamename); [table setTitle:buf]; return YES; } /********************************************************************************** * Sound * **********************************************************************************/ - (int)addSoundFromSection:(char *)soundfile /* Create a new SoundEffect instance for the file soundfile. Store its id in soundEffect array. Return its index in soundEffect, or SOUNDEFFECT_ERROR if it couldn't be created. */ { int i; for(i=0; i<MAX_SOUNDS; i++) { if(soundEffect[i] == nil) { soundEffect[i] = [[SoundEffect allocFromZone:[self zone]] initFromSection:soundfile]; if(soundEffect[i] == nil) return SOUNDEFFECT_ERROR; else return i; } } return SOUNDEFFECT_ERROR; } - playSound:(int)index /* Play the SoundEffect stored in soundEffect at index. */ { if(soundEnabled) [soundEffect[index] play:1.0 pan:0.0]; return self; } - removeSound:(int)index { [soundEffect[index] free]; soundEffect[index] = nil; return self; } - setSoundEnabled:(BOOL)flag { soundEnabled = flag; return self; } - (BOOL)soundEnabled { return soundEnabled; } /********************************************************************************** * Misc. Methods * **********************************************************************************/ - (BOOL)appIsTerminating { return appIsTerminating; } - dealer { return dealer; } - dealerText { return dealerText; } - currentPlayerText { return currentPlayerText; } - endModal:sender { if([[sender selectedCell] tag] == SET) [NXApp stopModal]; else [NXApp abortModal]; return self; } - help:sender { return self; } - preferences:sender { if(!prefController) { [NXApp loadNibSection:"preferences.nib" owner:self]; } [[prefController window] makeKeyAndOrderFront:self]; _PrefController = prefController; return self; } - showInfo:sender { if(!infoPanel) { [NXApp loadNibSection:"info.nib" owner:self]; } [infoPanelVersionText setStringValue:NV_CURRENTVERSIONTEXT]; [infoPanel makeKeyAndOrderFront:self]; return self; } - showRules:sender { [[dealer rulesWindow] makeKeyAndOrderFront:self]; return self; } - setHouseMin:(int)aNumber { char buf[100]; houseMin = aNumber; sprintf(buf, "House Minimum: $%d", houseMin); [houseMinText setStringValue:buf]; return self; } - setHouseMax:(int)aNumber { char buf[100]; houseMax = aNumber; sprintf(buf, "House Maximum: $%d", houseMax); [houseMaxText setStringValue:buf]; return self; } - suggestions:sender { MiscMailApp *mailer = [MiscMailApp localMailer]; char buf[64]; sprintf(buf, "NEXTVegas version %s", NV_CURRENTVERSIONTEXT); [mailer sendStringMailTo:"trombino@wendy.ucsd.edu" subject:buf body:"Hey Mark,\n\nNice game, but...\n\n"]; [NXApp deactivateSelf]; return self; } - (int)houseMin { return houseMin; } - (int)houseMax { return houseMax; } - tableWindow { return table; } - tableView { return [tableView contentView]; } - (float)NVVersion { return NV_CURRENTVERSION; } - updatePlayerMenus { int i; for(i=0; i<MAX_PLAYERS; i++) [self updatePlayerMenuAt:i]; return self; } - updatePlayerMenuAt:(int)playerNum { id player = playerList[playerNum]; if(player) [[pMenu[playerNum] setTitle:[player playerName]] setEnabled:YES]; else [[pMenu[playerNum] setTitle:"Closed"] setEnabled:NO]; return self; } @end /********************************************************************************** * Delegate Methods * **********************************************************************************/ @implementation PitBoss (ApplicationDelegate) - (BOOL)appAcceptsAnotherFile:sender { _PitBoss = self; return YES; } - (int)app:sender openFile:(const char *)filename type:(const char *)aType { _PitBoss = self; if(strcmp(aType, PFILE_EXTENSION) == 0) { if(numPlayers == MAX_PLAYERS) return NO; if(dealer && ![dealer playerWillJoin:self]) return NO; if([self addPlayerFromFile:filename]) return YES; else return NO; } return NO; } - appWillTerminate:sender { int i; appIsTerminating = YES; [dealer finishSessionAndClose]; for(i=0; i<MAX_PLAYERS; i++) if(playerList[i]) [self removePlayer:playerList[i]]; return self; } - appDidBecomeActive:sender { int i; [table orderFront:self]; for(i=0; i<MAX_PLAYERS; i++) { if(playerList[i]) [[playerList[i] window] orderFront:self]; } return self; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.