/* * game.cc - game control flow for Bombermaze * written by Sydney Tang * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * For more details see the file COPYING. */ #include "game.hh" #include "preferences.hh" #include #include #include static GameStateMachine *GlobalStateMachine = NULL; int game_initialize(UIWidget *widget) { srand(time((time_t *)NULL)); GlobalStateMachine = new GameStateMachine(); GlobalStateMachine->set_map(preferences_get_current_mapfile()); GlobalStateMachine->ui_dependent_initialization(widget); return 0; } void game_terminate(void) { delete GlobalStateMachine; } GameState *game_get_current_state(void) { GameState *CurrentGameState; CurrentGameState = GlobalStateMachine->get_game_state(); return CurrentGameState; } GameStateMachine::GameStates game_get_current_state_type(void) { return GlobalStateMachine->get_state(); } bool game_set_map(const char *mapfile_path) { if (GlobalStateMachine == NULL) return true; return GlobalStateMachine->set_map(mapfile_path); } void game_start_new(UIWidget *widget, int players) { GlobalStateMachine->start_multiplayer_game(players); } void game_toggle_pause(UIWidget *widget, gpointer data) { if (GlobalStateMachine->get_state() == GameStateMachine::STATE_MULTIPLAYER) { InGameState *state = (InGameState *)(game_get_current_state()); state->toggle_pause(); } } void game_set_pause(bool pause_setting) { if (GlobalStateMachine->get_state() == GameStateMachine::STATE_MULTIPLAYER) { InGameState *state = (InGameState *)(game_get_current_state()); state->set_pause(pause_setting); } } bool game_get_pause(void) { if (GlobalStateMachine->get_state() == GameStateMachine::STATE_MULTIPLAYER) { InGameState *state = (InGameState *)(game_get_current_state()); return state->get_pause(); } return false; } /////////////////////////////////////////////////////////////////////////////// GameStateMachine::GameStateMachine() { state[STATE_TITLESCREEN] = new TitleScreenState(this); state[STATE_MAINMENU] = new GameState(this); state[STATE_1_PLAYER] = new InGameState(this); state[STATE_MULTIPLAYER] = new InGameState(this); state[STATE_1_PLAYER_GAME_OVER] = new GameOverState(this); state[STATE_MULTIPLAYER_GAME_OVER] = new GameOverState(this); state[STATE_HIGHSCORES] = new GameState(this); status = STATE_TITLESCREEN; UIContainerWidget = NULL; UIActiveWidget = NULL; } GameStateMachine::~GameStateMachine() { terminate_current_state(); UIContainerWidget = NULL; UIActiveWidget = NULL; for (int i = 0; i < NUMBER_OF_STATES; i++) { delete state[i]; } } GameStateMachine::GameStates GameStateMachine::get_state(void) { return this->status; } GameState *GameStateMachine::get_game_state(void) { return state[status]; } void GameStateMachine::change_state(GameStateMachine::GameStates NewState, int InitializationData) { terminate_current_state(); this->status = NewState; initialize_current_state(InitializationData); return; } void GameStateMachine::initialize_current_state(int InitializationData) { state[status]->initialize_state(InitializationData); return; } void GameStateMachine::terminate_current_state(void) { state[status]->terminate_state(); return; } void GameStateMachine::start_game(int NumPlayers) { if (NumPlayers == 1) { //start_single_player_game(); } else if ((NumPlayers > 1) && (NumPlayers <= Player::MAX_NUMBER_OF_PLAYERS)) { start_multiplayer_game(NumPlayers); } } void GameStateMachine::start_single_player_game(void) { change_state(STATE_1_PLAYER, 1); } void GameStateMachine::start_multiplayer_game(int NumPlayers) { change_state(STATE_MULTIPLAYER, NumPlayers); } /* int GameStateMachine::get_number_of_players_in_current_game(void) { return NumberOfPlayersInCurrentGame; } */ bool GameStateMachine::set_map(const char *mapfile_path) { bool valid = GameMap::parse_map(mapfile_path, &ReferenceMap); ReferenceMap.set_valid(valid); return valid; } ParsedMap *GameStateMachine::get_map(void) { return &ReferenceMap; } /////////////////////////////////////////////////////////////////////////////// GameState::GameState(GameStateMachine *sm = (GameStateMachine *)NULL) { owner = sm; } GameState::~GameState() { } void GameState::initialize_state(int InitializationData) { return; } void GameState::terminate_state(void) { return; } /////////////////////////////////////////////////////////////////////////////// TitleScreenState::TitleScreenState(GameStateMachine *sm): GameState(sm) { } TitleScreenState::~TitleScreenState() { } void TitleScreenState::initialize_state(int InitializationData) { draw_title_screen(); ui_clear_status_message(); ui_clear_score_display(); return; } void TitleScreenState::terminate_state(void) { return; } /////////////////////////////////////////////////////////////////////////////// unsigned InGameState::Timeout_Interval = InGameState::DEFAULT_TIMEOUT_INTERVAL; unsigned InGameState::WinsPerMatch = InGameState::DEFAULT_WINS_PER_MATCH; InGameState::InGameState(GameStateMachine *sm): GameState(sm) { paused = true; } InGameState::~InGameState() { undraw_maze(); } void InGameState::initialize_state(int n_players) { ui_clear_status_message(); if (false == ui_apply_pending_theme_change()) { ui_notify_invalid_theme(); owner->change_state(GameStateMachine::STATE_TITLESCREEN, 0); return; } if (n_players != RESUME_MATCH) { ui_clear_score_display(); set_number_of_players(n_players); reset_match(); } initialize_round(); return; } void InGameState::terminate_state(void) { terminate_round(); return; } void InGameState::set_number_of_players(int NumPlayers) { NumberOfPlayers = NumPlayers; } int InGameState::get_number_of_players(void) { return NumberOfPlayers; } void InGameState::perform_player_action(PlayerActionKeyBinding *action) { int i = action->PlayerIndex; if (i >= NumberOfPlayers) return; player[i].perform_action(action->ActionType); return; } void InGameState::toggle_pause(void) { if (paused == false) { disable_timer(); } else { initialize_timer(); } notify_pause_status(); } void InGameState::set_pause(bool pause_setting) { if (pause_setting == true) { disable_timer(); } else { initialize_timer(); } notify_pause_status(); } bool InGameState::get_pause(void) { return paused; } unsigned InGameState::get_timeout_interval(void) { return Timeout_Interval; } void InGameState::set_timeout_interval(unsigned delay) { if (delay < TIMEOUT_INTERVAL_MINIMUM) { Timeout_Interval = TIMEOUT_INTERVAL_MINIMUM; } else if (delay > TIMEOUT_INTERVAL_MAXIMUM) { Timeout_Interval = TIMEOUT_INTERVAL_MAXIMUM; } else { Timeout_Interval = delay; } } void InGameState::set_wins_per_match(unsigned wins) { WinsPerMatch = wins; } int InGameState::timeout_callback(void *data) { if (TimeoutHandlingInProgress == true) { return TRUE; } TimeoutHandlingInProgress = true; for (int i = 0; i < NumberOfPlayers; i++) { for (int j = 0; j < MAX_ALLOWED_SUSTAINED_ACTIONS; j++) { if (SustainedPlayerAction[j][i] != -1) { player[i].perform_action((Player::PlayerAction) SustainedPlayerAction[j][i]); } } player[i].animate(); } maze.animate_map_entities(); update_ui(); handle_game_over_conditions(); TimeoutHandlingInProgress = false; return TRUE; } void InGameState::reset_match(void) { round = 1; for (int i = 0; i < Player::MAX_NUMBER_OF_PLAYERS; i++) { NumberOfWins[i] = 0; } update_score_display(); } void InGameState::initialize_round(void) { if (false == ui_check_for_valid_theme()) { ui_notify_invalid_theme(); owner->change_state(GameStateMachine::STATE_TITLESCREEN, 0); return; } if ((owner->get_map())->check_if_valid() == true) { maze.assign_map_from_parsed_map(owner->get_map()); } else { ui_notify_invalid_map(); owner->change_state(GameStateMachine::STATE_TITLESCREEN, 0); return; } int AllowableNumberOfPlayers = maze.get_allowable_number_of_players(); if (AllowableNumberOfPlayers < NumberOfPlayers) { NumberOfPlayers = AllowableNumberOfPlayers; } maze.populate_map(); undraw_maze(); draw_maze(); initialize_players(); update_ui(); update_score_display(); MatchStatusWindow = NULL; initialize_timer(); } void InGameState::initialize_players(void) { int i, j; int StartingX, StartingY; for (i = 0; i < NumberOfPlayers; i++) { for (j = 0; j < MAX_ALLOWED_SUSTAINED_ACTIONS; j++) { SustainedPlayerAction[j][i] = -1; } player[i].reset_fields(); player[i].set_id(i); player[i].set_game_map(&maze); maze.get_starting_coordinates_of_player(i+1, StartingX, StartingY); player[i].set_starting_coordinates(StartingX, StartingY); player[i].activate(); maze.move_entity_to_top(&(player[i]), StartingX, StartingY); } return; } void InGameState::terminate_round(void) { disable_timer(); maze.depopulate_map(); unref_ui_components(); } void InGameState::handle_game_over_conditions(void) { int winner = check_if_game_over(); if (winner != NOT_GAME_OVER) { if (winner != STALEMATE) { NumberOfWins[winner]++; if (NumberOfWins[winner] == WinsPerMatch) { owner->change_state(GameStateMachine::STATE_MULTIPLAYER_GAME_OVER, winner); } else { owner->change_state(GameStateMachine::STATE_MULTIPLAYER_GAME_OVER, RESUME_MATCH); } } else { owner->change_state(GameStateMachine::STATE_MULTIPLAYER_GAME_OVER, RESUME_MATCH); } update_score_display(); if (true == preferences_is_inter_round_status_enabled()) display_match_status(winner); else match_status_continue(); round++; } } int InGameState::check_if_game_over(void) { int i; int winner = STALEMATE; int ActivePlayers = 0; for (i = 0; i < NumberOfPlayers; i++) { if (player[i].get_status() != Player::PLAYER_INACTIVE) { ActivePlayers++; if (winner == STALEMATE) winner = i; } } if (ActivePlayers <= 1) { return winner; } else { return NOT_GAME_OVER; } } /////////////////////////////////////////////////////////////////////////////// GameOverState::GameOverState(GameStateMachine *sm): GameState(sm) { } GameOverState::~GameOverState() { } void GameOverState::initialize_state(int winner_of_match) { //GameOver = false; GameOverWindow = NULL; winner = winner_of_match; return; } void GameOverState::terminate_state(void) { hide_game_over_screen(); return; } ///////////////////////////////////////////////////////////////////////////////