72 #define LOG_AIT LOG_STREAM(info, log_aitesting) 76 #define LOG_NG LOG_STREAM(info, log_engine) 77 #define DBG_NG LOG_STREAM(debug, log_engine) 78 #define ERR_NG LOG_STREAM(err, log_engine) 81 #define ERR_DP LOG_STREAM(err, log_display) 84 #define LOG_RG LOG_STREAM(info, log_enginerefac) 87 #define DBG_EE LOG_STREAM(debug, log_engine_enemies) 94 static const std::set<std::string> attrs {
97 "victory_when_enemies_defeated",
98 "remove_from_carryover_on_defeat",
100 "experience_modifier",
105 static const std::set<std::string> tags {
111 for(
const std::string& attr : attrs) {
112 dst[attr] = src[attr];
115 for(
const std::string& tag : tags) {
142 , ticks_(SDL_GetTicks())
145 , saved_game_(state_of_game)
146 , tooltips_manager_()
147 , whiteboard_manager_()
149 , labels_manager_(new
font::floating_label_context())
150 , help_manager_(&game_config_)
151 , mouse_handler_(nullptr, *this)
152 , menu_handler_(nullptr, *this)
154 , soundsources_manager_()
158 , statistics_context_(new
statistics::scenario_context(level[
"name"]))
159 , replay_(new
replay(state_of_game.get_replay()))
160 , skip_replay_(skip_replay)
161 , skip_story_(state_of_game.skip_story())
163 , init_side_done_now_(false)
165 , victory_when_enemies_defeated_(level[
"victory_when_enemies_defeated"].to_bool(true))
166 , remove_from_carryover_on_defeat_(level[
"remove_from_carryover_on_defeat"].to_bool(true))
170 , ignore_replay_errors_(false)
171 , player_type_changed_(false)
210 LOG_NG <<
"initializing game_state..." << (SDL_GetTicks() -
ticks()) << std::endl;
225 LOG_NG <<
"initializing whiteboard..." << (SDL_GetTicks() -
ticks()) << std::endl;
230 LOG_NG <<
"loading units..." << (SDL_GetTicks() -
ticks()) << std::endl;
234 LOG_NG <<
"initializing theme... " << (SDL_GetTicks() -
ticks()) << std::endl;
238 LOG_NG <<
"building terrain rules... " << (SDL_GetTicks() -
ticks()) << std::endl;
243 if(!
gui_->video().faked()) {
245 gui_->get_theme().modify_label(
"time-icon",
_(
"time left for current turn"));
247 gui_->get_theme().modify_label(
"time-icon",
_(
"current local time"));
255 LOG_NG <<
"done initializing display... " << (SDL_GetTicks() -
ticks()) << std::endl;
257 LOG_NG <<
"building gamestate to gui and whiteboard... " << (SDL_GetTicks() -
ticks()) << std::endl;
264 if(
gamestate().first_human_team_ != -1) {
271 if(!
t.get_disallow_observers()) {
272 gui_->set_team(
t.side() - 1);
305 gui_->labels().set_team(
nullptr);
335 LOG_NG <<
"initializing managers... " << (SDL_GetTicks() -
ticks()) << std::endl;
341 LOG_NG <<
"done initializing managers... " << (SDL_GetTicks() -
ticks()) << std::endl;
372 const config cfg(
"side",
gui_->viewing_side());
393 tm.set_start_gold(tm.gold());
465 const std::string turn_num = std::to_string(
turn());
466 const std::string side_num = std::to_string(
current_side());
471 if(!
gamestate().tod_manager_.has_turn_event_fired()) {
478 pump().
fire(
"side_" + side_num +
"_turn");
479 pump().
fire(
"side_turn_" + turn_num);
480 pump().
fire(
"side_" + side_num +
"_turn_" + turn_num);
510 patient.set_resting(
true);
518 pump().
fire(
"side_" + side_num +
"_turn_refresh");
519 pump().
fire(
"turn_" + turn_num +
"_refresh");
520 pump().
fire(
"side_" + side_num +
"_turn_" + turn_num +
"_refresh");
539 gui_->invalidate_all();
562 gui_->labels().write(cfg);
577 const std::string turn_num = std::to_string(
turn());
578 const std::string side_num = std::to_string(
current_side());
584 pump().
fire(
"side_" + side_num +
"_turn_end");
585 pump().
fire(
"side_turn_" + turn_num +
"_end");
586 pump().
fire(
"side_" + side_num +
"_turn_" + turn_num +
"_end");
600 const std::string turn_num = std::to_string(
turn());
602 pump().
fire(
"turn_" + turn_num +
"_end");
655 ERR_DP <<
"unknown textbox mode" << std::endl;
674 auto prev = std::find(command_history.begin(), command_history.end(), str);
676 if (
prev != command_history.end())
679 if(
prev != command_history.begin()) {
683 if(++
prev != command_history.end()) {
690 if(command_history.size() > 0) {
703 std::set<std::string> dictionary;
708 if(!
gui_->fogged(loc) && !(
get_teams()[
gui_->viewing_team()].is_enemy(u.side()) && u.invisible(loc)))
709 dictionary.insert(u.name());
716 dictionary.insert(commands.begin(), commands.end());
722 dictionary.insert(
t.current_player());
726 for(
const std::string& o :
gui_->observers()) {
727 dictionary.insert(o);
731 for(
const std::string&
w :
gui_->get_chat_manager().whisperers()) {
732 dictionary.insert(
w);
738 for(std::map<std::string, std::string>::const_iterator iter = friends.begin(); iter != friends.end(); ++iter) {
739 dictionary.insert((*iter).first);
749 ERR_DP <<
"unknown textbox mode" << std::endl;
788 const int num_teams =
get_teams().size();
791 for(
int i = 0;
i < num_teams;
i++) {
833 if(event.key.keysym.sym == SDLK_ESCAPE) {
835 }
else if(event.key.keysym.sym == SDLK_TAB) {
837 }
else if(event.key.keysym.sym == SDLK_UP) {
839 }
else if(event.key.keysym.sym == SDLK_DOWN) {
841 }
else if(event.key.keysym.sym == SDLK_RETURN || event.key.keysym.sym == SDLK_KP_ENTER) {
848 if(event.key.keysym.sym == SDLK_TAB) {
857 if(event.key.keysym.sym >=
'1' && event.key.keysym.sym <=
'9') {
858 const int new_path_turns = (
event.type == SDL_KEYDOWN) ? event.key.keysym.sym -
'1' : 0;
877 }
else if(event.key.keysym.sym == SDLK_TAB) {
879 if(!keys[SDLK_TAB]) {
896 assert(!
gamestate().events_manager_->is_event_running());
978 const std::vector<std::string>& music_list = victory
979 ? (
gamestate_->get_game_data()->get_victory_music().empty()
981 :
gamestate_->get_game_data()->get_victory_music())
982 : (
gamestate_->get_game_data()->get_defeat_music().empty()
984 :
gamestate_->get_game_data()->get_defeat_music());
986 if(music_list.empty()) {
988 static const std::string empty_str =
"";
1005 bool continue_level, found_player, found_network_player, invalidate_all;
1006 std::set<unsigned> not_defeated;
1011 found_network_player,
1017 if(invalidate_all) {
1018 gui_->invalidate_all();
1021 if(continue_level) {
1025 if(found_player || found_network_player) {
1033 DBG_EE <<
"found_player: " << found_player << std::endl;
1034 DBG_EE <<
"found_network_player: " << found_network_player << std::endl;
1041 if(
gui_->video().non_interactive()) {
1043 for(
unsigned l : not_defeated) {
1047 LOG_AIT << l <<
" (using " << ai <<
") ";
1054 DBG_EE <<
"throwing end level exception..." << std::endl;
1064 if(
gui_->video().non_interactive()) {
1072 std::stringstream message;
1073 message <<
_(
"The game is out of sync. It might not make much sense to continue. Do you want to save your game?");
1074 message <<
"\n\n" <<
_(
"Error details:") <<
"\n\n" <<
msg;
1083 gui_->set_team(team_index, observe);
1084 gui_->recalculate_minimap();
1085 gui_->invalidate_all();
1186 gui_->recalculate_minimap();
1197 gui_->recalculate_minimap();
1210 std::set<std::string> res =
gui_->observers();
1213 res.insert(
t.current_player());
1223 gui_->parse_team_overlays();
1254 gui_->invalidate_game_status();
1258 if(
gui_->video().non_interactive()) {
1262 int last_player_number =
gamestate_->player_number_;
1263 int next_player_number =
gamestate_->next_player_number_;
1267 next_player_number =
gamestate_->next_player_number_;
1268 last_player_number =
gamestate_->player_number_;
1283 next_player_number =
gamestate_->next_player_number_;
1284 assert(next_player_number <= 2 * static_cast<int>(
get_teams().
size()));
1300 if(
gui_->video().non_interactive()) {
1306 gamestate_->player_number_ = next_player_number;
1310 gamestate_->player_number_ = last_player_number;
1327 LOG_NG <<
"firing time over event...\n";
1330 LOG_NG <<
"done firing time over event...\n";
1333 if(
gamestate().tod_manager_.is_time_left()) {
1337 if(
gui_->video().non_interactive()) {
1338 LOG_AIT <<
"time over (draw)\n";
1355 : controller_(controller)
1368 static const std::string no_objectives(
_(
"No objectives available"));
1378 if(skip_animation_button) {
std::shared_ptr< gui::button > find_action_button(const std::string &id)
Retrieves a pointer to a theme UI button.
void clear()
Clears the stack of undoable (and redoable) actions.
play_controller * controller
std::vector< std::string > default_victory_music
bool player_type_changed_
void do_search(const std::string &new_search)
void set_current_paths(const pathfind::paths &new_paths)
virtual bool should_return_to_play_side() const
std::unique_ptr< soundsource::manager > soundsources_manager_
static void log_turn_start(unsigned int side)
static void log_turn_end(unsigned int side)
void set_preference_display_settings()
::tod_manager * tod_manager
static lg::log_domain log_engine_enemies("engine/enemies")
hotkey::command_executor * get_hotkey_command_executor() override
Optionally get a command executor to handle context menu events.
void reset_objectives_changed() const
std::string interpolate_variables_into_string(const std::string &str, const string_map *const symbols)
Function which will interpolate variables, starting with '$' in the string 'str' with the equivalent ...
map_location last_selected
the last location where a select event fired.
The class for loading a savefile.
std::unique_ptr< game_lua_kernel > lua_kernel_
void refresh_objectives() const
Reevaluate [show_if] conditions and build a new objectives string.
void save_replay_auto(const std::string &filename)
int find_last_visible_team() const
returns 0 if no such team was found.
This class represents a single unit of a specific type.
std::unique_ptr< game_display > gui_
bool victory_when_enemies_defeated_
While any instance of this class exists, attempts to save the game via any call to play_controller wi...
game_classification * classification
const unit_map & get_units() const
Various functions implementing vision (through fog of war and shroud).
const mp_game_settings & get_mp_settings()
void do_final_checkup(bool dont_throw=false)
Note: Specific to sdl_ttf.
events::mouse_handler mouse_handler_
static manager & get_singleton()
static void copy_persistent(const config &src, config &dst)
Copies [scenario] attributes/tags that are not otherwise stored in C++ structs/clases.
std::unique_ptr< plugins_context > plugins_context_
bool is_skipping_replay() const
std::vector< game_tip > load(const config &cfg)
Loads the tips from a config.
std::unique_ptr< replay > replay_
static game_config_view wrap(const config &cfg)
Exception used to escape form the ai or ui code to playsingle_controller::play_side.
game_display & get_display() override
Get a reference to a display member a derived class uses.
static std::shared_ptr< save_index_class > default_saves_dir()
Returns an instance for managing saves in filesystem::get_saves_dir()
replay_recorder_base & get_replay()
game_events::wml_event_pump & pump()
void set_scope_active(scope s, bool set)
static void log_victory(std::set< unsigned int > teams)
static void on_unblock(play_controller *controller, void(play_controller::*callback)())
std::string sounds
List of "ambient" sounds associated with this time_of_day, Played at the beginning of turn...
std::unique_ptr< hotkey_handler > hotkey_handler_
const int INFINITE_AUTO_SAVES
bool enemies_visible() const
child_itors child_range(config_key_type key)
void process_keydown_event(const SDL_Event &event) override
Process keydown (always).
const pathfind::paths & current_paths() const
void show_transient_message(const std::string &title, const std::string &message, const std::string &image, const bool message_use_markup, const bool title_use_markup, const bool restore_background)
Shows a transient message to the user.
void do_command(const std::string &str)
void set_do_healing(bool do_healing)
static void progress(loading_stage stage=loading_stage::none)
virtual void update_viewing_player()=0
gui::floating_textbox & get_textbox()
void set_gui(game_display *gui)
static const config & get_theme(const game_config_view &game_config, std::string theme_name)
virtual soundsource::manager * get_soundsource_man() override
Get (optionally) a soundsources manager a derived class uses.
void undo()
Undoes the top action on the undo stack.
Gather statistics important for AI testing and output them.
unit_type_data unit_types
virtual void process_oos(const std::string &msg) const
Asks the user whether to continue on an OOS error.
A RAII object to enter the synced context, cannot be called if we are already in a synced context...
virtual void play_slice(bool is_delay_enabled=true)
void new_side_turn(int side)
Performs some initializations and error checks when starting a new side-turn.
static lg::log_domain log_engine("engine")
Class for "normal" midgame saves.
static void msg(const char *act, debug_info &i, const char *to="", const char *result="")
persist_manager * persist
void check_victory()
Checks to see if a side has won.
void apply_scenario_fix(const config &cfg)
config & set_snapshot(config snapshot)
void append_children(const config &cfg)
Adds children from cfg.
bool ignore_replay_errors_
bool save_game_interactive(const std::string &message, DIALOG_TYPE dialog_type)
Save a game interactively through the savegame dialog.
static lg::log_domain log_display("display")
void write_music_play_list(config &snapshot)
static std::string _(const char *str)
void process_keyup_event(const SDL_Event &event) override
Process keyup (always).
static void clear_resources()
This file implements all the hotkey handling and menu details for play controller.
void select_hex(const map_location &hex, const bool browse, const bool highlight=true, const bool fire_event=true)
void reset_turn_stats(const std::string &save_id)
void process_focus_keydown_event(const SDL_Event &event) override
Process keydown (only when the general map display does not have focus).
void memorize_command(const std::string &command)
std::unique_ptr< tooltips::manager > tooltips_manager_
std::vector< std::string > default_defeat_music
const std::unique_ptr< game_events::manager > events_manager_
config::attribute_value & get_variable(const std::string &varname)
throws invalid_variablename_exception if varname is no valid variable name.
bool have_keyboard_focus() override
Derived classes should override this to return false when arrow keys should not scroll the map...
events::menu_handler menu_handler_
void play_sound(const std::string &files, channel_group group, unsigned int repeats)
~scoped_savegame_snapshot()
void set_phase(PHASE phase)
std::unique_ptr< game_state > gamestate_
An exception-safe means of making sure that unblock() gets called after try_block().
void do_consolesave(const std::string &filename)
bool is_lingering() const
map_location get_selected_hex() const
Object which defines a time of day with associated bonuses, image, sounds etc.
This class stores all the data for a single 'side' (in game nomenclature).
A small explanation about what's going on here: Each action has access to two game_info objects First...
scoped_savegame_snapshot(const play_controller &controller)
void throw_quit_game_exception()
std::size_t size(const std::string &str)
Length in characters of a UTF-8 string.
void save_game_auto(const std::string &filename)
Various functions that implement advancements of units.
bool add_start_if_not_there_yet()
void textbox_move_vertically(bool up)
void set_path_turns(const int path_turns)
virtual void check_time_over()
bool can_redo() const
True if there are actions that can be redone.
Implements a quit confirmation dialog.
config to_config() const
Builds the snapshot config from members and their respective configs.
filter_context * filter_con
const time_of_day & get_time_of_day(int for_turn=0) const
Returns global time of day for the passed turn.
bool ignore_replay_errors
int side_upkeep(int side_num) const
TEXTBOX_MODE mode() const
This class is the frontend of the whiteboard framework for the rest of the Wesnoth code...
bool is_regular_game_end() const
void init(const config &level)
std::vector< team > & get_teams()
void recalculate_fog(int side)
Function that recalculates the fog of war.
void maybe_do_init_side()
Called by turn_info::process_network_data() or init_side() to call do_init_side() if necessary...
Object which temporarily resets a unit's movement.
bool load_game_ingame()
Load a game without providing any information.
std::unique_ptr< pathfind::manager > pathfind_manager_
Managing the AIs lifecycle - headers TODO: Refactor history handling and internal commands...
std::string theme() const
void check_victory(bool &, bool &, bool &, bool &, std::set< unsigned > &, bool)
void set_gui(game_display *gui)
void spend_gold(const int amount)
std::shared_ptr< wb::manager > get_whiteboard() const
static void add_color_info(const game_config_view &v, bool build_defaults)
An object which will lock the display for the duration of its lifetime.
Error used for any general game error, e.g.
game_events::manager * game_events
bool is_browsing() const override
void deactivate_all_scopes()
void update_gui_to_player(const int team_index, const bool observe=false)
Changes the UI for this client to the passed side index.
void do_init_side()
Called by replay handler or init_side() to do actual work for turn change.
Encapsulates the map of the game.
void calculate_healing(int side, bool update_display)
Calculates healing for all units for the given side.
int mp_countdown_init_time
std::shared_ptr< wb::manager > whiteboard
virtual ~play_controller()
bool is_proxy_human() const
Various functions related to the creation of units (recruits, recalls, and placed units)...
int support() const
Calculate total support capacity, based on support_per_village.
void set_end_level_data(const end_level_data &data)
int get_path_turns() const
soundsource::manager * soundsources
const std::string & select_music(bool victory) const
void redo()
Redoes the top action on the redo stack.
const std::vector< std::string > & command_history() const
unit_map::iterator selected_unit()
std::string get_active_ai_identifier_for_side(side_number side)
Gets AI algorithm identifier for active AI of the given side.
void reset_gamestate(const config &level, int replay_pos)
const t_string & objectives() const
std::shared_ptr< wb::manager > whiteboard_manager_
bool is_team_visible(int team_num, bool observer) const
Define the game's event mechanism.
void encounter_all_content(const game_board &gameboard_)
#define log_scope(description)
void tab(const std::set< std::string > &dictionary)
bool proceed_to_next_level
whether to proceed to the next scenario, equals is_victory in sp.
bool can_use_synced_wml_menu() const
t_string get_scenario_name() const
Additional information on the game outcome which can be provided by WML.
int get_random_int(int min, int max)
This helper method provides a random int from the underlying generator, using results of next_random...
actions::undo_list & undo_stack()
std::map< std::string, std::string > get_acquaintances_nice(const std::string &filter)
static void save(LexState *ls, int c)
static lg::log_domain log_enginerefac("enginerefac")
Class for replay saves (either manually or automatically).
config & add_child(config_key_type key)
pump_result_t fire(const std::string &event, const entity_location &loc1=entity_location::null_entity, const entity_location &loc2=entity_location::null_entity, const config &data=config())
Function to fire an event.
compression::format save_compression_format()
bool clear_shroud(int side, bool reset_fog, bool fire_events)
Function that will clear shroud (and fog) based on current unit positions.
bool get_disallow_observers() const
static void display(std::function< void()> f)
void set_game_display(game_display *)
bool is_local_human() const
events::mouse_handler & get_mouse_handler_base() override
Get a reference to a mouse handler member a derived class uses.
const std::unique_ptr< gui::textbox > & box() const
Various functions that implement healing of units (when a side turn starts).
const game_config_view & game_config_
game_classification & classification()
void toggle_skipping_replay()
A variable-expanding proxy for the config class.
Various functions that implement the undoing (and redoing) of in-game commands.
Standard logging facilities (interface).
void autosave(const bool disable_autosave, const int autosave_max, const int infinite_autosaves)
int current_side() const
Returns the number of the side whose turn it is.
Object which contains all the possible locations a unit can move to, with associated best routes to t...
void remove_scenario_fixes()
static const map_location & null_location()
game_lua_kernel * lua_kernel
config * get_next_action()
std::set< std::string > all_players() const
static lg::log_domain log_aitesting("ai/testing")
void fire_preload()
preload events cannot be synced
virtual plugins_context * get_plugins_context() override
Get (optionally) a plugins context a derived class uses.
actions::undo_list * undo_stack
play_controller(const config &level, saved_game &state_of_game, bool skip_replay)
void update_savegame_snapshot() const
const config & child_or_empty(config_key_type key) const
Returns the first child with the given key, or an empty config if there is none.
void set_side(int side_number)
const play_controller & controller_
bool next_turn(game_data *vars)
Function to move to the next turn.
A config object defines a single node in a WML file, with access to child nodes.
game_classification & get_classification()
Class that keeps track of all the keys on the keyboard.
mp_game_settings & mp_settings()
Multiplayer parameters for this game.
void delete_all_wml_hotkeys()
deletes all wml hotkeys, should be called after a game has ended
std::vector< std::string > get_commands_list()
void write(config &cfg) const
const std::set< map_location > & villages() const
void close(game_display &gui)
pathfind::manager * tunnels
bool can_undo() const
True if there are actions that can be undone.
static rng & default_instance()
virtual void check_objectives()=0
bool save_game_automatic(bool ask_for_overwrite=false, const std::string &filename="")
Saves a game without user interaction, unless the file exists and it should be asked to overwrite it...
virtual void play_side_impl()
T modulo(T num, int mod, T min=0)
void show_objectives() const
bool init_side_done_now_
Whether we did init sides in this session (false = we did init sides before we reloaded the game)...
bool remove_from_carryover_on_defeat_
void do_ai_formula(const std::string &str, int side_num, mouse_handler &mousehandler)
virtual void sync_end_turn()