int make_move(const void* pstate, ChoiceIndex hold) { const GameState* state = pstate; int player = ai_current_player(); switch (hold) { // hold and pass case 0: DEBUG("P%d: Hold %+d points\n", player, state->turn_total[player]); ai_add_player_score(player, state->turn_total[player]); SET(state->turn_total[player], 0); if (ai_next_player()) { play_turn(state); } return 1; // roll again case 1: play_turn(state); return 1; default: assert(0); return 0; } }
int die_rolled(const void* pstate, ChoiceIndex die) { const GameState* state = pstate; int player = ai_current_player(); DEBUG("P%d: Roll %d\n", player, die); switch (die) { case 0: // forfeit turn SET(state->turn_total[player], 0); if (ai_next_player()) { play_turn(state); } return 1; case 1: case 2: case 3: case 4: case 5: // add die roll to turn total SET(state->turn_total[player], state->turn_total[player] + die + 1); DEBUG("P%d: Added %+d points -> %d\n", player, die+1, state->turn_total[player]); // roll or hold? ai_choice(state, 0, make_move, 0, 0x3); return 1; default: assert(0); return 0; } }
void replay_controller::play_replay(){ if (recorder.at_end()){ return; } try{ is_playing_ = true; buttons_.playback_should_start(); DBG_REPLAY << "starting main loop\n" << (SDL_GetTicks() - ticks_) << "\n"; for(; !recorder.at_end() && is_playing_; first_player_ = 1) { play_turn(); } //end for loop if (!is_playing_) { gui_->scroll_to_leader(units_, player_number_,game_display::ONSCREEN,false); } } catch(end_level_exception& e){ if (e.result == QUIT) { throw e; } } buttons_.playback_should_stop(is_playing_); }
possible_end_play_signal playsingle_controller::play_scenario_main_loop(end_level_data & end_level, bool & /*past_prestart*/) { LOG_NG << "starting main loop\n" << (SDL_GetTicks() - ticks_) << "\n"; // Initialize countdown clock. std::vector<team>::const_iterator t; for(t = gamestate_.board_.teams().begin(); t != gamestate_.board_.teams().end(); ++t) { if (saved_game_.mp_settings().mp_countdown && !loading_game_ ) { t->set_countdown_time(1000 * saved_game_.mp_settings().mp_countdown_init_time); } } // if we loaded a save file in linger mode, skip to it. if (linger_) { //determine the bonus gold handling for this scenario end_level.read(level_.child_or_empty("end_level_data")); end_level.transient.carryover_report = false; end_level.transient.disabled = true; end_level_struct els = { SKIP_TO_LINGER }; return possible_end_play_signal ( els ); //throw end_level_exception(SKIP_TO_LINGER); } // Avoid autosaving after loading, but still // allow the first turn to have an autosave. do_autosaves_ = !loading_game_; ai_testing::log_game_start(); for(; ; first_player_ = 1) { PROPOGATE_END_PLAY_SIGNAL( play_turn() ); do_autosaves_ = true; } //end for loop return boost::none; }
possible_end_play_signal replay_controller::play_replay_main_loop() { DBG_REPLAY << "starting main loop\n" << (SDL_GetTicks() - ticks_) << "\n"; for(; !recorder.at_end() && is_playing_; first_player_ = 1) { PROPOGATE_END_PLAY_SIGNAL ( play_turn() ); } return boost::none; }
void playsingle_controller::play_scenario_main_loop() { LOG_NG << "starting main loop\n" << (SDL_GetTicks() - ticks()) << "\n"; // Avoid autosaving after loading, but still // allow the first turn to have an autosave. ai_testing::log_game_start(); if(gamestate().board_.teams().empty()) { ERR_NG << "Playing game with 0 teams." << std::endl; } while(true) { try { play_turn(); if (is_regular_game_end()) { turn_data_.send_data(); return; } gamestate_->player_number_ = 1; } catch(const reset_gamestate_exception& ex) { // // TODO: // // The MP replay feature still doesn't work properly (causes OOS) // because: // // 1) The undo stack is not reset along with the gamestate (fixed). // 2) The server_request_number_ is not reset along with the // gamestate (fixed). // 3) chat and other unsynced actions are inserted in the middle of // the replay bringing the replay_pos in unorder (fixed). // 4) untracked changes in side controllers are lost when resetting // gamestate (fixed). // 5) The game should have a stricter check for whether the loaded // game is actually a parent of this game. // 6) If an action was undone after a game was saved it can cause // OOS if the undone action is in the snapshot of the saved // game (luckily this is never the case for autosaves). // boost::dynamic_bitset<> local_players; local_players.resize(gamestate().board_.teams().size(), true); //Preserve side controllers, becasue we won't get the side controoller updates again when replaying. for(size_t i = 0; i < local_players.size(); ++i) { local_players[i] = gamestate().board_.teams()[i].is_local(); } reset_gamestate(*ex.level, (*ex.level)["replay_pos"]); for(size_t i = 0; i < local_players.size(); ++i) { resources::gameboard->teams()[i].set_local(local_players[i]); } play_scenario_init(); replay_.reset(new replay_controller(*this, false, ex.level)); if(ex.start_replay) { replay_->play_replay(); } } } //end for loop }
void play_game(const GameState* state) { while (!is_game_over(state)) { print_board(state); play_turn(state); } }
int main(int argc, char **argv) { if (main_init(argc, argv) == -1) sig_handler(-1); while (42) { play_turn(); } exit_shmem(); return (EXIT_SUCCESS); }
void replay_controller::replay_next_turn(){ is_playing_ = true; play_turn(); if (!skip_replay_){ gui_->scroll_to_leader(units_, player_number_,game_display::ONSCREEN,false); } is_playing_ = false; gui::button* b = gui_->find_button("button-nextturn"); if (b != NULL) { b->release(); } }
void replay_controller::replay_next_turn(){ is_playing_ = true; buttons_.playback_should_start(); play_turn(); if (!skip_replay_ || !is_playing_){ gui_->scroll_to_leader(units_, player_number_,game_display::ONSCREEN,false); } buttons_.playback_should_stop(is_playing_); }
possible_end_play_signal replay_controller::replay_next_turn(){ is_playing_ = true; replay_ui_playback_should_start(); PROPOGATE_END_PLAY_SIGNAL( play_turn() ); if (!skip_replay_ || !is_playing_){ gui_->scroll_to_leader(player_number_,game_display::ONSCREEN,false); } replay_ui_playback_should_stop(); return boost::none; }
int make_move_0(const GameState* state) { int d1 = state->d1; int d2 = state->d2; int player = ai_current_player(); DEBUG("P%d dice %d %d\n", player, d1, d2); ChoiceMask mask = 0; // entering from bar has priority if (state->bar[player]) { if (reenter_from_bar(state, player, d1)) { SET(state->d1, 0); d1 = 0; } if (reenter_from_bar(state, player, d2)) { SET(state->d2, 0); d2 = 0; } } // player can move any of 24 points // TODO: bearing off rules for (int i=0; i<24; i++) { // does this point have a valid move? if (state->points[PT(player,i)].occupied == player+1 && (is_valid_move(state,player,i,d1) || is_valid_move(state,player,i,d2) || is_valid_move(state,player,i,d1+d2))) { mask |= (1<<i); } } if (mask != 0) { // try each of our pieces if (ai_choice(state, 0, make_move_1, 0, mask) == 0) mask = 0; } // none are valid, so player passes if (mask == 0) { DEBUG("P%d no moves\n", player); if (ai_next_player()) play_turn(state); // if in search mode } return 1; }
int make_move_2(const void* pstate, ChoiceIndex index) { const GameState* state = pstate; int d1 = state->d1; int d2 = state->d2; if (index == 3) SWAP(d1,d2); // make moves, either one at a time or together int pt = state->point_to_move; //print_board(state); printf("0 %d %d %d\n", ai_current_player(), index, pt); if (index != 1) { int m1 = make_move(state, pt, d1); // return failure if move is invalid // or if we bearoff but have a move remaining (TODO: prune earlier) if (m1 == MOVE_INVALID) return 0; if (m1 == MOVE_BEAROFF && index != 0) return 0; pt -= d1; } //print_board(state); printf("1 %d %d %d\n", ai_current_player(), index, pt); if (index != 0) { if (!make_move(state, pt, d2)) return 0; } // did we play both our dice? if (index >= 2 || d1 == 0 || d2 == 0) { if (ai_next_player()) play_turn(state); // if in search mode return 1; } // make another move if (index == 0) { SET(state->d1, 0); } else { SET(state->d2, 0); } return make_move_0(state); }
void playsingle_controller::play_scenario_main_loop() { LOG_NG << "starting main loop\n" << (SDL_GetTicks() - ticks_) << "\n"; // Avoid autosaving after loading, but still // allow the first turn to have an autosave. ai_testing::log_game_start(); if(gamestate_.board_.teams().empty()) { ERR_NG << "Playing game with 0 teams." << std::endl; } while(true) { play_turn(); if (is_regular_game_end()) { return; } player_number_ = 1; } //end for loop }
void play_game(const GameState* state) { while (!is_game_over(state)) { print_board(state); /* // AI solve for this player? if (ai_set_mode_search()) { play_turn(state); ai_print_stats(); } // commit the best move, or prompt human for move if (!ai_set_mode_play()) break; */ play_turn(state); } }
void replay_controller::play_replay(){ gui::button* b = gui_->find_button("button-stopreplay"); if (b != NULL) { b->release(); } if (recorder.at_end()){ return; } try{ is_playing_ = true; DBG_REPLAY << "starting main loop\n" << (SDL_GetTicks() - ticks_) << "\n"; for(; !recorder.at_end() && is_playing_; first_player_ = 1) { play_turn(); } //end for loop is_playing_ = false; } catch(end_level_exception& e){ if (e.result == QUIT) { throw e; } } }
int run(void* foo, void* api, void* client_cx) { init_game(); set_event_handler(api, next_turn_callback); g_ccx = client_cx; while (get_state(api) != GS_END) { // Play a turn. // When this return, it means the user asked to go to // the next turn. play_turn(); // Process our messages. process_messages(client_cx); } //end_game(); foo = foo; return 0; }
void playsingle_controller::play_scenario_main_loop() { LOG_NG << "starting main loop\n" << (SDL_GetTicks() - ticks()) << "\n"; // Avoid autosaving after loading, but still // allow the first turn to have an autosave. ai_testing::log_game_start(); if(gamestate().board_.teams().empty()) { ERR_NG << "Playing game with 0 teams." << std::endl; } while(true) { try { play_turn(); if (is_regular_game_end()) { return; } gamestate_->player_number_ = 1; } catch(const reset_gamestate_exception& ex) { /** @TODO: The mp replay feature still doesnt work properly (casues OOS) becasue: 1) The undo stack is not reset along with the gamestate (fixed). 2) The server_request_number_ is not reset along with the gamestate (fixed). 3) chat and other unsynced actions are inserted in the middle of the replay bringing the replay_pos in unorder (fixed). 4) untracked changes in side controllers are lost when resetting gamestate. 5) The game should have a stricter check for whether the loaded game is actually a parent of this game. 6) If an action was undone after a game was saved it can casue if teh undone action is in the snapshot of the saved game. (luckyli this is never the case for autosaves) */ reset_gamestate(*ex.level, (*ex.level)["replay_pos"]); play_scenario_init(*ex.level); mp_replay_.reset(new replay_controller(*this, false, ex.level)); mp_replay_->play_replay(); } } //end for loop }
LEVEL_RESULT playsingle_controller::play_scenario( const config::const_child_itors &story, bool skip_replay) { uint32_t start = SDL_GetTicks(); // level_ // save game: [snapshort] in save file // new game: [scenario] in <scenarios>.cfg // Start music. BOOST_FOREACH (const config &m, level_.child_range("music")) { sound::play_music_config(m); } sound::commit_music_changes(); if(!skip_replay) { // show_story(*gui_, level_["name"], story); // gui2::show_story(*gui_, level_["name"], story); } gui_->labels().read(level_); // Read sound sources assert(soundsources_manager_ != NULL); BOOST_FOREACH (const config &s, level_.child_range("sound_source")) { soundsource::sourcespec spec(s); soundsources_manager_->add(spec); } uint32_t end_sound_sources = SDL_GetTicks(); posix_print("playsingle_controller::play_scenario, sound sources, used time: %u ms\n", end_sound_sources - start); set_victory_when_enemy_no_city(level_["victory_when_enemy_no_city"].to_bool(true)); end_level_data &end_level = get_end_level_data(); end_level.carryover_percentage = level_["carryover_percentage"].to_int(game_config::gold_carryover_percentage); end_level.carryover_add = level_["carryover_add"].to_bool(); try { uint32_t end_entering_try = SDL_GetTicks(); posix_print("playsingle_controller::play_scenario, entering try, used time: %u ms\n", end_entering_try - end_sound_sources); fire_prestart(!loading_game_); uint32_t end_fire_prestart = SDL_GetTicks(); posix_print("playsingle_controller::play_scenario, fire_prestrt, used time: %u ms\n", end_fire_prestart - end_entering_try); init_gui(); fire_start(!loading_game_); gui_->recalculate_minimap(); // replaying_ = (recorder.at_end() == false); // Initialize countdown clock. std::vector<team>::iterator t; for(t = teams_.begin(); t != teams_.end(); ++t) { if (gamestate_.mp_settings().mp_countdown && !loading_game_ ){ t->set_countdown_time(1000 * gamestate_.mp_settings().mp_countdown_init_time); } } // if we loaded a save file in linger mode, skip to it. if (linger_) { //determine the bonus gold handling for this scenario const config end_cfg = level_.child_or_empty("endlevel"); end_level.carryover_percentage = level_["carryover_percentage"].to_int(game_config::gold_carryover_percentage); end_level.carryover_add = level_["carr`yover_add"].to_bool(); end_level.gold_bonus = end_cfg["bonus"].to_bool(true); end_level.carryover_report = false; throw end_level_exception(SKIP_TO_LINGER); } // Avoid autosaving after loading, but still // allow the first turn to have an autosave. bool save = !loading_game_; for(; ; first_player_ = 1) { play_turn(save); save = true; } //end for loop } catch(game::load_game_exception& lge) { // Loading a new game is effectively a quit. // if (lge.game != "") { gamestate_ = game_state(); } throw lge; } catch (end_level_exception &end_level_exn) { LEVEL_RESULT end_level_result = end_level_exn.result; if (!end_level.custom_endlevel_music.empty()) { if (end_level_result == DEFEAT) { set_defeat_music_list(end_level.custom_endlevel_music); } else { set_victory_music_list(end_level.custom_endlevel_music); } } if (teams_.empty()) { //store persistent teams gamestate_.snapshot = config(); return VICTORY; // this is probably only a story scenario, i.e. has its endlevel in the prestart event } const bool obs = is_observer(); if (end_level_result == DEFEAT || end_level_result == VICTORY) { gamestate_.classification().completion = (end_level_exn.result == VICTORY) ? "victory" : "defeat"; // If we're a player, and the result is victory/defeat, then send // a message to notify the server of the reason for the game ending. if (!obs) { config cfg; config& info = cfg.add_child("info"); info["type"] = "termination"; info["condition"] = "game over"; info["result"] = gamestate_.classification().completion; network::send_data(cfg, 0); } else { gui2::show_transient_message(gui_->video(),_("Game Over"), _("The game is over.")); return OBSERVER_END; } } if (end_level_result == QUIT) { return QUIT; } else if (end_level_result == DEFEAT) { gamestate_.classification().completion = "defeat"; game_events::fire("defeat"); if (!obs) { const std::string& defeat_music = select_defeat_music(); if(defeat_music.empty() != true) sound::play_music_once(defeat_music); return DEFEAT; } else { return QUIT; } } else if (end_level_result == VICTORY) { gamestate_.classification().completion = !end_level.linger_mode ? "running" : "victory"; game_events::fire("victory"); // // Play victory music once all victory events // are finished, if we aren't observers. // // Some scenario authors may use 'continue' // result for something that is not story-wise // a victory, so let them use [music] tags // instead should they want special music. // if (!obs && end_level.linger_mode) { const std::string& victory_music = select_victory_music(); if(victory_music.empty() != true) sound::play_music_once(victory_music); } // Add all the units that survived the scenario. LOG_NG << "Add units that survived the scenario to the recall list.\n"; //store all units that survived (recall list for the next scenario) in snapshot gamestate_.snapshot = config(); //store gold and report victory store_gold(obs); return VICTORY; } else if (end_level_result == SKIP_TO_LINGER) { LOG_NG << "resuming from loaded linger state...\n"; //as carryover information is stored in the snapshot, we have to re-store it after loading a linger state gamestate_.snapshot = config(); store_gold(); return VICTORY; } } // end catch catch(network::error& e) { bool disconnect = false; if(e.socket) { e.disconnect(); disconnect = true; } config snapshot; to_config(snapshot); savegame::game_savegame save(heros_, heros_start_, gamestate_, *gui_, snapshot); save.save_game_interactive(gui_->video(), _("A network disconnection has occurred, and the game cannot continue. Do you want to save the game?"), gui::YES_NO); if(disconnect) { throw network::error(); } else { return QUIT; } } return QUIT; }
LEVEL_RESULT playsingle_controller::play_scenario( const config::const_child_itors &story, bool skip_replay) { LOG_NG << "in playsingle_controller::play_scenario()...\n"; // Start music. foreach (const config &m, level_.child_range("music")) { sound::play_music_config(m); } sound::commit_music_changes(); if(!skip_replay) { show_story(*gui_, level_["name"], story); } gui_->labels().read(level_); // Read sound sources assert(soundsources_manager_ != NULL); foreach (const config &s, level_.child_range("sound_source")) { soundsource::sourcespec spec(s); soundsources_manager_->add(spec); } set_victory_when_enemies_defeated(level_["victory_when_enemies_defeated"].to_bool(true)); end_level_data &end_level = get_end_level_data(); end_level.carryover_percentage = level_["carryover_percentage"].to_int(game_config::gold_carryover_percentage); end_level.carryover_add = level_["carryover_add"].to_bool(); bool past_prestart = false; LOG_NG << "entering try... " << (SDL_GetTicks() - ticks_) << "\n"; try { fire_prestart(!loading_game_); init_gui(); past_prestart = true; LOG_NG << "first_time..." << (recorder.is_skipping() ? "skipping" : "no skip") << "\n"; events::raise_draw_event(); fire_start(!loading_game_); gui_->recalculate_minimap(); replaying_ = (recorder.at_end() == false); LOG_NG << "starting main loop\n" << (SDL_GetTicks() - ticks_) << "\n"; // Initialize countdown clock. std::vector<team>::iterator t; for(t = teams_.begin(); t != teams_.end(); ++t) { if (gamestate_.mp_settings().mp_countdown && !loading_game_ ){ t->set_countdown_time(1000 * gamestate_.mp_settings().mp_countdown_init_time); } } // if we loaded a save file in linger mode, skip to it. if (linger_) { //determine the bonus gold handling for this scenario end_level.read(level_.child_or_empty("endlevel")); end_level.carryover_report = false; end_level.disabled = true; throw end_level_exception(SKIP_TO_LINGER); } // Avoid autosaving after loading, but still // allow the first turn to have an autosave. bool save = !loading_game_; ai_testing::log_game_start(); for(; ; first_player_ = 1) { play_turn(save); save = true; } //end for loop #ifdef _MSC_VER //MSVC claims that const game::load_game_exception& lge would be unreferenced... #pragma warning (push) #pragma warning (disable : 4101) #endif } catch(const game::load_game_exception& lge) { // Loading a new game is effectively a quit. // if (lge.game != "") { gamestate_ = game_state(); } throw; } catch (end_level_exception &end_level_exn) { if(!past_prestart) { draw_solid_tinted_rectangle( 0, 0, gui_->video().getx(), gui_->video().gety(), 0, 0, 0, 1.0, gui_->video().getSurface() ); update_rect(0, 0, gui_->video().getx(), gui_->video().gety()); } ai_testing::log_game_end(); LEVEL_RESULT end_level_result = end_level_exn.result; if (!end_level.custom_endlevel_music.empty()) { if (end_level_result == DEFEAT) { set_defeat_music_list(end_level.custom_endlevel_music); } else { set_victory_music_list(end_level.custom_endlevel_music); } } if (teams_.empty()) { //store persistent teams gamestate_.snapshot = config(); store_recalls(); return VICTORY; // this is probably only a story scenario, i.e. has its endlevel in the prestart event } const bool obs = is_observer(); if (game_config::exit_at_end) { exit(0); } if (end_level_result == DEFEAT || end_level_result == VICTORY) { gamestate_.classification().completion = (end_level_exn.result == VICTORY) ? "victory" : "defeat"; // If we're a player, and the result is victory/defeat, then send // a message to notify the server of the reason for the game ending. if (!obs) { config cfg; config& info = cfg.add_child("info"); info["type"] = "termination"; info["condition"] = "game over"; info["result"] = gamestate_.classification().completion; network::send_data(cfg, 0); } else { gui2::show_transient_message(gui_->video(),_("Game Over"), _("The game is over.")); return OBSERVER_END; } } if (end_level_result == QUIT) { return QUIT; } else if (end_level_result == DEFEAT) { gamestate_.classification().completion = "defeat"; game_events::fire("defeat"); if (!obs) { const std::string& defeat_music = select_defeat_music(); if(defeat_music.empty() != true) sound::play_music_once(defeat_music); return DEFEAT; } else { return QUIT; } } else if (end_level_result == VICTORY) { gamestate_.classification().completion = !end_level.linger_mode ? "running" : "victory"; game_events::fire("victory"); // // Play victory music once all victory events // are finished, if we aren't observers. // // Some scenario authors may use 'continue' // result for something that is not story-wise // a victory, so let them use [music] tags // instead should they want special music. // if (!obs && end_level.linger_mode) { const std::string& victory_music = select_victory_music(); if(victory_music.empty() != true) sound::play_music_once(victory_music); } // Add all the units that survived the scenario. LOG_NG << "Add units that survived the scenario to the recall list.\n"; for(unit_map::iterator un = units_.begin(); un != units_.end(); ++un) { if (teams_[un->side() - 1].persistent()) { LOG_NG << "Added unit " << un->id() << ", " << un->name() << "\n"; un->new_turn(); un->new_scenario(); teams_[un->side() - 1].recall_list().push_back(*un); } } //store all units that survived (recall list for the next scenario) in snapshot gamestate_.snapshot = config(); store_recalls(); //store gold and report victory store_gold(obs); return VICTORY; } else if (end_level_result == SKIP_TO_LINGER) { LOG_NG << "resuming from loaded linger state...\n"; //as carryover information is stored in the snapshot, we have to re-store it after loading a linger state gamestate_.snapshot = config(); store_recalls(); store_gold(); return VICTORY; } } // end catch catch(network::error& e) { bool disconnect = false; if(e.socket) { e.disconnect(); disconnect = true; } savegame::game_savegame save(gamestate_, *gui_, to_config(), preferences::compress_saves()); save.save_game_interactive(gui_->video(), _("A network disconnection has occurred, and the game cannot continue. Do you want to save the game?"), gui::YES_NO); if(disconnect) { throw network::error(); } else { return QUIT; } } return QUIT; }