This is SplatGame.m in view mode; [Download] [Up]
/*
* SplatGame
* description: implementation of the SplatGame class
* a class to keep track of the state of a splat game instance
* history:
* 5/1/93 [Erik Kay] - converted much of the SplatController to here
* 6/8/93 [Erik Kay] - better network support
*/
#import "SplatView.h"
#import "SplatGame.h"
#import "SplatApp.h"
#import "SplatDefaults.h"
#import "HumanPlayer.h"
#import "ComputerPlayer.h"
#import "NetworkPlayer.h"
#import "PieceView.h"
@implementation SplatGame
- init
{
[super init];
// load the nib
[NXApp loadNibSection:"Board.nib" owner:self withNames:NO];
// set up the server to talk to the other threads....
myConnection = [NXConnection registerRoot:self];
[myConnection runFromAppKit];
threadPort = [myConnection inPort];
return self;
}
- free
{
move_list *list;
[super free];
[player1 free];
[player2 free];
[myConnection free];
[rules free];
[board free];
[boardWindow free];
[origBoard free];
list = &moves;
while (list->next) {
list = list->next;
free(list->prev);
}
return self;
}
- (NXPort *)inPort
{
return threadPort;
}
- awakeFromNib
{
[player1ColorView setImage:[NXImage findImageNamed:"smallone"]];
[player2ColorView setImage:[NXImage findImageNamed:"smalltwo"]];
return self;
}
- showPlayerNames
{
char name[64];
if ([player1 isKindOf:[HumanPlayer class]]) {
sprintf(name,"%s",[player1 playerName]);
[player1Name setStringValue:name];
} else if ([player1 isKindOf:[ComputerPlayer class]]) {
sprintf(name,"Computer\n%s",[player1 playerName]);
[player1Name setStringValue:name];
} else {
/* network player */
sprintf(name,"%s\n@%s",[player1 playerName],[player1 hostname]);
[player1Name setStringValue:name];
}
if ([player2 isKindOf:[HumanPlayer class]]) {
sprintf(name,"%s",[player2 playerName]);
[player2Name setStringValue:name];
} else if ([player2 isKindOf:[ComputerPlayer class]]) {
sprintf(name,"Computer\n%s",[player2 playerName]);
[player2Name setStringValue:name];
} else {
/* network player */
sprintf(name,"%s\n@%s",[player2 playerName],[player2 hostname]);
[player2Name setStringValue:name];
}
return self;
}
- showGame
{
[self showPlayerNames];
[self initGame];
if (board) {
[boardWindow display];
[boardView redrawBoard]; // need to do this manually here
[boardWindow flushWindow];
[boardWindow center];
[boardWindow makeKeyAndOrderFront:self];
}
if ([player1 isKindOf:[ComputerPlayer class]])
[self pauseGame:nil];
else
[self startGame:nil];
return self;
}
- initNetPlayers
{
int res;
NXModalSession session;
id alert;
if ([player1 isKindOf:[NetworkPlayer class]]) {
alert = NXGetAlertPanel("Network Splat",
"Trying to connect to remote Splat server...",
"Cancel",NULL,NULL);
[alert center];
[alert makeKeyAndOrderFront:self];
[player1 connectToServer];
[NXApp beginModalSession:&session for:alert];
for (;;) {
if ((res = [NXApp runModalSession:&session]) != NX_RUNCONTINUES)
return nil;
if ([player1 isConnected])
break;
}
[NXApp endModalSession:&session];
[alert close];
} else if ([player2 isKindOf:[NetworkPlayer class]]) {
alert = NXGetAlertPanel("Network Splat",
"Waiting for connection from Splat client...",
"Cancel",NULL,NULL);
[alert center];
[alert makeKeyAndOrderFront:self];
[player2 connectToClient];
[NXApp beginModalSession:&session for:alert];
for (;;) {
if ((res = [NXApp runModalSession:&session]) != NX_RUNCONTINUES)
break;
if ([player2 isConnected])
break;
}
[NXApp endModalSession:&session];
[alert close];
if (res != NX_RUNCONTINUES)
return nil;
}
return self;
}
- initGame
{
[self resetBoard];
currentPlayer = nil; // this indicates that the game is just starting
otherPlayer = player2;
winner = NULL;
last_move = &moves;
[player1 setPlayerState:PLAYER_INACTIVE];
[player2 setPlayerState:PLAYER_INACTIVE];
return self;
}
- startGame:sender
{
if (gameState == GAME_RUNNING)
return self;
if ((gameState == GAME_OVER) || (gameState == NO_GAME)) {
[self initGame];
[self setGameState:GAME_RUNNING];
[currentPlayer setPlayerState:PLAYER_ACTIVE];
[otherPlayer setPlayerState:PLAYER_INACTIVE];
[currentPlayer doNextMove:board];
} else if (gameState == GAME_PAUSED) {
[self pauseGame:sender];
}
return self;
}
- pauseGame:sender
{
if (gameState == GAME_PAUSED) {
[self setGameState:GAME_RUNNING];
[currentPlayer setPlayerState:PLAYER_ACTIVE];
[otherPlayer setPlayerState:PLAYER_INACTIVE];
if ([currentPlayer isKindOf:[ComputerPlayer class]])
[currentPlayer doNextMove:board];
} else {
[self setGameState:GAME_PAUSED];
[currentPlayer setPlayerState:PLAYER_PAUSED];
[currentPlayer setPlayerState:PLAYER_PAUSED];
}
return self;
}
- stopGame:sender
{
[self resetGame];
return self;
}
- gameOver
{
char *tmp,title[256];
[self setGameState:GAME_OVER];
[board fillEmptyWith:[currentPlayer pieceType]];
[self updateCount];
winner = [rules winner:self];
[otherPlayer gameOver:board];
if (winner) {
if (winner == player1)
tmp = "Player One Wins";
else
tmp = "Player Two Wins";
} else
tmp = "Tie Game";
sprintf(title,"Game Over - %s",tmp);
[boardWindow setTitle:title];
[boardView display];
[boardView gameOver];
if ([[NXApp defaultsManager] playSounds]) {
if ([winner isKindOf:[HumanPlayer class]])
[[NXApp soundManager] playSound:WIN_SOUND];
else
[[NXApp soundManager] playSound:GAMEOVER_SOUND];
}
return self;
}
- resetGame
{
[player1 setPlayerState:PLAYER_STOPPED];
[player2 setPlayerState:PLAYER_STOPPED];
[self setGameState:NO_GAME];
winner = NULL;
return self;
}
- (Player *)winner
{
return winner;
}
- resetBoard
{
[board free];
board = [origBoard trueCopy];
[[boardView setBoard:board] display];
[boardWindow flushWindow];
return self;
}
- setBoard:(Board *)b
{
Board *newb;
if (board)
[board free];
if (origBoard)
[origBoard free];
newb = [b trueCopy];
origBoard = [b trueCopy];
[boardView setScalable:NO];
[[boardView setBoard:newb] display];
[boardView setScalable:YES];
[rules setInitialBoard:newb];
board = newb;
return self;
}
- updateBoard:(Board *)b
{
Board *newb;
if (board)
[board free];
newb = [b trueCopy];
[boardView setScalable:NO];
[boardView setBoard:newb];
[boardView setScalable:YES];
board = newb;
return self;
}
- (Board *)board
{
return board;
}
- setRules:(SplatRules *)r
{
rules = r;
return self;
}
- (SplatRules *)rules
{
return rules;
}
- (Player *)currentPlayer
{
return currentPlayer;
}
- (Player *)otherPlayer
{
return otherPlayer;
}
- setPlayer1:(Player *)p
{
if (player1) {
[player1 free];
}
player1 = p;
[player1 setGame:self];
return self;
}
- (Player *)player1
{
return player1;
}
- setPlayer2:(Player *)p
{
if (player2) {
[player2 free];
}
player2 = p;
[player2 setGame:self];
return self;
}
- (Player *)player2
{
return player2;
}
- updateStatus
{
char title[256], *tmp;
switch (gameState) {
case GAME_RUNNING:
if (!currentPlayer)
currentPlayer = player1;
if ([player1 isKindOf:[HumanPlayer class]] ||
[player2 isKindOf:[HumanPlayer class]]) {
if ([currentPlayer isKindOf:[HumanPlayer class]])
tmp = "Splat - %s's Turn";
else
tmp = "Splat - %s's Turn (Thinking)";
sprintf(title,tmp,[currentPlayer playerName]);
} else {
if ([currentPlayer isKindOf:[HumanPlayer class]])
tmp = "Splat - Player %s's Turn";
else
tmp = "Splat - Player %s's Turn (Thinking)";
if (currentPlayer == player1)
sprintf(title,tmp,"One");
else
sprintf(title,tmp,"Two");
}
[boardWindow setTitle:title];
[self showPlayerNames];
[pauseButton setEnabled:1];
[playButton setEnabled:0];
[stopButton setEnabled:1];
[undoButton setEnabled:1];
[pauseButton setState:0];
[playButton setState:1];
break;
case GAME_PAUSED:
[boardWindow setTitle:"Splat - Paused"];
[pauseButton setEnabled:1];
[playButton setEnabled:1];
[stopButton setEnabled:1];
[undoButton setEnabled:0];
[pauseButton setState:1];
[playButton setState:1];
break;
case GAME_OVER:
[pauseButton setEnabled:0];
[playButton setEnabled:1];
[stopButton setEnabled:0];
[undoButton setEnabled:0];
[pauseButton setState:0];
[playButton setState:0];
break;
case NO_GAME:
[boardWindow setTitle:"Splat - Game Aborted"];
[pauseButton setEnabled:0];
[playButton setEnabled:1];
[stopButton setEnabled:0];
[undoButton setEnabled:0];
[pauseButton setState:0];
[playButton setState:0];
break;
}
[[pauseButton controlView] display];
[[playButton controlView] display];
[[stopButton controlView] display];
[[undoButton controlView] display];
[boardWindow flushWindow];
return self;
}
- setGameState:(enum game_state)state
{
if (gameState == state)
return self;
gameState = state;
switch (gameState) {
case NO_GAME:
[player1 setPlayerState:PLAYER_STOPPED];
[player2 setPlayerState:PLAYER_STOPPED];
break;
case GAME_PAUSED:
[player1 setPlayerState:PLAYER_PAUSED];
[player2 setPlayerState:PLAYER_PAUSED];
break;
case GAME_RUNNING:
if (currentPlayer == player1) {
[player1 setPlayerState:PLAYER_ACTIVE];
[player2 setPlayerState:PLAYER_INACTIVE];
} else if (currentPlayer == player2) {
[player1 setPlayerState:PLAYER_INACTIVE];
[player2 setPlayerState:PLAYER_ACTIVE];
} else {
[player1 setPlayerState:PLAYER_INACTIVE];
[player2 setPlayerState:PLAYER_INACTIVE];
}
break;
default:
break;
}
[self updateStatus];
return self;
}
- (enum game_state)gameState
{
return gameState;
}
- updateCount
{
int num;
num = [board numberOfPiece:SQUARE_ONE];
[player1PiecesField setIntValue:num];
num = [board numberOfPiece:SQUARE_TWO];
[player2PiecesField setIntValue:num];
return self;
}
- doNextMove
{
id player;
if (gameState != GAME_RUNNING)
return self;
if ([rules gameOver:board forPlayer:[otherPlayer pieceType]]) {
[self gameOver];
return self;
}
if (!currentPlayer)
currentPlayer = player1;
player = currentPlayer;
currentPlayer = otherPlayer;
otherPlayer = player;
[self updateStatus];
[currentPlayer setPlayerState:PLAYER_ACTIVE];
[otherPlayer setPlayerState:PLAYER_INACTIVE];
[currentPlayer doNextMove:board];
return self;
}
- doMove:(move *)mv
{
location loc = {0,0};
move_list *newmove;
last_move->mv = *mv;
newmove = malloc(sizeof(move_list));
newmove->prev = last_move;
newmove->next = NULL;
newmove->mv.from = loc;
newmove->mv.to = loc;
last_move->next = newmove;
last_move = newmove;
[rules doMove:mv onBoard:board];
[self updateCount];
return self;
}
- doUndoMove:sender
{
Board *newb;
move_list *last;
move nomove = {0,0};
id tmpPlayer;
if (!moves.next)
return self;
[boardWindow setTitle:"Undoing Move..."];
if (([otherPlayer isKindOf:[ComputerPlayer class]]) ||
([currentPlayer isKindOf:[ComputerPlayer class]])) {
newb = [rules undoMove:&moves];
[self updateBoard:newb];
last = last_move->prev;
if (!last->prev)
last->mv = nomove;
else {
last = last->prev;
free(last->next);
last->next = last_move;
last_move->prev = last;
}
} else {
tmpPlayer = currentPlayer;
currentPlayer = otherPlayer;
otherPlayer = tmpPlayer;
}
newb = [rules undoMove:&moves];
[self updateBoard:newb];
last = last_move->prev;
if (!last->prev) {
last_move->mv = nomove;
} else {
last = last->prev;
free(last->next);
last->next = last_move;
last_move->prev = last;
}
[self updateCount];
[self updateStatus];
return self;
}
/*
* BoardView callbacks
*/
- squareHit:(int)col :(int)row
{
move mv;
if (![currentPlayer isKindOf:[HumanPlayer class]])
return self;
if (gameState != GAME_RUNNING)
return self;
mv.from.col = [boardView selectedCol];
mv.from.row = [boardView selectedRow];
mv.to.col = col;
mv.to.row = row;
if ((mv.from.col == -1) || (![rules validMove:&mv onBoard:board])) {
if ([board pieceAt:col :row] == [currentPlayer pieceType])
[[boardView selectSquare:col :row] display];
} else {
[self startMove:&mv];
}
return self;
}
- startMove:(move *)mv
{
if ([[NXApp defaultsManager] doMoveAnimation])
[boardView doMoveAnimation:mv];
else
[self moveAnimationFinished:mv];
return self;
}
- moveAnimationFinished:(move *)mv
{
Board *copy;
copy = [board trueCopy];
[self doMove:mv];
[self updateCount];
if ([[NXApp defaultsManager] doMoveAnimation])
[boardView doChangeAnimation:copy];
else
[self changeAnimationFinished];
[copy free]; //? we assume that boardView has made a copy here
return self;
}
- changeAnimationFinished
{
if (![[NXApp defaultsManager] doMoveAnimation])
[boardView display];
[self doNextMove];
return self;
}
- windowWillClose:sender
{
int res;
switch (gameState) {
case NO_GAME:
case GAME_OVER:
return self;
break;
default:
res = NXRunAlertPanel("Whoops!","There's a game in progress. Are you sure you want to kill it?\n","OK","Cancel",NULL);
if (res == NX_ALERTDEFAULT)
return self;
else
return nil;
break;
}
return self;
}
/*
* for saving and restoring games
* (extension == ".splat")
*/
- write
{
return self;
}
- read
{
return self;
}
@end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.