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.