67 #define DBG_NG LOG_STREAM(debug, log_engine) 68 #define LOG_NG LOG_STREAM(info, log_engine) 69 #define WRN_NG LOG_STREAM(warn, log_engine) 70 #define ERR_NG LOG_STREAM(err, log_engine) 73 #define DBG_DP LOG_STREAM(debug, log_display) 74 #define LOG_DP LOG_STREAM(info, log_display) 77 #define LOG_WML LOG_STREAM(info, log_wml) 78 #define WRN_WML LOG_STREAM(warn, log_wml) 79 #define ERR_WML LOG_STREAM(err, log_wml) 82 #define ERR_CF LOG_STREAM(err, log_config) 107 std::string
type = cfg[
"type"];
108 std::string variation = cfg[
"variation"];
109 std::string img_mods = cfg[
"image_mods"];
111 std::size_t side_num = cfg[
"side"].to_int(1);
121 if(!variation.empty()) {
124 effect[
"apply_to"] =
"variation";
125 effect[
"name"] = variation;
126 fake->add_modification(
"variation",mod);
129 if(!img_mods.empty()) {
132 effect[
"apply_to"] =
"image_mod";
133 effect[
"add"] = img_mods;
134 fake->add_modification(
"image_mod",mod);
140 std::vector<map_location> fake_unit_path(
const unit& fake_unit,
const std::vector<std::string>& xvals,
const std::vector<std::string>& yvals)
143 std::vector<map_location>
path;
146 for(std::size_t
i = 0;
i != std::min(xvals.size(),yvals.size()); ++
i) {
151 }
catch(std::invalid_argument&) {
152 ERR_CF <<
"Invalid move_unit_fake source: " << xvals[
i] <<
", " << yvals[
i] <<
'\n';
156 ERR_CF <<
"Invalid move_unit_fake source: " << src <<
'\n';
170 }
catch(std::invalid_argument&) {
171 ERR_CF <<
"Invalid move_unit_fake destination: " << xvals[
i] <<
", " << yvals[
i] <<
'\n';
174 ERR_CF <<
"Invalid move_unit_fake destination: " << dst <<
'\n';
179 game_map->
w(), game_map->
h());
181 if (route.
steps.empty()) {
182 WRN_NG <<
"Could not find move_unit_fake route from " << src <<
" to " << dst <<
": ignoring complexities" << std::endl;
186 game_map->
w(), game_map->
h());
187 if(route.
steps.empty()) {
191 WRN_NG <<
"Could not find move_unit_fake route from " << src <<
" to " << dst <<
": ignoring terrain" << std::endl;
193 route =
a_star_search(src, dst, 10000, dummy_calc, game_map->
w(), game_map->
h());
194 assert(!route.
steps.empty());
200 path.insert(path.end(),
249 #define WML_HANDLER_FUNCTION(pname, pei, pcfg) \ 250 static void wml_func_##pname(const queued_event &pei, const vconfig &pcfg); \ 251 static wml_action wml_action_##pname(#pname, &wml_func_##pname); \ 252 static void wml_func_##pname(const queued_event& pei, const vconfig& pcfg) 267 ERR_NG <<
"Error via [do_command]:" << std::endl;
268 ERR_NG << message << std::endl;
281 ERR_NG <<
"[do_command] called while whiteboard is applied, ignoring" << std::endl;
285 static const std::set<std::string> allowed_tags {
"attack",
"move",
"recruit",
"recall",
"disband",
"fire_event",
"custom_command"};
292 ERR_NG <<
"[do_command] called too early, only allowed at START or later" << std::endl;
297 ERR_NG <<
"[do_command] cannot be used in linger mode" << std::endl;
302 ERR_NG <<
"[do_command] cannot be used before the turn has started" << std::endl;
305 if(is_unsynced && is_unsynced_too_early)
307 ERR_NG <<
"[do_command] called too early" << std::endl;
312 ERR_NG <<
"[do_command] cannot invoke synced commands while commands are blocked" << std::endl;
317 ERR_NG <<
"[do_command] can only be used from clients that control the currently playing side" << std::endl;
322 if(allowed_tags.find(
i.get_key()) == allowed_tags.end()) {
323 ERR_NG <<
"unsupported tag [" <<
i.get_key() <<
"] in [do_command]" << std::endl;
325 std::copy(allowed_tags.begin(), allowed_tags.end(), std::ostream_iterator<std::string>(o,
" "));
326 ERR_NG <<
"allowed tags: " << o.str() << std::endl;
336 i.get_child().get_parsed_config(),
356 std::string add = cfg[
"add"];
361 }
else if(!value.
empty()) {
365 if(!current.
empty()) {
366 const unsigned int current_turn_number = tod_man.
turn();
367 int new_turn_number = current.
to_int(current_turn_number);
368 const unsigned int new_turn_number_u =
static_cast<unsigned int>(new_turn_number);
370 ERR_NG <<
"attempted to change current turn number to one out of range (" << new_turn_number <<
")" << std::endl;
371 }
else if(new_turn_number_u != current_turn_number) {
387 if(!dummy_unit.
get())
390 const bool force_scroll = cfg[
"force_scroll"].to_bool(
true);
392 const std::string x = cfg[
"x"];
393 const std::string y = cfg[
"y"];
398 const std::vector<map_location>&
path = fake_unit_path(*dummy_unit, xvals, yvals);
409 LOG_NG <<
"Processing [move_units_fake]\n";
411 const bool force_scroll = cfg[
"force_scroll"].to_bool();
413 std::size_t num_units = unit_cfgs.size();
414 std::vector<fake_unit_ptr > units;
415 units.reserve(num_units);
416 std::vector<std::vector<map_location>> paths;
417 paths.reserve(num_units);
419 LOG_NG <<
"Moving " << num_units <<
" units\n";
421 std::size_t longest_path = 0;
426 int skip_steps =
config[
"skip_steps"];
429 paths.push_back(fake_unit_path(*u, xvals, yvals));
431 paths.back().insert(paths.back().begin(), skip_steps, paths.back().front());
432 longest_path = std::max(longest_path, paths.back().size());
433 DBG_NG <<
"Path " << paths.size() - 1 <<
" has length " << paths.back().size() <<
'\n';
435 u->set_location(paths.back().front());
439 LOG_NG <<
"Units placed, longest path is " << longest_path <<
" long\n";
441 std::vector<map_location> path_step(2);
443 for(std::size_t step = 1; step < longest_path; ++step) {
444 DBG_NG <<
"Doing step " << step <<
"...\n";
445 for(std::size_t un = 0; un < num_units; ++un) {
446 if(step >= paths[un].
size() || paths[un][step - 1] == paths[un][step])
448 DBG_NG <<
"Moving unit " << un <<
", doing step " << step <<
'\n';
449 path_step[0] = paths[un][step - 1];
450 path_step[1] = paths[un][step];
452 units[un]->set_location(path_step[1]);
453 units[un]->anim_comp().set_standing(
false);
457 LOG_NG <<
"Units moved\n";
468 LOG_NG <<
"recalling unit...\n";
469 config temp_config(cfg.get_config());
477 temp_config[
"x"] =
"recall";
478 temp_config[
"y"] =
"recall";
480 vconfig unit_filter_cfg(temp_config);
481 const vconfig & leader_filter = cfg.
child(
"secondary_unit");
488 DBG_NG <<
"recall list is empty when trying to recall!\n" 489 <<
"player_id: " << player_id <<
" side: " << index+1 <<
"\n";
499 DBG_NG <<
"checking unit against filter...\n";
502 DBG_NG << (*u)->id() <<
" matched the filter...\n";
504 const unit* pass_check = to_recruit.get();
505 if(!cfg[
"check_passability"].to_bool(
true)) pass_check =
nullptr;
507 if(cfg.has_attribute(
"location_id")) {
509 const auto& iter = special_locs.find(cfg[
"location_id"]);
510 if(iter != special_locs.end()) {
511 cfg_loc = iter->second;
516 DBG_NG <<
"...considering " + leader->id() +
" as the recalling leader...\n";
518 if ( lfilt(*leader) &&
520 DBG_NG <<
"...matched the leader filter and is able to recall the unit.\n";
522 loc = leader->get_location();
526 DBG_NG <<
"...valid location for the recall found. Recalling.\n";
530 cfg[
"show"].to_bool(
true), cfg[
"fire_event"].to_bool(
false),
542 DBG_NG <<
"No usable leader found, but found usable location. Recalling.\n";
547 cfg[
"show"].to_bool(
true), cfg[
"fire_event"].to_bool(
false),
555 LOG_WML <<
"A [recall] tag with the following content failed:\n" << cfg.get_config().debug();
561 map_choice(
const std::string& filename) :
filename_(filename) {}
563 virtual config query_user(
int )
const override 566 return config {
"map_data", res};
568 virtual config random_choice(
int )
const override 572 virtual std::string description()
const override 576 virtual bool is_visible()
const override 604 if(!cfg[
"map_file"].empty()) {
606 map.
read(file_cfg[
"map_data"].str(),
false);
607 }
else if(!cfg[
"map_data"].empty()) {
608 map.
read(cfg[
"map_data"],
false);
611 map.
read(cfg[
"map"],
false);
614 const std::string log_map_name = cfg[
"map"].empty() ? cfg[
"map_file"] : std::string(
"from inline data");
615 lg::wml_error() <<
"replace_map: Unable to load map " << log_map_name << std::endl;
624 if (!cfg[
"expand"].to_bool()) {
625 lg::wml_error() <<
"replace_map: Map dimension(s) increase but expand is not set" << std::endl;
632 if (!cfg[
"shrink"].to_bool()) {
633 lg::wml_error() <<
"replace_map: Map dimension(s) decrease but shrink is not set" << std::endl;
664 ERR_NG <<
"trying to set a variable with an empty name:\n" << cfg.get_config().debug();
668 std::vector<config> data;
669 if(cfg.has_attribute(
"to_variable"))
681 ERR_NG <<
"Cannot do [set_variables] with invalid to_variable variable: " << cfg[
"to_variable"] <<
" with " << cfg.get_config().debug() << std::endl;
684 typedef std::pair<std::string, vconfig> vchild;
685 for (
const vchild&
p : cfg.all_ordered()) {
686 if(
p.first ==
"value") {
687 data.push_back(
p.second.get_parsed_config());
688 }
else if(
p.first ==
"literal") {
689 data.push_back(
p.second.get_config());
690 }
else if(
p.first ==
"split") {
691 const vconfig & split_element =
p.second;
693 std::string split_string=split_element[
"list"];
694 std::string separator_string=split_element[
"separator"];
695 std::string key_name=split_element[
"key"];
701 bool remove_empty = split_element[
"remove_empty"].to_bool();
703 char* separator = separator_string.
empty() ? nullptr : &separator_string[0];
704 if(separator_string.size() > 1){
705 ERR_NG <<
"[set_variables] [split] separator only supports 1 character, multiple passed: " << split_element[
"separator"] <<
" with " << cfg.
get_config().
debug() << std::endl;
708 std::vector<std::string> split_vector;
711 if(separator ==
nullptr)
715 split_vector.push_back(std::string(1, *
i));
724 data.emplace_back(key_name, *
i);
731 const std::string& mode = cfg[
"mode"];
738 for (
const config &ch : data) {
739 merged_children.
append(ch);
741 data = {merged_children};
745 else if(mode ==
"insert")
749 else if(mode ==
"append")
760 ERR_NG <<
"Cannot do [set_variables] with invalid destination variable: " << name <<
" with " << cfg.get_config().debug() << std::endl;
771 if (!cfg.child(
"source")) {
772 WRN_NG <<
"No source in [store_relative_direction]" << std::endl;
775 if (!cfg.child(
"destination")) {
776 WRN_NG <<
"No destination in [store_relative_direction]" << std::endl;
779 if (!cfg.has_attribute(
"variable")) {
780 WRN_NG <<
"No variable in [store_relative_direction]" << std::endl;
787 std::string variable = cfg[
"variable"];
797 ERR_NG <<
"Cannot do [store_relative_direction] with invalid destination variable: " << variable <<
" with " << cfg.get_config().debug() << std::endl;
809 if (!cfg.child(
"source")) {
810 WRN_NG <<
"No source in [store_rotate_map_location]" << std::endl;
813 if (!cfg.child(
"destination")) {
814 WRN_NG <<
"No destination in [store_rotate_map_location]" << std::endl;
817 if (!cfg.has_attribute(
"variable")) {
818 WRN_NG <<
"No variable in [store_rotate_map_location]" << std::endl;
825 std::string variable = cfg[
"variable"];
826 int angle = cfg[
"angle"].to_int(1);
832 dst.rotate_right_around_center(src,angle).write(store.
as_container());
836 ERR_NG <<
"Cannot do [store_rotate_map_location] with invalid destination variable: " << variable <<
" with " << cfg.get_config().debug() << std::endl;
849 int turn = cfg[
"turn"];
853 std::string variable = cfg[
"variable"];
854 if(variable.empty()) {
855 variable =
"time_of_day";
864 ERR_NG <<
"Found invalid variablename " << variable <<
" in [store_time_of_day] with " << cfg.get_config().debug() <<
"\n";
870 const bool remove = cfg[
"remove"].to_bool(
false);
871 const bool delay = cfg[
"delayed_variable_substitution"].to_bool(
true);
873 const std::vector<std::string> ids =
utils::split(cfg[
"id"]);
874 for (
const std::string &
id : ids) {
877 }
else if (cfg.get_children(
"source").empty() ||
878 cfg.get_children(
"target").empty() ||
879 cfg.get_children(
"filter").empty()) {
880 ERR_WML <<
"[tunnel] is missing a mandatory tag:\n" 881 << cfg.get_config().debug();
886 if(cfg[
"bidirectional"].to_bool(
true)) {
897 config parsed_cfg = cfg.get_parsed_config();
900 if (!to_variable.
blank())
908 new_unit->write(var);
914 ERR_NG <<
"Cannot do [unit] with invalid to_variable: " << to_variable <<
" with " << cfg.get_config().debug() << std::endl;
920 int side = parsed_cfg[
"side"].to_int(1);
946 if(cfg[
"delayed_variable_substitution"].to_bool(
false)) {
std::optional< std::string > replace_map(const gamemap &r)
void verify_and_get_global_variable(const vconfig &pcfg)
play_controller * controller
static void add_undo_commands(const config &commands, const game_events::queued_event &ctx)
bool empty() const
Tests for an attribute that either was never set or was set to "".
std::map< std::string, handler > map
unit_creator & allow_rename_side(bool b)
config get_user_choice(const std::string &name, const user_choice &uch, int side=0)
static synced_state get_synced_state()
static void get_global_variable(persist_context &ctx, const vconfig &pcfg)
static DIRECTION parse_direction(const std::string &str)
::tod_manager * tod_manager
int h() const
Effective map height, in hexes.
std::vector< unit_iterator > find_leaders(int side)
static display * get_singleton()
Returns the display object if a display object exists.
Function which doesn't take anything into account.
const unit_type * find(const std::string &key, unit_type::BUILD_STATUS status=unit_type::FULL) const
Finds a unit_type by its id() and makes sure it is built to the specified level.
virtual const std::vector< team > & teams() const override
vconfig child(const std::string &key) const
Returns a child of *this whose key is key.
virtual const unit_map & units() const override
DIRECTION get_relative_dir(const map_location &loc, map_location::RELATIVE_DIR_MODE mode) const
This class represents a single unit of a specific type.
wml_action(const std::string &tag, handler function)
Using this constructor for a static object outside action_wml.cpp will likely lead to a static initia...
void append(const config &cfg)
Append data from another config object to this one.
Various functions implementing vision (through fog of war and shroud).
static manager & get_singleton()
unit_creator & allow_invalidate(bool b)
static void set_global_variable(persist_context &ctx, const vconfig &pcfg)
unit_creator & allow_show(bool b)
bool explicit_index() const
Various functions that implement attacks and attack calculations.
void remove(const std::string &id)
Variant for storing WML attributes.
Add a special kind of assert to validate whether the input from WML doesn't contain any problems that...
internal_ptr get_unit_ptr()
Get a copy of the internal unit pointer.
config & get_variable_cfg(const std::string &varname)
throws invalid_variablename_exception if varname is no valid variable name.
void raise_map_changed()
Notifies all observers of 'ai_map_changed' event.
maybe_const_t< config::attribute_value, V > & as_scalar() const
If instantiated with vi_policy_const, the lifetime of the returned const attribute_value reference mi...
map_location find_vacant_tile(const map_location &loc, VACANT_TILE_TYPE vacancy, const unit *pass_check, const team *shroud_check, const game_board *board)
Function that will find a location on the board that is as near to loc as possible, but which is unoccupied by any units.
REMOVE_EMPTY: remove empty elements.
unit_creator & allow_discover(bool b)
const attribute_value * get(config_key_type key) const
Returns a pointer to the attribute with the given key or nullptr if it does not exist.
virtual const gamemap & map() const override
WML_HANDLER_FUNCTION(clear_global_variable,, pcfg)
Experimental data persistence.
void modify_turns_by_wml(const std::string &mod)
unit_type_data unit_types
Define actions for the game's events mechanism.
config::child_itors insert_array(std::vector< config > children) const
This class encapsulates the recall list of a team.
bool on_board(const map_location &loc) const
Tell if a location is on the map.
static lg::log_domain log_config("config")
void verify_and_set_global_variable(const vconfig &pcfg)
bool matches(const unit &u, const map_location &loc) const
Determine if *this matches filter at a specified location.
Additional functionality for a non-const variable_info.
int to_int(int def=0) const
maybe_const_t< config, V > & as_container() const
If instantiated with vi_policy_const, the lifetime of the returned const attribute_value reference mi...
void write(config &cfg) const
An object to leave the synced context during draw or unsynced wml items when we don’t know whether w...
void remove_attribute(config_key_type key)
unit_creator & allow_add_to_recall(bool b)
std::shared_ptr< unit > unit_ptr
void new_turn()
Update lighting settings.
static unit_ptr create(const config &cfg, bool use_traits=false, const vconfig *vcfg=nullptr)
Initializes a unit from a config.
A single unit type that the player may recruit.
int total_width() const
Real width of the map, including borders.
Object which defines a time of day with associated bonuses, image, sounds etc.
void show() const
Shows the error in a dialog.
This class stores all the data for a single 'side' (in game nomenclature).
std::size_t size(const std::string &str)
Length in characters of a UTF-8 string.
std::vector< map_location > steps
void set_number_of_turns_by_wml(int num)
std::string deprecated_message(const std::string &elem_name, DEP_LEVEL level, const version_info &version, const std::string &detail)
const starting_positions & special_locations() const
Structure which holds a single route between one location and another.
void merge_array(std::vector< config > children) const
const time_of_day & get_time_of_day(int for_turn=0) const
Returns global time of day for the passed turn.
variable_access_create get_variable_access_write(const std::string &varname)
returns a variable_access that can be used to change the game variables
bool blank() const
Tests for an attribute that was never set.
Interface for querying local choices.
iterator begin()
begin iterator
Encapsulates the map of the game.
unit_race::GENDER string_gender(const std::string &str, unit_race::GENDER def)
fake_unit_manager * fake_units
config::child_itors append_array(std::vector< config > children) const
Managing the AIs lifecycle - headers TODO: Refactor history handling and internal commands...
Function which only uses terrain, ignoring shroud, enemies, etc.
void read(const std::string &data, const bool allow_invalid=true)
iterator end()
end iterator
void needs_rebuild(bool b)
Sets whether the screen (map visuals) needs to be rebuilt.
int number_of_turns() const
std::string read_map(const std::string &name)
void set_turn_by_wml(const int num, game_data *vars=nullptr, const bool increase_limit_if_needed=true)
Dynamically change the current turn number.
Encapsulates the map of the game.
Various functions related to moving units.
Helper class, don't construct this directly.
static map registry_
Tracks the known action handlers.
std::shared_ptr< wb::manager > whiteboard
Various functions related to the creation of units (recruits, recalls, and placed units)...
Define conditionals for the game's events mechanism, a.k.a.
unit * get()
Get a raw pointer to the underlying unit.
int w() const
Effective map width, in hexes.
std::stringstream & wml_error()
Use this logger to send errors due to deprecated WML.
unit_creator & allow_get_village(bool b)
Define the game's event mechanism.
config::child_itors replace_array(std::vector< config > children) const
static lg::log_domain log_display("display")
Declarations for File-IO.
std::size_t index(const std::string &str, const std::size_t index)
Codepoint index corresponding to the nth character in a UTF-8 string.
int total_height() const
Real height of the map, including borders.
config & add_child(config_key_type key)
iterator erase(iterator it)
Erase an iterator to this object.
void add_unit(const config &cfg, const vconfig *vcfg=nullptr)
adds a unit on map without firing any events (so, usable during team construction in gamestatus) ...
static void on_replay_error(const std::string &message)
void add(const teleport_group &group)
Information on a WML variable.
static bool run_in_synced_context_if_not_already(const std::string &commandname, const config &data, bool use_undo=true, bool show=true, synced_command::error_handler_function error_handler=default_error_function)
Checks whether we are currently running in a synced context, and if not we enters it...
void reload_map()
Updates internals that cache map size.
std::vector< std::string > split(const config_attribute_value &val)
A variable-expanding proxy for the config class.
const config & get_config() const
Standard logging facilities (interface).
static const map_location & null_location()
static lg::log_domain log_engine("engine")
A RAII object to temporary leave the synced context like in wesnoth.synchronize_choice.
int side() const
The side this unit belongs to.
static void clear_global_variable(persist_context &ctx, const vconfig &pcfg)
maybe_const_t< config::child_itors, V > as_array() const
If instantiated with vi_policy_const, the lifetime of the returned const attribute_value reference mi...
place_recruit_result place_recruit(unit_ptr u, const map_location &recruit_location, const map_location &recruited_from, int cost, bool is_recall, map_location::DIRECTION facing, bool show, bool fire_event, bool full_movement, bool wml_triggered)
Place a unit into the game.
std::vector< vconfig > child_list
static lg::log_domain log_wml("wml")
plain_route a_star_search(const map_location &src, const map_location &dst, double stop_at, const cost_calculator &calc, const std::size_t width, const std::size_t height, const teleport_map *teleports, bool border)
A config object defines a single node in a WML file, with access to child nodes.
This module contains various pathfinding functions and utilities.
static std::string write_direction(DIRECTION dir)
pathfind::manager * tunnels
std::string::const_iterator iterator
Holds a temporary unit that can be drawn on the map without being placed in the unit_map.
Display units performing various actions: moving, attacking, and dying.
void move_unit(const std::vector< map_location > &path, unit_ptr u, bool animate, map_location::DIRECTION dir, bool force_scroll)
Display a unit moving along a given path.
std::string debug() const
void verify_and_clear_global_variable(const vconfig &pcfg)
static game_display * get_singleton()
variable_access_const get_variable_access_read(const std::string &varname) const
returns a variable_access that cannot be used to change the game variables