This is SplatApp.m in view mode; [Download] [Up]
/*
* SplatApp
* description: subclass of EKApplication - keeps track of the main UI
* components and application flow
* history:
* 5/1/93 [Erik Kay] - converted much of the SplatController to here
* 6/8/93 [Erik Kay] - cleaned up some of the file opening code
*/
#import "SplatApp.h"
#import "SplatGame.h"
#import "SplatDefaults.h"
#import "Board.h"
#import "ComputerPlayer.h"
#import "HumanPlayer.h"
#import "NetworkPlayer.h"
#import <sys/dir.h>
#define COMP_EXTENSION "scplayer"
@implementation SplatApp
- challenge:sender
{
int exitValue;
id panel;
DPSContext newcontext, oldcontext;
NXHandler handler;
newcontext = DPSCreateContext("drool",0,0,0);
oldcontext = context;
context = newcontext;
DPSSetContext(newcontext);
panel = NXGetAlertPanel
("Splat Challenge",
"Erik is challenging you to a game of Splat. Do you accept?",
"OK","Cancel",NULL);
[panel center];
[panel makeKeyAndOrderFront:self];
NX_DURING {
handler.code = 0;
exitValue = [NXApp runModalFor:panel];
} NX_HANDLER {
handler = NXLocalHandler;
if (handler.code == dps_err_ps) NXReportError((NXHandler *)(&handler));
} NX_ENDHANDLER
[panel orderOut:self];
context = oldcontext;
DPSSetContext([NXApp context]);
return self;
}
/*
* setup and new game initialization
*/
+ new
{
self = [super new];
[self setDelegate:self]; //? we're our own delegate... duh!
// setup resources that I want to be preloaded
[self addImageResource:"one"];
[self addImageResource:"two"];
[self addImageResource:"obstruction"];
[self addImageResource:"smallone"];
[self addImageResource:"smalltwo"];
[self addSoundResource:"move"];
[self addSoundResource:"change"];
[self addSoundResource:"bigChange"];
[self addSoundResource:"wowChange"];
[self addSoundResource:"gameOver"];
[self addSoundResource:"win"];
return self;
}
- appDidInit:sender
{
NXRect f1, f2;
int i;
id button, matrix, popup;
char path[MAXPATHLEN], boardPath[MAXPATHLEN];
const char *tmp;
[defaultsManager loadDefaults];
// load the computer players
[self loadComputerStrategies];
// board file initialization
tmp = [[NXBundle mainBundle] directory];
sprintf(path,"%s/boards",tmp);
boardBundle = [[NXBundle alloc] initForDirectory:path];
strcpy(boardPath,[defaultsManager boardPath]);
// initialize the mini board
[miniSplatBoard setScalable:YES];
[miniSplatBoard setBoard:[Board newFromFile:boardPath]];
// games
games = [[List alloc] init];
// load resources
[self loadResources];
// setup the "new game setup" panel
player1CurrentView = player1NewHuman;
player2CurrentView = player2NewComputer;
[player1NewGame getFrame:&f1];
[player2NewGame getFrame:&f2];
[player1CurrentView setFrame:&f1];
[player2CurrentView setFrame:&f2];
[[player1NewGame superview] replaceSubview:player1NewGame
with:player1CurrentView];
[[player2NewGame superview] replaceSubview:player2NewGame
with:player2CurrentView];
[player1CurrentView display];
[player2CurrentView display];
[newGamePanel flushWindow];
//? initialize all of the popups properly
//? This is a hack to workaround bug #35247
//? basically, popup matrices aren't initialized properly (they don't have
//? a selected cell unless the user selects something), so the we have to
//? do the initialization manually. Note that all popup connections are
//? also being set equal to their matrices since all future operations will
//? be with the matrices themselves. the variable name is a little
//? confusing for this and perhaps we should have additional variables for
//? the matrices
button = player1TypePopup;
popup = [button target];
matrix = [popup itemList];
[matrix selectCellAt:[popup indexOfItem:[button title]] :0];
player1TypePopup = matrix;
button = player2TypePopup;
popup = [button target];
matrix = [popup itemList];
[matrix selectCellAt:[popup indexOfItem:[button title]] :0];
player2TypePopup = matrix;
button = player1SearchDepth;
popup = [button target];
matrix = [popup itemList];
[matrix selectCellAt:[popup indexOfItem:[button title]] :0];
player1SearchDepth = matrix;
button = player2SearchDepth;
popup = [button target];
matrix = [popup itemList];
[matrix selectCellAt:[popup indexOfItem:[button title]] :0];
player2SearchDepth = matrix;
button = player1CompPopup;
popup = [button target];
matrix = [popup itemList];
[matrix selectCellAt:[popup indexOfItem:[button title]] :0];
player1CompPopup = popup;
button = player2CompPopup;
popup = [button target];
matrix = [popup itemList];
[matrix selectCellAt:[popup indexOfItem:[button title]] :0];
player2CompPopup = popup;
// add the different strategies to the popup list for new game selection
for (i = 0; i < [computerStrategies count]; i++) {
[[player1CompPopup addItem: [[computerStrategies objectAt:i] strategyName]] setTag:i];
[[player2CompPopup addItem: [[computerStrategies objectAt:i] strategyName]] setTag:i];
}
player1CompPopup = [player1CompPopup itemList];
player2CompPopup = [player2CompPopup itemList];
[player1HumanName setStringValue:[defaultsManager defaultPlayerName]];
[player2HumanName setStringValue:[defaultsManager defaultPlayerName]];
[newGamePanel makeKeyAndOrderFront:self];
return self;
}
- initializePlayersForGame:game
{
id item, player, strategy, rules;
int tag;
rules = [game rules];
item = [player1TypePopup selectedCell];
tag = [item tag];
switch (tag) {
case 0: /* Human */
player = [[HumanPlayer alloc] initWithRules:rules andPieceType:SQUARE_ONE];
[player setPlayerName:[player1HumanName stringValue]];
break;
case 1: /* Computer */
strategy = [computerStrategies objectAt:[[player1CompPopup selectedCell] tag]];
player = [[strategy alloc] initWithRules:rules andPieceType:SQUARE_ONE];
[player setSearchDepth:[[player1SearchDepth selectedCell] tag]];
break;
case 2: /* Network */
default:
player = [[NetworkPlayer alloc] initWithRules:rules andPieceType:SQUARE_ONE];
[player setHostname:[player1NetHostname stringValue]];
break;
}
[game setPlayer1:player];
item = [player2TypePopup selectedCell];
tag = [item tag];
switch (tag) {
case 0: /* Human */
player = [[HumanPlayer alloc] initWithRules:rules andPieceType:SQUARE_TWO];
[player setPlayerName:[player2HumanName stringValue]];
break;
case 1: /* Computer */
strategy = [computerStrategies objectAt:[[player2CompPopup selectedCell] tag]];
player = [[strategy alloc] initWithRules:rules andPieceType:SQUARE_TWO];
[player setSearchDepth:[[player2SearchDepth selectedCell] tag]];
break;
case 2: /* Network */
default:
player = [[NetworkPlayer alloc] initWithRules:rules andPieceType:SQUARE_TWO];
[player setHostname:[player2NetHostname stringValue]];
break;
}
[game setPlayer2:player];
return self;
}
/*
* dynamically loaded computer strategies
*/
- loadComputerStrategies
{
DIR *dir;
struct direct *dir_entry;
const char *path;
char *filename, *suffix;
computerStrategies = [[List alloc] init];
path = [[NXBundle mainBundle] directory];
dir = opendir(path);
if (dir) {
while (dir_entry = readdir(dir)) {
filename = dir_entry->d_name;
if ((strcmp(filename,".") == 0) || (strcmp(filename,"..") == 0))
continue;
suffix = rindex(filename,'.');
if (!suffix ||
(strcmp(suffix,".cplayer") && strcmp(suffix,".bundle")))
continue;
[self loadComputer:filename];
}
closedir(dir);
}
return self;
}
- loadComputer:(const char *)name
{
char path[MAXPATHLEN], cname[256];
id newBundle, comp;
sprintf(path,"%s/%s",[[NXBundle mainBundle] directory],name);
newBundle = [[NXBundle alloc] initForDirectory:path];
strcpy(path,name);
*(rindex(path,'.')) = '\0';
sprintf(cname,"%sComp",path);
comp = [newBundle classNamed:cname];
if ([computerStrategies indexOf:comp] != NX_NOT_IN_LIST)
return comp; // this one has already been loaded
[computerStrategies addObject:comp];
return comp;
}
/*
* the board... opening a new board file, etc.
*/
- openBoard:sender
{
static id openPanel = nil;
const char *theType = BOARD_EXTENSION, *filename;
char const *fileTypes[2] = {0,0};
static char boardDir[MAXPATHLEN] = {'\0'};
int opr;
char *ptr;
if (!boardDir[0])
strcpy(boardDir,[boardBundle directory]);
if (!openPanel)
openPanel = [OpenPanel new];
if (theType && *theType)
fileTypes[0] = theType;
[NXApp setAutoupdate:NO];
opr = [openPanel runModalForDirectory:boardDir
file:NULL types:fileTypes];
if (opr) {
filename = [openPanel filename];
[self loadBoard:filename];
strcpy(boardDir,filename);
ptr = rindex(boardDir,'/');
if (ptr)
*ptr = '\0';
} else {
[NXApp setAutoupdate:YES];
return self;
}
return self;
}
- loadBoard:(const char *)path
{
id oldBoard, newBoard;
oldBoard = [miniSplatBoard board];
newBoard = [Board newFromFile:path];
[miniSplatBoard setScalable:YES];
[miniSplatBoard setBoard:newBoard];
[oldBoard free];
[NXApp setAutoupdate:YES];
return self;
}
- (BOOL)appAcceptsAnotherFile:sender
{
return YES;
}
- (int)app:sender openFile:(const char *)filename type:(const char *)aType
{
if (!strcmp(aType,BOARD_EXTENSION))
[self loadBoard:filename];
else if (!strcmp(aType,COMP_EXTENSION))
[self loadComputer:filename];
else
return NO;
return YES;
}
/*
* selecting a new game setup
*/
- newGame:sender
{
id rules, game, board;
[newGamePanel close];
[newGameCancel setEnabled:YES];
rules = [[SplatRules alloc] init];
game = [[SplatGame alloc] init];
[game setRules:rules];
[game setGameState:NO_GAME];
board = [[miniSplatBoard board] trueCopy];
[game setBoard:board];
[board free];
[self initializePlayersForGame:game];
if (![game initNetPlayers]) {
[game free];
return self;
}
//? must do this to prevent deadlock
if (![[game player1] isKindOf:[NetworkPlayer class]])
[game showGame];
currentGame = game;
return self;
}
- cancelNewGame:sender
{
[newGamePanel close];
return self;
}
- setPlayer1Type:sender
{
id menu, newView;
NXRect f;
int tag;
menu = [sender selectedCell];
tag = [menu tag];
switch (tag) {
case 0: /* Human */
newView = player1NewHuman;
break;
case 1: /* Computer */
newView = player1NewComputer;
break;
case 2: /* Network */
newView = player1NewNetwork;
break;
default: /* error */
fprintf (stderr,"Splat: unknown player type selected: %d\n",tag);
return self;
break;
}
[[player1CurrentView superview] replaceSubview:player1CurrentView
with:newView];
player1CurrentView = newView;
[player1NewGame getFrame:&f];
[player1CurrentView setFrame:&f];
[newView display];
return self;
}
- setPlayer2Type:sender
{
id menu, newView;
NXRect f;
int tag;
menu = [sender selectedCell];
tag = [menu tag];
switch (tag) {
case 0: /* Human */
newView = player2NewHuman;
break;
case 1: /* Computer */
newView = player2NewComputer;
break;
case 2: /* Network */
newView = player2NewNetwork;
break;
default: /* error */
fprintf (stderr,"Splat: unknown player type selected: %d\n",tag);
return self;
break;
}
[[player2CurrentView superview] replaceSubview:player2CurrentView
with:newView];
player2CurrentView = newView;
[player2NewGame getFrame:&f];
[player2CurrentView setFrame:&f];
[newView display];
return self;
}
//
// control the current game
//
- pauseGame:sender
{
[currentGame pauseGame:sender];
return self;
}
- stopGame:sender
{
[currentGame stopGame:sender];
return self;
}
- startGame:sender
{
[currentGame stopGame:sender];
[currentGame startGame:sender];
return self;
}
//
// delegate methods
//
- appWillTerminate:sender
{
[defaultsManager writeDefaults];
return self;
}
@end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.