68 #define DBG_NG LOG_STREAM(debug, log_engine) 69 #define LOG_NG LOG_STREAM(info, log_engine) 70 #define WRN_NG LOG_STREAM(warn, log_engine) 71 #define ERR_NG LOG_STREAM(err, log_engine) 74 #define DBG_DP LOG_STREAM(debug, log_display) 75 #define LOG_DP LOG_STREAM(info, log_display) 78 #define LOG_WML LOG_STREAM(info, log_wml) 79 #define WRN_WML LOG_STREAM(warn, log_wml) 80 #define ERR_WML LOG_STREAM(err, log_wml) 83 #define ERR_CF LOG_STREAM(err, log_config) 108 std::string
type = cfg[
"type"];
109 std::string variation = cfg[
"variation"];
110 std::string img_mods = cfg[
"image_mods"];
112 std::size_t side_num = cfg[
"side"].to_int(1);
122 if(!variation.empty()) {
125 effect[
"apply_to"] =
"variation";
126 effect[
"name"] = variation;
127 fake->add_modification(
"variation",mod);
130 if(!img_mods.empty()) {
133 effect[
"apply_to"] =
"image_mod";
134 effect[
"add"] = img_mods;
135 fake->add_modification(
"image_mod",mod);
141 std::vector<map_location> fake_unit_path(
const unit& fake_unit,
const std::vector<std::string>& xvals,
const std::vector<std::string>& yvals)
144 std::vector<map_location>
path;
147 for(std::size_t
i = 0;
i != std::min(xvals.size(),yvals.size()); ++
i) {
152 }
catch(std::invalid_argument&) {
153 ERR_CF <<
"Invalid move_unit_fake source: " << xvals[
i] <<
", " << yvals[
i] <<
'\n';
157 ERR_CF <<
"Invalid move_unit_fake source: " << src <<
'\n';
171 }
catch(std::invalid_argument&) {
172 ERR_CF <<
"Invalid move_unit_fake destination: " << xvals[
i] <<
", " << yvals[
i] <<
'\n';
175 ERR_CF <<
"Invalid move_unit_fake destination: " << dst <<
'\n';
180 game_map->
w(), game_map->
h());
182 if (route.
steps.empty()) {
183 WRN_NG <<
"Could not find move_unit_fake route from " << src <<
" to " << dst <<
": ignoring complexities" << std::endl;
187 game_map->
w(), game_map->
h());
188 if(route.
steps.empty()) {
192 WRN_NG <<
"Could not find move_unit_fake route from " << src <<
" to " << dst <<
": ignoring terrain" << std::endl;
194 route =
a_star_search(src, dst, 10000, dummy_calc, game_map->
w(), game_map->
h());
195 assert(!route.
steps.empty());
201 path.insert(path.end(),
250 #define WML_HANDLER_FUNCTION(pname, pei, pcfg) \ 251 static void wml_func_##pname(const queued_event &pei, const vconfig &pcfg); \ 252 static wml_action wml_action_##pname(#pname, &wml_func_##pname); \ 253 static void wml_func_##pname(const queued_event& pei, const vconfig& pcfg) 268 ERR_NG <<
"Error via [do_command]:" << std::endl;
269 ERR_NG << message << std::endl;
282 ERR_NG <<
"[do_command] called while whiteboard is applied, ignoring" << std::endl;
286 static const std::set<std::string> allowed_tags {
"attack",
"move",
"recruit",
"recall",
"disband",
"fire_event",
"custom_command"};
293 ERR_NG <<
"[do_command] called too early, only allowed at START or later" << std::endl;
298 ERR_NG <<
"[do_command] cannot be used in linger mode" << std::endl;
303 ERR_NG <<
"[do_command] cannot be used before the turn has started" << std::endl;
306 if(is_unsynced && is_unsynced_too_early)
308 ERR_NG <<
"[do_command] called too early" << std::endl;
313 ERR_NG <<
"[do_command] cannot invoke synced commands while commands are blocked" << std::endl;
318 ERR_NG <<
"[do_command] can only be used from clients that control the currently playing side" << std::endl;
321 for(
const auto& [key, child] : cfg.all_ordered())
323 if(allowed_tags.find(key) == allowed_tags.end()) {
324 ERR_NG <<
"unsupported tag [" << key <<
"] in [do_command]" << std::endl;
326 std::copy(allowed_tags.begin(), allowed_tags.end(), std::ostream_iterator<std::string>(o,
" "));
327 ERR_NG <<
"allowed tags: " << o.str() << std::endl;
337 child.get_parsed_config(),
358 std::string add = cfg[
"add"];
363 }
else if(!value.
empty()) {
367 if(!current.
empty()) {
368 const unsigned int current_turn_number = tod_man.
turn();
369 int new_turn_number = current.
to_int(current_turn_number);
370 const unsigned int new_turn_number_u =
static_cast<unsigned int>(new_turn_number);
372 ERR_NG <<
"attempted to change current turn number to one out of range (" << new_turn_number <<
")" << std::endl;
373 }
else if(new_turn_number_u != current_turn_number) {
389 if(!dummy_unit.
get())
392 const bool force_scroll = cfg[
"force_scroll"].to_bool(
true);
394 const std::string x = cfg[
"x"];
395 const std::string y = cfg[
"y"];
400 const std::vector<map_location>&
path = fake_unit_path(*dummy_unit, xvals, yvals);
411 LOG_NG <<
"Processing [move_units_fake]\n";
413 const bool force_scroll = cfg[
"force_scroll"].to_bool();
415 std::size_t num_units = unit_cfgs.size();
416 std::vector<fake_unit_ptr > units;
417 units.reserve(num_units);
418 std::vector<std::vector<map_location>> paths;
419 paths.reserve(num_units);
421 LOG_NG <<
"Moving " << num_units <<
" units\n";
423 std::size_t longest_path = 0;
428 int skip_steps =
config[
"skip_steps"];
431 paths.push_back(fake_unit_path(*u, xvals, yvals));
433 paths.back().insert(paths.back().begin(), skip_steps, paths.back().front());
434 longest_path = std::max(longest_path, paths.back().size());
435 DBG_NG <<
"Path " << paths.size() - 1 <<
" has length " << paths.back().size() <<
'\n';
437 u->set_location(paths.back().front());
441 LOG_NG <<
"Units placed, longest path is " << longest_path <<
" long\n";
443 std::vector<map_location> path_step(2);
445 for(std::size_t step = 1; step < longest_path; ++step) {
446 DBG_NG <<
"Doing step " << step <<
"...\n";
447 for(std::size_t un = 0; un < num_units; ++un) {
448 if(step >= paths[un].
size() || paths[un][step - 1] == paths[un][step])
450 DBG_NG <<
"Moving unit " << un <<
", doing step " << step <<
'\n';
451 path_step[0] = paths[un][step - 1];
452 path_step[1] = paths[un][step];
454 units[un]->set_location(path_step[1]);
455 units[un]->anim_comp().set_standing(
false);
459 LOG_NG <<
"Units moved\n";
470 LOG_NG <<
"recalling unit...\n";
471 config temp_config(cfg.get_config());
479 temp_config[
"x"] =
"recall";
480 temp_config[
"y"] =
"recall";
482 vconfig unit_filter_cfg(temp_config);
483 const vconfig & leader_filter = cfg.
child(
"secondary_unit");
490 DBG_NG <<
"recall list is empty when trying to recall!\n" 491 <<
"player_id: " << player_id <<
" side: " << index+1 <<
"\n";
501 DBG_NG <<
"checking unit against filter...\n";
504 DBG_NG << (*u)->id() <<
" matched the filter...\n";
506 const unit* pass_check = to_recruit.get();
507 if(!cfg[
"check_passability"].to_bool(
true)) pass_check =
nullptr;
509 if(cfg.has_attribute(
"location_id")) {
511 const auto& iter = special_locs.find(cfg[
"location_id"]);
512 if(iter != special_locs.end()) {
513 cfg_loc = iter->second;
518 DBG_NG <<
"...considering " + leader->id() +
" as the recalling leader...\n";
520 if ( lfilt(*leader) &&
522 DBG_NG <<
"...matched the leader filter and is able to recall the unit.\n";
524 loc = leader->get_location();
528 DBG_NG <<
"...valid location for the recall found. Recalling.\n";
532 cfg[
"show"].to_bool(
true), cfg[
"fire_event"].to_bool(
false),
544 DBG_NG <<
"No usable leader found, but found usable location. Recalling.\n";
549 cfg[
"show"].to_bool(
true), cfg[
"fire_event"].to_bool(
false),
557 LOG_WML <<
"A [recall] tag with the following content failed:\n" << cfg.get_config().debug();
563 map_choice(
const std::string& filename) :
filename_(filename) {}
565 virtual config query_user(
int )
const override 568 return config {
"map_data", res};
570 virtual config random_choice(
int )
const override 574 virtual std::string description()
const override 578 virtual bool is_visible()
const override 606 if(!cfg[
"map_file"].empty()) {
608 map.
read(file_cfg[
"map_data"].str(),
false);
609 }
else if(!cfg[
"map_data"].empty()) {
610 map.
read(cfg[
"map_data"],
false);
613 map.
read(cfg[
"map"],
false);
616 const std::string log_map_name = cfg[
"map"].empty() ? cfg[
"map_file"] : std::string(
"from inline data");
617 lg::log_to_chat() <<
"replace_map: Unable to load map " << log_map_name <<
'\n';
618 ERR_WML <<
"replace_map: Unable to load map " << log_map_name;
627 if (!cfg[
"expand"].to_bool()) {
628 lg::log_to_chat() <<
"replace_map: Map dimension(s) increase but expand is not set\n";
629 ERR_WML <<
"replace_map: Map dimension(s) increase but expand is not set";
636 if (!cfg[
"shrink"].to_bool()) {
637 lg::log_to_chat() <<
"replace_map: Map dimension(s) decrease but shrink is not set\n";
638 ERR_WML <<
"replace_map: Map dimension(s) decrease but shrink is not set";
670 ERR_NG <<
"trying to set a variable with an empty name:\n" << cfg.get_config().debug();
674 std::vector<config> data;
675 if(cfg.has_attribute(
"to_variable"))
687 ERR_NG <<
"Cannot do [set_variables] with invalid to_variable variable: " << cfg[
"to_variable"] <<
" with " << cfg.get_config().debug() << std::endl;
690 typedef std::pair<std::string, vconfig> vchild;
691 for (
const vchild&
p : cfg.all_ordered()) {
692 if(
p.first ==
"value") {
693 data.push_back(
p.second.get_parsed_config());
694 }
else if(
p.first ==
"literal") {
695 data.push_back(
p.second.get_config());
696 }
else if(
p.first ==
"split") {
697 const vconfig & split_element =
p.second;
699 std::string split_string=split_element[
"list"];
700 std::string separator_string=split_element[
"separator"];
701 std::string key_name=split_element[
"key"];
707 bool remove_empty = split_element[
"remove_empty"].to_bool();
709 char* separator = separator_string.
empty() ? nullptr : &separator_string[0];
710 if(separator_string.size() > 1){
711 ERR_NG <<
"[set_variables] [split] separator only supports 1 character, multiple passed: " << split_element[
"separator"] <<
" with " << cfg.
get_config().
debug() << std::endl;
714 std::vector<std::string> split_vector;
717 if(separator ==
nullptr)
721 split_vector.push_back(std::string(1, *
i));
730 data.emplace_back(key_name, *
i);
737 const std::string& mode = cfg[
"mode"];
744 for (
const config &ch : data) {
745 merged_children.
append(ch);
747 data = {merged_children};
751 else if(mode ==
"insert")
755 else if(mode ==
"append")
766 ERR_NG <<
"Cannot do [set_variables] with invalid destination variable: " << name <<
" with " << cfg.get_config().debug() << std::endl;
777 if (!cfg.child(
"source")) {
778 WRN_NG <<
"No source in [store_relative_direction]" << std::endl;
781 if (!cfg.child(
"destination")) {
782 WRN_NG <<
"No destination in [store_relative_direction]" << std::endl;
785 if (!cfg.has_attribute(
"variable")) {
786 WRN_NG <<
"No variable in [store_relative_direction]" << std::endl;
793 std::string variable = cfg[
"variable"];
803 ERR_NG <<
"Cannot do [store_relative_direction] with invalid destination variable: " << variable <<
" with " << cfg.get_config().debug() << std::endl;
815 if (!cfg.child(
"source")) {
816 WRN_NG <<
"No source in [store_rotate_map_location]" << std::endl;
819 if (!cfg.child(
"destination")) {
820 WRN_NG <<
"No destination in [store_rotate_map_location]" << std::endl;
823 if (!cfg.has_attribute(
"variable")) {
824 WRN_NG <<
"No variable in [store_rotate_map_location]" << std::endl;
831 std::string variable = cfg[
"variable"];
832 int angle = cfg[
"angle"].to_int(1);
838 dst.rotate_right_around_center(src,angle).write(store.
as_container());
842 ERR_NG <<
"Cannot do [store_rotate_map_location] with invalid destination variable: " << variable <<
" with " << cfg.get_config().debug() << std::endl;
848 const bool remove = cfg[
"remove"].to_bool(
false);
849 const bool delay = cfg[
"delayed_variable_substitution"].to_bool(
true);
851 const std::vector<std::string> ids =
utils::split(cfg[
"id"]);
852 for (
const std::string &
id : ids) {
855 }
else if (cfg.get_children(
"source").empty() ||
856 cfg.get_children(
"target").empty() ||
857 cfg.get_children(
"filter").empty()) {
858 ERR_WML <<
"[tunnel] is missing a mandatory tag:\n" 859 << cfg.get_config().debug();
864 if(cfg[
"bidirectional"].to_bool(
true)) {
875 config parsed_cfg = cfg.get_parsed_config();
878 if (!to_variable.
blank())
886 new_unit->write(var);
892 ERR_NG <<
"Cannot do [unit] with invalid to_variable: " << to_variable <<
" with " << cfg.get_config().debug() << std::endl;
898 int side = parsed_cfg[
"side"].to_int(1);
924 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
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
location_map & special_locations()
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()
void raise_gamestate_changed()
Notifies all observers of 'ai_gamestate_changed' event.
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.
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.
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...
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.
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)
int w() const
Effective map width.
Structure which holds a single route between one location and another.
void merge_array(std::vector< config > children) const
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)
REMOVE_EMPTY: remove empty elements.
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.
int total_width() const
Real width of the map, including borders.
unit * get()
Get a raw pointer to the underlying unit.
unit_creator & allow_get_village(bool b)
Define the game's event mechanism.
config::child_itors replace_array(std::vector< config > children) const
bool on_board(const map_location &loc) const
Tell if a location is on the map.
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.
int h() const
Effective map height.
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)
std::stringstream & log_to_chat()
Use this to show WML errors in the ingame chat.
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