68 #define LOG_AIT LOG_STREAM(info, log_aitesting)
72 #define LOG_NG LOG_STREAM(info, log_engine)
73 #define DBG_NG LOG_STREAM(debug, log_engine)
74 #define ERR_NG LOG_STREAM(err, log_engine)
77 #define ERR_DP LOG_STREAM(err, log_display)
80 #define LOG_RG LOG_STREAM(info, log_enginerefac)
83 #define DBG_EE LOG_STREAM(debug, log_engine_enemies)
90 static const std::set<std::string> attrs {
94 "experience_modifier",
99 static const std::set<std::string> tags {
105 for(
const std::string& attr : attrs) {
109 for(
const std::string&
tag : tags) {
139 , saved_game_(state_of_game)
140 , tooltips_manager_()
141 , whiteboard_manager_()
143 , labels_manager_(new
font::floating_label_context())
144 , help_manager_(&game_config_)
145 , mouse_handler_(*this)
146 , menu_handler_(*this)
148 , soundsources_manager_()
152 , statistics_context_(new
statistics_t(state_of_game.statistics()))
153 , replay_(new
replay(state_of_game.get_replay()))
154 , skip_replay_(false)
155 , skip_story_(state_of_game.skip_story())
156 , did_autosave_this_turn_(true)
157 , did_tod_sound_this_turn_(false)
163 , ignore_replay_errors_(false)
164 , player_type_changed_(false)
237 LOG_NG <<
"initializing display (includes theme init and building terrain rules)... " <<
timer();
242 gui_->set_fade({0,0,0,255});
243 gui_->set_prevent_draw(
true);
251 gui_->get_theme().modify_label(
"time-icon",
_(
"time left for current turn"));
253 gui_->get_theme().modify_label(
"time-icon",
_(
"current local time"));
260 LOG_NG <<
"done initializing display... " <<
timer();
262 LOG_NG <<
"building gamestate to gui and whiteboard... " <<
timer();
289 ERR_NG <<
"plugin called synced command while whiteboard is applied, ignoring";
290 pm.notify_event(
"synced_command_error",
config{
"error",
"whiteboard"});
299 ERR_NG <<
"synced command called too early, only allowed at START or later";
300 pm.notify_event(
"synced_command_error",
config{
"error",
"too-early"});
304 ERR_NG <<
"synced command can only be used during a turn when a user would also be able to invoke commands";
305 pm.notify_event(
"synced_command_error",
config{
"error",
"not-your-turn"});
309 ERR_NG <<
"synced command cannot be invoked while commands are blocked";
310 pm.notify_event(
"synced_command_error",
config{
"error",
"disabled"});
314 ERR_NG <<
"synced command can only be used from clients that control the currently playing side";
315 pm.notify_event(
"synced_command_error",
config{
"error",
"not-your-turn"});
319 ERR_NG <<
"synced command from plugin raised an error: " << message;
320 pm.notify_event(
"synced_command_error",
config{
"error",
"error",
"message", message});
343 gui_->labels().set_team(
nullptr);
378 LOG_NG <<
"done initializing managers... " <<
timer();
410 const config cfg(
"side",
gui_->viewing_team().side());
432 tm.set_start_gold(tm.gold());
503 const std::string turn_num = std::to_string(
turn());
504 const std::string side_num = std::to_string(
current_side());
509 if(!
gamestate().tod_manager_.has_turn_event_fired()) {
516 pump().
fire(
"side_" + side_num +
"_turn");
517 pump().
fire(
"side_turn_" + turn_num);
518 pump().
fire(
"side_" + side_num +
"_turn_" + turn_num);
548 patient.set_resting(
true);
556 pump().
fire(
"side_" + side_num +
"_turn_refresh");
557 pump().
fire(
"turn_" + turn_num +
"_refresh");
558 pump().
fire(
"side_" + side_num +
"_turn_" + turn_num +
"_refresh");
599 gui_->labels().write(cfg);
602 if(cfg[
"replay_pos"].to_int(0) > 0 && cfg[
"playing_team"].empty()) {
618 const std::string turn_num = std::to_string(
turn());
619 const std::string side_num = std::to_string(
current_side());
625 pump().
fire(
"side_" + side_num +
"_turn_end");
626 pump().
fire(
"side_turn_" + turn_num +
"_end");
627 pump().
fire(
"side_" + side_num +
"_turn_" + turn_num +
"_end");
639 const std::string turn_num = std::to_string(
turn());
641 pump().
fire(
"turn_" + turn_num +
"_end");
696 ERR_DP <<
"unknown textbox mode";
709 auto prev =
std::find(command_history.begin(), command_history.end(), str);
711 if (
prev != command_history.end())
714 if(
prev != command_history.begin()) {
718 if(++
prev != command_history.end()) {
725 if(command_history.size() > 0) {
738 std::set<std::string> dictionary;
743 if(!
gui_->fogged(
loc) && !(
gui_->viewing_team().is_enemy(u.side()) && u.invisible(
loc)))
744 dictionary.insert(u.name());
751 dictionary.insert(commands.begin(), commands.end());
757 dictionary.insert(
t.current_player());
761 for(
const std::string& o :
gui_->observers()) {
762 dictionary.insert(o);
766 for(
const std::string&
w :
gui_->get_chat_manager().whisperers()) {
767 dictionary.insert(
w);
773 for(std::map<std::string, std::string>::const_iterator iter = friends.begin(); iter != friends.end(); ++iter) {
774 dictionary.insert((*iter).first);
784 ERR_DP <<
"unknown textbox mode";
843 if(event.key.keysym.sym == SDLK_ESCAPE) {
845 }
else if(event.key.keysym.sym == SDLK_TAB) {
847 }
else if(event.key.keysym.sym == SDLK_UP) {
849 }
else if(event.key.keysym.sym == SDLK_DOWN) {
851 }
else if(event.key.keysym.sym == SDLK_RETURN || event.key.keysym.sym == SDLK_KP_ENTER) {
858 if(event.key.keysym.sym == SDLK_TAB) {
867 if(event.key.keysym.sym >=
'1' && event.key.keysym.sym <=
'9') {
868 const int new_path_turns = (
event.type == SDL_KEYDOWN) ? event.key.keysym.sym -
'1' : 0;
887 }
else if(event.key.keysym.sym == SDLK_TAB) {
889 if(!
keys[SDLK_TAB]) {
905 assert(!
gamestate().events_manager_->is_event_running());
939 load.load_game_ingame();
966 const std::vector<std::string>& music_list = victory
967 ? (
gamestate_->get_game_data()->get_victory_music().empty()
969 :
gamestate_->get_game_data()->get_victory_music())
970 : (
gamestate_->get_game_data()->get_defeat_music().empty()
972 :
gamestate_->get_game_data()->get_defeat_music());
974 if(music_list.empty()) {
976 static const std::string empty_str =
"";
993 bool continue_level, found_player, found_network_player,
invalidate_all;
994 std::set<unsigned> not_defeated;
999 found_network_player,
1002 gamestate().remove_from_carryover_on_defeat_
1006 gui_->invalidate_all();
1009 if(continue_level) {
1013 if(found_player || found_network_player) {
1021 DBG_EE <<
"found_player: " << found_player;
1022 DBG_EE <<
"found_network_player: " << found_network_player;
1024 if(!
gamestate().victory_when_enemies_defeated_ && (found_player || found_network_player)) {
1031 for(
unsigned l : not_defeated) {
1035 LOG_AIT << l <<
" (using " <<
ai <<
") ";
1042 DBG_EE <<
"throwing end level exception...";
1061 std::stringstream message;
1062 message <<
_(
"The game is out of sync. It might not make much sense to continue. Do you want to save your game?");
1063 message <<
"\n\n" <<
_(
"Error details:") <<
"\n\n" <<
msg;
1077 gui_->set_viewing_team_index(team_index, observe);
1078 gui_->recalculate_minimap();
1079 gui_->invalidate_all();
1129 return !
t.is_local_human() || !
t.is_proxy_human();
1174 gui_->recalculate_minimap();
1185 gui_->recalculate_minimap();
1195 for(
const auto& endlevel : parent.
child_range(
"endlevel")) {
1196 if(endlevel.has_attribute(
"next_scenario")) {
1197 result.insert(endlevel[
"next_scenario"]);
1207 std::set<std::string> possible_next_scenarios;
1208 possible_next_scenarios.insert(
gamestate().gamedata_.next_scenario());
1219 bool possible_this_is_the_last_scenario =
false;
1220 std::vector<std::string> known;
1221 std::vector<std::string> unknown;
1222 for(
const auto& x : possible_next_scenarios) {
1223 if(x.empty() || x ==
"null") {
1224 possible_this_is_the_last_scenario =
true;
1225 LOG_NG <<
"This can be the last scenario";
1229 LOG_NG <<
"Variable value for next scenario '" << x <<
"'";
1232 LOG_NG <<
"Known next scenario '" << x <<
"'";
1234 unknown.push_back(x);
1235 ERR_NG <<
"Unknown next scenario '" << x <<
"'";
1239 if(unknown.empty()) {
1244 std::string title =
_(
"Warning: broken campaign branches");
1245 std::stringstream message;
1250 "The next scenario is missing, you will not be able to finish this campaign.",
1253 "Some of the possible next scenarios are missing, you might not be able to finish this campaign.",
1254 unknown.size() + known.size() + (possible_this_is_the_last_scenario ? 1 : 0));
1257 "Please report the following missing scenario to the campaign’s author:\n$unknown_list|",
1258 "Please report the following missing scenarios to the campaign’s author:\n$unknown_list|",
1261 message <<
_(
"Once this is fixed, you will need to restart this scenario.");
1263 std::stringstream unknown_list;
1264 for(
const auto& x : unknown) {
1268 symbols[
"unknown_list"] = unknown_list.str();
1276 const team& viewing_team =
gui_->viewing_team();
1283 std::set<std::string> res =
gui_->observers();
1286 res.insert(
t.current_player());
1298 LOG_NG <<
"firing time over event...";
1301 LOG_NG <<
"done firing time over event...";
1304 if(
gamestate().tod_manager_.is_time_left()) {
1309 LOG_AIT <<
"time over (draw)";
1320 e.proceed_to_next_level =
false;
1321 e.is_victory =
false;
1334 controller_.saved_game_.remove_snapshot();
1340 static const std::string no_objectives(
_(
"No objectives available"));
1343 t.reset_objectives_changed();
1350 if(skip_animation_button) {
Managing the AIs lifecycle - headers TODO: Refactor history handling and internal commands.
Class that keeps track of all the keys on the keyboard.
void new_side_turn(int side)
Performs some initializations and error checks when starting a new side-turn.
bool can_undo() const
True if there are actions that can be undone.
void redo()
Redoes the top action on the redo stack.
bool can_redo() const
True if there are actions that can be redone.
void undo()
Undoes the top action on the undo stack.
std::string get_active_ai_identifier_for_side(side_number side)
Gets AI algorithm identifier for active AI of the given side.
void raise_gamestate_changed()
Notifies all observers of 'ai_gamestate_changed' event.
static manager & get_singleton()
static void log_victory(const std::set< unsigned int > &teams)
A config object defines a single node in a WML file, with access to child nodes.
auto all_children_view() const
In-order iteration over all children.
const_all_children_itors all_children_range() const
In-order iteration over all children.
child_itors child_range(config_key_type key)
config & add_child(config_key_type key)
const game_config_view & game_config_
virtual void play_slice()
int side_upkeep(int side_num) const
std::shared_ptr< gui::button > find_action_button(const std::string &id)
Retrieves a pointer to a theme UI button.
void do_ai_formula(const std::string &str, int side_num, mouse_handler &mousehandler)
gui::floating_textbox & get_textbox()
void do_command(const std::string &str)
void do_search(const std::string &new_search)
void set_gui(game_display *gui)
std::vector< std::string > get_commands_list()
void set_gui(game_display *gui)
const pathfind::paths & current_paths() const
void set_current_paths(const pathfind::paths &new_paths)
unit_map::iterator selected_unit()
map_location get_selected_hex() const
void select_hex(const map_location &hex, const bool browse, const bool highlight=true, const bool fire_event=true, const bool force_unhighlight=false)
int get_path_turns() const
void set_side(int side_number)
void set_path_turns(const int path_turns)
void check_victory(bool &, bool &, bool &, bool &, std::set< unsigned > &, bool)
std::string get_tagname() const
optional_const_config find_child(config_key_type key, const std::string &name, const std::string &value) const
static game_config_view wrap(const config &cfg)
void set_phase(PHASE phase)
@ PRELOAD
the preload [event] is fired next phase: PRESTART (normal game), TURN_STARTING_WAITING (reloaded game...
@ INITIAL
creating intitial [unit]s, executing toplevel [lua] etc.
@ GAME_ENDED
The game has ended and the user is observing the final state "lingering" The game can be saved here.
@ PRESTART
the prestart [event] is fired next phase: START (default), GAME_ENDING
@ TURN_PLAYING
The User is controlling the game and invoking actions The game can be saved here.
@ TURN_STARTING_WAITING
we are waiting for the turn to start.
@ START
the start [event] is fired next phase: TURN_STARTING_WAITING (default), GAME_ENDING
@ TURN_STARTING
the turn, side turn etc.
map_location last_selected
the last location where a select event fired.
config::attribute_value & get_variable(const std::string &varname)
throws invalid_variablename_exception if varname is no valid variable name.
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.
void write(config &cfg) const
bool in_phase(game_data::PHASE phase) const
void set_game_display(game_display *)
std::unique_ptr< game_lua_kernel > lua_kernel_
std::unique_ptr< pathfind::manager > pathfind_manager_
const std::unique_ptr< game_events::manager > events_manager_
bool victory_when_enemies_defeated_
static void progress(loading_stage stage=loading_stage::none)
Report what is being loaded to the loading screen.
static void raise()
Raise the loading screen to the top of the draw stack.
static void display(const std::function< void()> &f)
@ close_button
Shows a close button.
void memorize_command(const std::string &command)
const std::unique_ptr< gui::textbox > & box() const
TEXTBOX_MODE mode() const
void tab(const std::set< std::string > &dictionary)
const std::vector< std::string > & command_history() const
game_classification & get_classification()
const std::string & select_music(bool victory) const
void process_keydown_event(const SDL_Event &event) override
Process keydown (always).
bool ignore_replay_errors_
void maybe_throw_return_to_play_side() const
config to_config() const
Builds the snapshot config from members and their respective configs.
void init(const config &level)
std::vector< team > & get_teams()
std::unique_ptr< hotkey_handler > hotkey_handler_
bool have_keyboard_focus() override
Derived classes should override this to return false when arrow keys should not scroll the map,...
std::unique_ptr< game_state > gamestate_
void show_objectives() const
events::menu_handler menu_handler_
void fire_preload()
preload events cannot be synced
void check_victory()
Checks to see if a side has won.
bool is_linger_mode() const
actions::undo_list & undo_stack()
statistics_t & statistics()
virtual soundsource::manager * get_soundsource_man() override
Get (optionally) a soundsources manager a derived class uses.
void check_next_scenario_is_known()
This shows a warning dialog if either [scenario]next_scenario or any [endlevel]next_scenario would le...
bool reveal_map_default() const
const unit_map & get_units() const
play_controller(const config &level, saved_game &state_of_game)
void set_end_level_data(const end_level_data &data)
events::mouse_handler & get_mouse_handler_base() override
Get a reference to a mouse handler member a derived class uses.
void update_savegame_snapshot() const
void set_do_healing(bool do_healing)
bool is_skipping_actions() const
bool is_during_turn() const
virtual void require_end_turn()=0
bool can_use_synced_wml_menu() const
void reset_gamestate(const config &level, int replay_pos)
void do_consolesave(const std::string &filename)
void save_game_auto(const std::string &filename)
void textbox_move_vertically(bool up)
bool is_regular_game_end() const
virtual void check_objectives()=0
void save_replay_auto(const std::string &filename)
hotkey::command_executor * get_hotkey_command_executor() override
Optionally get a command executor to handle context menu events.
bool enemies_visible() const
std::unique_ptr< replay > replay_
const mp_game_settings & get_mp_settings()
game_display & get_display() override
Get a reference to a display member a derived class uses.
virtual void update_viewing_player()=0
std::unique_ptr< game_display > gui_
void toggle_skipping_replay()
void maybe_do_init_side()
Called by turn_info::process_network_data() or init_side() to call do_init_side() if necessary.
virtual void process_oos(const std::string &msg) const
Asks the user whether to continue on an OOS error.
bool is_browsing() const override
std::unique_ptr< soundsource::manager > soundsources_manager_
void do_init_side()
Called by replay handler or init_side() to do actual work for turn change.
std::string theme() const
int current_side() const
Returns the number of the side whose turn it is.
bool is_skipping_replay() const
bool did_tod_sound_this_turn_
std::shared_ptr< wb::manager > get_whiteboard() const
bool did_autosave_this_turn_
Whether we did init sides in this session (false = we did init sides before we reloaded the game).
virtual bool should_return_to_play_side() const
std::set< std::string > all_players() const
void update_gui_to_player(const int team_index, const bool observe=false)
Changes the UI for this client to the passed side index.
events::mouse_handler mouse_handler_
const auto & timer() const
std::unique_ptr< plugins_context > plugins_context_
virtual plugins_context * get_plugins_context() override
Get (optionally) a plugins context a derived class uses.
virtual ~play_controller()
void process_focus_keydown_event(const SDL_Event &event) override
Process keydown (only when the general map display does not have focus).
void refresh_objectives() const
Reevaluate [show_if] conditions and build a new objectives string.
game_events::wml_event_pump & pump()
void process_keyup_event(const SDL_Event &event) override
Process keyup (always).
void finish_side_turn_events()
std::shared_ptr< wb::manager > whiteboard_manager_
virtual void check_time_over()
t_string get_scenario_name() const
static plugins_manager * get()
void encounter_all_content(const game_board &gb)
std::map< std::string, std::string > get_acquaintances_nice(const std::string &filter)
Implements a quit confirmation dialog.
static rng & default_instance()
int get_random_int(int min, int max)
bool add_start_if_not_there_yet()
config * get_next_action()
Exception used to escape form the ai or ui code to playsingle_controller::play_side.
game_classification & classification()
mp_game_settings & mp_settings()
Multiplayer parameters for this game.
replay_recorder_base & get_replay()
config & set_snapshot(config snapshot)
void autosave(const bool disable_autosave, const int autosave_max, const int infinite_autosaves)
Class for "normal" midgame saves.
The class for loading a savefile.
Class for replay saves (either manually or automatically).
static std::shared_ptr< save_index_class > default_saves_dir()
Returns an instance for managing saves in filesystem::get_saves_dir()
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.
bool save_game_interactive(const std::string &message, DIALOG_TYPE dialog_type)
Save a game interactively through the savegame dialog.
A RAII object to enter the synced context, cannot be called if we are already in a synced context.
void do_final_checkup(bool dont_throw=false)
void reset_turn_stats(const std::string &save_id)
static bool run_in_synced_context_if_not_already(const std::string &commandname, const config &data, action_spectator &spectator=get_default_spectator())
Checks whether we are currently running in a synced context, and if not we enters it.
static synced_state get_synced_state()
static void block_undo(bool do_block=true, bool clear_undo=true)
set this to false to prevent clearing the undo stack, this is important when we cannot change the gam...
This class stores all the data for a single 'side' (in game nomenclature).
int support() const
Calculate total support capacity, based on support_per_village.
bool is_local_human() const
void spend_gold(const int amount)
const time_of_day & get_time_of_day(int for_turn=0) const
Returns global time of day for the passed turn.
bool next_turn(game_data *vars)
Function to move to the next turn.
void remove_scenario_fixes()
void apply_scenario_fix(const config &cfg)
This class represents a single unit of a specific type.
A variable-expanding proxy for the config class.
This class is the frontend of the whiteboard framework for the rest of the Wesnoth code.
void throw_quit_game_exception()
static std::string _n(const char *str1, const char *str2, int n)
static std::string _(const char *str)
void calculate_healing(int side, bool update_display)
Calculates healing for all units for the given side.
Various functions that implement healing of units (when a side turn starts).
This file implements all the hotkey handling and menu details for play controller.
Standard logging facilities (interface).
#define log_scope(description)
bool clear_shroud(int side, bool reset_fog, bool fire_events)
Function that will clear shroud (and fog) based on current unit positions.
void recalculate_fog(int side)
Function that recalculates the fog of war.
A small explanation about what's going on here: Each action has access to two game_info objects First...
void invalidate_all()
Mark the entire screen as requiring redraw.
Handling of system events.
const std::string unicode_bullet
std::vector< std::string > default_defeat_music
bool ignore_replay_errors
static void add_color_info(const game_config_view &v, bool build_defaults)
std::vector< std::string > default_victory_music
std::vector< game_tip > load(const config &cfg)
Loads the tips from a config.
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)
Shows a transient message to the user.
void show_error_message(const std::string &msg, bool message_use_markup)
Shows an error message to the user.
void show_message(const std::string &title, const std::string &msg, const std::string &button_caption, const bool auto_close, const bool message_use_markup, const bool title_use_markup)
Shows a message to the user.
Keyboard shortcuts for game actions.
constexpr uint32_t scope_game
std::string tag(std::string_view tag, Args &&... data)
Wraps the given data in the specified tag.
const int INFINITE_AUTO_SAVES
::tod_manager * tod_manager
persist_manager * persist
game_events::manager * game_events
actions::undo_list * undo_stack
soundsource::manager * soundsources
game_lua_kernel * lua_kernel
game_classification * classification
pathfind::manager * tunnels
play_controller * controller
filter_context * filter_con
std::shared_ptr< wb::manager > whiteboard
void write_music_play_list(config &snapshot)
void play_sound(const std::string &files, channel_group group, unsigned int repeats)
std::size_t size(std::string_view str)
Length in characters of a UTF-8 string.
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 ...
bool contains(const Container &container, const Value &value)
Returns true iff value is found in container.
std::string get_unknown_exception_type()
Utility function for finding the type of thing caught with catch(...).
std::map< std::string, t_string > string_map
auto * find(Container &container, const Value &value)
Convenience wrapper for using find on a container without needing to comare to end()
bool headless()
The game is running headless.
static void msg(const char *act, debug_info &i, const char *to="", const char *result="")
static void clear_resources()
static lg::log_domain log_engine("engine")
static lg::log_domain log_aitesting("ai/testing")
static void find_next_scenarios(const config &parent, std::set< std::string > &result)
Find all [endlevel]next_scenario= attributes, and add them to result.
static void copy_persistent(const config &src, config &dst)
Copies [scenario] attributes/tags that are not otherwise stored in C++ structs/clases.
static lg::log_domain log_enginerefac("enginerefac")
static lg::log_domain log_display("display")
static lg::log_domain log_engine_enemies("engine/enemies")
Define the game's event mechanism.
rect dst
Location on the final composed sheet.
rect src
Non-transparent portion of the surface to compose.
std::string filename
Filename.
Additional information on the game outcome which can be provided by WML.
bool proceed_to_next_level
whether to proceed to the next scenario, equals is_victory in sp.
transient_end_level transient
Error used for any general game error, e.g.
Encapsulates the map of the game.
static const map_location & null_location()
std::chrono::seconds mp_countdown_init_time
Object which contains all the possible locations a unit can move to, with associated best routes to t...
~scoped_savegame_snapshot()
scoped_savegame_snapshot(const play_controller &controller)
const play_controller & controller_
Object which defines a time of day with associated bonuses, image, sounds etc.
std::string sounds
List of "ambient" sounds associated with this time_of_day, Played at the beginning of turn.
bool reveal_map
Should we reveal map when game is ended? (Multiplayer only)
Object which temporarily resets a unit's movement.
const std::string & gamedata
Gather statistics important for AI testing and output them.
unit_type_data unit_types
Various functions that implement the undoing (and redoing) of in-game commands.
Various functions implementing vision (through fog of war and shroud).