76 #define LOG_AIT LOG_STREAM(info, log_aitesting) 80 #define LOG_NG LOG_STREAM(info, log_engine) 81 #define DBG_NG LOG_STREAM(debug, log_engine) 82 #define ERR_NG LOG_STREAM(err, log_engine) 85 #define ERR_DP LOG_STREAM(err, log_display) 88 #define LOG_RG LOG_STREAM(info, log_enginerefac) 91 #define DBG_EE LOG_STREAM(debug, log_engine_enemies) 98 static const std::set<std::string> attrs {
101 "victory_when_enemies_defeated",
102 "remove_from_carryover_on_defeat",
104 "experience_modifier",
109 static const std::set<std::string> tags {
115 for(
const std::string& attr : attrs) {
116 dst[attr] = src[attr];
119 for(
const std::string& tag : tags) {
146 , ticks_(SDL_GetTicks())
149 , saved_game_(state_of_game)
150 , tooltips_manager_()
151 , whiteboard_manager_()
153 , labels_manager_(new
font::floating_label_context())
154 , help_manager_(&game_config_)
155 , mouse_handler_(nullptr, *this)
156 , menu_handler_(nullptr, *this)
158 , soundsources_manager_()
162 , statistics_context_(new
statistics::scenario_context(level[
"name"]))
163 , replay_(new
replay(state_of_game.get_replay()))
164 , skip_replay_(skip_replay)
165 , skip_story_(state_of_game.skip_story())
167 , init_side_done_now_(false)
169 , start_faded_(start_faded)
170 , victory_when_enemies_defeated_(level[
"victory_when_enemies_defeated"].to_bool(true))
171 , remove_from_carryover_on_defeat_(level[
"remove_from_carryover_on_defeat"].to_bool(true))
175 , ignore_replay_errors_(false)
176 , player_type_changed_(false)
212 LOG_NG <<
"initializing game_state..." << (SDL_GetTicks() -
ticks());
227 LOG_NG <<
"initializing whiteboard..." << (SDL_GetTicks() -
ticks());
232 LOG_NG <<
"loading units..." << (SDL_GetTicks() -
ticks());
236 LOG_NG <<
"initializing theme... " << (SDL_GetTicks() -
ticks());
239 LOG_NG <<
"building terrain rules... " << (SDL_GetTicks() -
ticks());
245 gui_->set_fade({0,0,0,255});
246 gui_->set_prevent_draw(
true);
254 gui_->get_theme().modify_label(
"time-icon",
_(
"time left for current turn"));
256 gui_->get_theme().modify_label(
"time-icon",
_(
"current local time"));
264 LOG_NG <<
"done initializing display... " << (SDL_GetTicks() -
ticks());
266 LOG_NG <<
"building gamestate to gui and whiteboard... " << (SDL_GetTicks() -
ticks());
273 if(
gamestate().first_human_team_ != -1) {
280 if(!
t.get_disallow_observers()) {
281 gui_->set_team(
t.side() - 1);
311 gui_->labels().set_team(
nullptr);
341 LOG_NG <<
"initializing managers... " << (SDL_GetTicks() -
ticks());
345 LOG_NG <<
"done initializing managers... " << (SDL_GetTicks() -
ticks());
376 const config cfg(
"side",
gui_->viewing_side());
397 tm.set_start_gold(tm.gold());
469 const std::string turn_num = std::to_string(
turn());
470 const std::string side_num = std::to_string(
current_side());
475 if(!
gamestate().tod_manager_.has_turn_event_fired()) {
482 pump().
fire(
"side_" + side_num +
"_turn");
483 pump().
fire(
"side_turn_" + turn_num);
484 pump().
fire(
"side_" + side_num +
"_turn_" + turn_num);
514 patient.set_resting(
true);
522 pump().
fire(
"side_" + side_num +
"_turn_refresh");
523 pump().
fire(
"turn_" + turn_num +
"_refresh");
524 pump().
fire(
"side_" + side_num +
"_turn_" + turn_num +
"_refresh");
543 gui_->invalidate_all();
566 gui_->labels().write(cfg);
581 const std::string turn_num = std::to_string(
turn());
582 const std::string side_num = std::to_string(
current_side());
588 pump().
fire(
"side_" + side_num +
"_turn_end");
589 pump().
fire(
"side_turn_" + turn_num +
"_end");
590 pump().
fire(
"side_" + side_num +
"_turn_" + turn_num +
"_end");
604 const std::string turn_num = std::to_string(
turn());
606 pump().
fire(
"turn_" + turn_num +
"_end");
659 ERR_DP <<
"unknown textbox mode";
678 auto prev = std::find(command_history.begin(), command_history.end(), str);
680 if (
prev != command_history.end())
683 if(
prev != command_history.begin()) {
687 if(++
prev != command_history.end()) {
694 if(command_history.size() > 0) {
707 std::set<std::string> dictionary;
712 if(!
gui_->fogged(loc) && !(
get_teams()[
gui_->viewing_team()].is_enemy(u.side()) && u.invisible(loc)))
713 dictionary.insert(u.name());
720 dictionary.insert(commands.begin(), commands.end());
726 dictionary.insert(
t.current_player());
730 for(
const std::string& o :
gui_->observers()) {
731 dictionary.insert(o);
735 for(
const std::string&
w :
gui_->get_chat_manager().whisperers()) {
736 dictionary.insert(
w);
742 for(std::map<std::string, std::string>::const_iterator iter = friends.begin(); iter != friends.end(); ++iter) {
743 dictionary.insert((*iter).first);
753 ERR_DP <<
"unknown textbox mode";
792 const int num_teams =
get_teams().size();
795 for(
int i = 0;
i < num_teams;
i++) {
837 if(event.key.keysym.sym == SDLK_ESCAPE) {
839 }
else if(event.key.keysym.sym == SDLK_TAB) {
841 }
else if(event.key.keysym.sym == SDLK_UP) {
843 }
else if(event.key.keysym.sym == SDLK_DOWN) {
845 }
else if(event.key.keysym.sym == SDLK_RETURN || event.key.keysym.sym == SDLK_KP_ENTER) {
852 if(event.key.keysym.sym == SDLK_TAB) {
861 if(event.key.keysym.sym >=
'1' && event.key.keysym.sym <=
'9') {
862 const int new_path_turns = (
event.type == SDL_KEYDOWN) ? event.key.keysym.sym -
'1' : 0;
881 }
else if(event.key.keysym.sym == SDLK_TAB) {
883 if(!keys[SDLK_TAB]) {
900 assert(!
gamestate().events_manager_->is_event_running());
982 const std::vector<std::string>& music_list = victory
983 ? (
gamestate_->get_game_data()->get_victory_music().empty()
985 :
gamestate_->get_game_data()->get_victory_music())
986 : (
gamestate_->get_game_data()->get_defeat_music().empty()
988 :
gamestate_->get_game_data()->get_defeat_music());
990 if(music_list.empty()) {
992 static const std::string empty_str =
"";
1009 bool continue_level, found_player, found_network_player,
invalidate_all;
1010 std::set<unsigned> not_defeated;
1015 found_network_player,
1021 if(invalidate_all) {
1022 gui_->invalidate_all();
1025 if(continue_level) {
1029 if(found_player || found_network_player) {
1037 DBG_EE <<
"found_player: " << found_player;
1038 DBG_EE <<
"found_network_player: " << found_network_player;
1040 if(!victory_when_enemies_defeated_ && (found_player || found_network_player)) {
1047 for(
unsigned l : not_defeated) {
1051 LOG_AIT << l <<
" (using " << ai <<
") ";
1058 DBG_EE <<
"throwing end level exception...";
1076 std::stringstream message;
1077 message <<
_(
"The game is out of sync. It might not make much sense to continue. Do you want to save your game?");
1078 message <<
"\n\n" <<
_(
"Error details:") <<
"\n\n" <<
msg;
1087 gui_->set_team(team_index, observe);
1088 gui_->recalculate_minimap();
1089 gui_->invalidate_all();
1190 gui_->recalculate_minimap();
1201 gui_->recalculate_minimap();
1211 for(
const auto& endlevel : parent.
child_range(
"endlevel")) {
1212 if(endlevel.has_attribute(
"next_scenario")) {
1213 result.insert(endlevel[
"next_scenario"]);
1223 std::set<std::string> possible_next_scenarios;
1224 possible_next_scenarios.insert(
gamestate().gamedata_.next_scenario());
1235 bool possible_this_is_the_last_scenario =
false;
1236 std::vector<std::string> known;
1237 std::vector<std::string> unknown;
1238 for(
const auto& x : possible_next_scenarios) {
1239 if(x.empty() || x ==
"null") {
1240 possible_this_is_the_last_scenario =
true;
1241 LOG_NG <<
"This can be the last scenario";
1245 LOG_NG <<
"Variable value for next scenario '" << x <<
"'";
1248 LOG_NG <<
"Known next scenario '" << x <<
"'";
1250 unknown.push_back(x);
1251 ERR_NG <<
"Unknown next scenario '" << x <<
"'";
1255 if(unknown.empty()) {
1260 std::string title =
_(
"Warning: broken campaign branches");
1261 std::stringstream message;
1266 "The next scenario is missing, you will not be able to finish this campaign.",
1269 "Some of the possible next scenarios are missing, you might not be able to finish this campaign.",
1270 unknown.size() + known.size() + (possible_this_is_the_last_scenario ? 1 : 0));
1273 "Please report the following missing scenario to the campaign’s author:\n$unknown_list|",
1274 "Please report the following missing scenarios to the campaign’s author:\n$unknown_list|",
1277 message <<
_(
"Once this is fixed, you will need to restart this scenario.");
1279 std::stringstream unknown_list;
1280 for(
const auto& x : unknown) {
1284 symbols[
"unknown_list"] = unknown_list.str();
1299 std::set<std::string> res =
gui_->observers();
1302 res.insert(
t.current_player());
1312 gui_->parse_team_overlays();
1343 gui_->invalidate_game_status();
1351 int last_player_number =
gamestate_->player_number_;
1352 int next_player_number =
gamestate_->next_player_number_;
1356 next_player_number =
gamestate_->next_player_number_;
1357 last_player_number =
gamestate_->player_number_;
1372 next_player_number =
gamestate_->next_player_number_;
1373 assert(next_player_number <= 2 * static_cast<int>(
get_teams().
size()));
1395 gamestate_->player_number_ = next_player_number;
1399 gamestate_->player_number_ = last_player_number;
1416 LOG_NG <<
"firing time over event...";
1419 LOG_NG <<
"done firing time over event...";
1422 if(
gamestate().tod_manager_.is_time_left()) {
1427 LOG_AIT <<
"time over (draw)";
1444 : controller_(controller)
1457 static const std::string no_objectives(
_(
"No objectives available"));
1467 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_
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.
static std::string _n(const char *str1, const char *str2, int n)
static void log_turn_start(unsigned int side)
static void log_turn_end(unsigned int side)
::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.
const_all_children_itors all_children_range() const
In-order iteration over all children.
void reset_objectives_changed() const
std::string interpolate_variables_into_string(const std::string &str, const string_map *const symbols)
map_location last_selected
the last location where a select event fired.
The class for loading a savefile.
std::map< std::string, t_string > string_map
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)
Collection of helper functions relating to Pango formatting.
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()
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...
play_controller(const config &level, saved_game &state_of_game, bool skip_replay, bool start_faded=false)
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 do_command(const std::string &str)
void set_do_healing(bool do_healing)
static void progress(loading_stage stage=loading_stage::none)
Report what is being loaded to the loading screen.
virtual void update_viewing_player()=0
gui::floating_textbox & get_textbox()
void set_gui(game_display *gui)
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).
Keyboard shortcuts for game actions.
void memorize_command(const std::string &command)
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 invalidate_all()
Mark the entire screen as requiring redraw.
void play_sound(const std::string &files, channel_group group, unsigned int repeats)
~scoped_savegame_snapshot()
bool contains(const Container &container, const Value &value)
Returns true iff value is found in container.
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.
static void find_next_scenarios(const config &parent, std::set< std::string > &result)
Find all [endlevel]next_scenario= attributes, and add them to result.
filter_context * filter_con
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.
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.
bool headless()
The game is running headless.
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.
constexpr T modulo(T num, int mod, T min=0)
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)
constexpr uint32_t scope_game
std::shared_ptr< wb::manager > get_whiteboard() const
static void add_color_info(const game_config_view &v, bool build_defaults)
Error used for any general game error, e.g.
game_events::manager * game_events
bool is_browsing() const override
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)
const std::string unicode_bullet
static lg::log_domain log_enginerefac("enginerefac")
Class for replay saves (either manually or automatically).
config & add_child(config_key_type key)
const config & find_child(config_key_type key, const std::string &name, const std::string &value) const
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.
Handling of system events.
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
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.
std::vector< std::string > get_commands_list()
void write(config &cfg) const
void check_next_scenario_is_known()
This shows a warning dialog if either [scenario]next_scenario or any [endlevel]next_scenario would le...
const std::set< map_location > & villages() const
static void raise()
Raise the loading screen to the top of the draw stack.
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
std::string get_tagname() const
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()
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()