52 #define DBG_NG LOG_STREAM(debug, log_engine)
53 #define LOG_NG LOG_STREAM(info, log_engine)
54 #define WRN_NG LOG_STREAM(warn, log_engine)
55 #define ERR_NG LOG_STREAM(err, log_engine)
58 #define DBG_DP LOG_STREAM(debug, log_display)
59 #define LOG_DP LOG_STREAM(info, log_display)
62 #define LOG_WML LOG_STREAM(info, log_wml)
63 #define WRN_WML LOG_STREAM(warn, log_wml)
64 #define ERR_WML LOG_STREAM(err, log_wml)
67 #define ERR_CF LOG_STREAM(err, log_config)
92 std::string
type = cfg[
"type"];
93 std::string variation = cfg[
"variation"];
94 std::string img_mods = cfg[
"image_mods"];
96 std::size_t side_num = cfg[
"side"].to_int(1);
106 if(!variation.empty()) {
109 effect[
"apply_to"] =
"variation";
110 effect[
"name"] = variation;
111 fake->add_modification(
"variation",mod);
114 if(!img_mods.empty()) {
117 effect[
"apply_to"] =
"image_mod";
118 effect[
"add"] = img_mods;
119 fake->add_modification(
"image_mod",mod);
125 std::vector<map_location> fake_unit_path(
const unit& fake_unit,
const std::vector<std::string>& xvals,
const std::vector<std::string>& yvals)
128 std::vector<map_location>
path;
131 for(std::size_t
i = 0;
i != std::min(xvals.size(),yvals.size()); ++
i) {
136 }
catch(std::invalid_argument&) {
137 ERR_CF <<
"Invalid move_unit_fake source: " << xvals[
i] <<
", " << yvals[
i];
141 ERR_CF <<
"Invalid move_unit_fake source: " <<
src;
155 }
catch(std::invalid_argument&) {
156 ERR_CF <<
"Invalid move_unit_fake destination: " << xvals[
i] <<
", " << yvals[
i];
159 ERR_CF <<
"Invalid move_unit_fake destination: " <<
dst;
164 game_map->
w(), game_map->
h());
166 if (route.
steps.empty()) {
167 WRN_NG <<
"Could not find move_unit_fake route from " <<
src <<
" to " <<
dst <<
": ignoring complexities";
171 game_map->
w(), game_map->
h());
172 if(route.
steps.empty()) {
176 WRN_NG <<
"Could not find move_unit_fake route from " <<
src <<
" to " <<
dst <<
": ignoring terrain";
179 assert(!route.
steps.empty());
234 #define WML_HANDLER_FUNCTION(pname, pei, pcfg) \
235 static void wml_func_##pname(const queued_event& pei, const vconfig& pcfg); \
236 static wml_action wml_action_##pname(#pname, &wml_func_##pname); \
237 static void wml_func_##pname(const queued_event& pei, const vconfig& pcfg)
260 ERR_NG <<
"[do_command] called while whiteboard is applied, ignoring";
264 static const std::set<std::string> allowed_tags {
"attack",
"move",
"recruit",
"recall",
"disband",
"fire_event",
"custom_command"};
271 ERR_NG <<
"[do_command] called too early, only allowed at START or later";
274 if(is_unsynced && !is_during_turn)
276 ERR_NG <<
"[do_command] can only be used during a turn when a user woudl also be able to invoke commands";
281 ERR_NG <<
"[do_command] cannot invoke synced commands while commands are blocked";
286 ERR_NG <<
"[do_command] can only be used from clients that control the currently playing side";
289 for(
const auto& [key, child] : cfg.all_ordered())
291 if(allowed_tags.find(key) == allowed_tags.end()) {
292 ERR_NG <<
"unsupported tag [" << key <<
"] in [do_command]";
294 std::copy(allowed_tags.begin(), allowed_tags.end(), std::ostream_iterator<std::string>(o,
" "));
295 ERR_NG <<
"allowed tags: " << o.str();
304 ERR_NG <<
"Error via [do_command]:";
309 child.get_parsed_config(),
328 std::string add = cfg[
"add"];
333 }
else if(!value.
empty()) {
337 if(!current.empty()) {
338 const unsigned int current_turn_number = tod_man.
turn();
339 int new_turn_number = current.to_int(current_turn_number);
340 const unsigned int new_turn_number_u =
static_cast<unsigned int>(new_turn_number);
342 ERR_NG <<
"attempted to change current turn number to one out of range (" << new_turn_number <<
")";
343 }
else if(new_turn_number_u != current_turn_number) {
359 if(!dummy_unit.
get())
362 const bool force_scroll = cfg[
"force_scroll"].to_bool(
true);
364 const std::string x = cfg[
"x"];
365 const std::string y = cfg[
"y"];
370 const std::vector<map_location>&
path = fake_unit_path(*dummy_unit, xvals, yvals);
381 LOG_NG <<
"Processing [move_units_fake]";
383 const bool force_scroll = cfg[
"force_scroll"].to_bool();
385 std::size_t num_units = unit_cfgs.size();
386 std::vector<fake_unit_ptr > units;
387 units.reserve(num_units);
388 std::vector<std::vector<map_location>> paths;
389 paths.reserve(num_units);
391 LOG_NG <<
"Moving " << num_units <<
" units";
393 std::size_t longest_path = 0;
398 int skip_steps =
config[
"skip_steps"].to_int();
401 paths.push_back(fake_unit_path(*u, xvals, yvals));
403 paths.back().insert(paths.back().begin(), skip_steps, paths.back().front());
404 longest_path = std::max(longest_path, paths.back().size());
405 DBG_NG <<
"Path " << paths.size() - 1 <<
" has length " << paths.back().size();
407 u->set_location(paths.back().front());
411 LOG_NG <<
"Units placed, longest path is " << longest_path <<
" long";
413 std::vector<map_location> path_step(2);
415 for(std::size_t step = 1; step < longest_path; ++step) {
416 DBG_NG <<
"Doing step " << step <<
"...";
417 for(std::size_t un = 0; un < num_units; ++un) {
418 if(step >= paths[un].
size() || paths[un][step - 1] == paths[un][step])
420 DBG_NG <<
"Moving unit " << un <<
", doing step " << step;
421 path_step[0] = paths[un][step - 1];
422 path_step[1] = paths[un][step];
424 units[un]->set_location(path_step[1]);
425 units[un]->anim_comp().set_standing(
false);
440 LOG_NG <<
"recalling unit...";
441 config temp_config(cfg.get_config());
449 temp_config[
"x"] =
"recall";
450 temp_config[
"y"] =
"recall";
452 vconfig unit_filter_cfg(temp_config);
453 const vconfig & leader_filter = cfg.
child(
"secondary_unit");
456 LOG_NG <<
"for side " <<
t.side() <<
"...";
457 const std::string player_id =
t.save_id_or_number();
459 if(
t.recall_list().size() < 1) {
460 DBG_NG <<
"recall list is empty when trying to recall!";
461 DBG_NG <<
"player_id: " << player_id <<
" side: " <<
t.side();
471 DBG_NG <<
"checking unit against filter...";
474 DBG_NG << (*u)->id() <<
" matched the filter...";
476 const unit* pass_check = to_recruit.get();
477 if(!cfg[
"check_passability"].to_bool(
true)) pass_check =
nullptr;
479 if(cfg.has_attribute(
"location_id")) {
481 const auto& iter = special_locs.find(cfg[
"location_id"]);
482 if(iter != special_locs.end()) {
483 cfg_loc = iter->second;
488 DBG_NG <<
"...considering " + leader->id() +
" as the recalling leader...";
490 if ( lfilt(*leader) &&
492 DBG_NG <<
"...matched the leader filter and is able to recall the unit.";
494 loc = leader->get_location();
498 DBG_NG <<
"...valid location for the recall found. Recalling.";
502 cfg[
"show"].to_bool(
true), cfg[
"fire_event"].to_bool(
false),
514 DBG_NG <<
"No usable leader found, but found usable location. Recalling.";
519 cfg[
"show"].to_bool(
true), cfg[
"fire_event"].to_bool(
false),
527 LOG_WML <<
"A [recall] tag with the following content failed:\n" << cfg.get_config().debug();
535 virtual config query_user(
int )
const override
538 return config {
"map_data", res};
540 virtual config random_choice(
int )
const override
544 virtual std::string description()
const override
548 virtual bool is_visible()
const override
576 if(!cfg[
"map_file"].empty()) {
578 map.
read(file_cfg[
"map_data"].str(),
false);
579 }
else if(!cfg[
"map_data"].empty()) {
580 map.
read(cfg[
"map_data"],
false);
583 map.
read(cfg[
"map"],
false);
586 const std::string log_map_name = cfg[
"map"].empty() ? cfg[
"map_file"] : std::string(
"from inline data");
587 lg::log_to_chat() <<
"replace_map: Unable to load map " << log_map_name <<
'\n';
588 ERR_WML <<
"replace_map: Unable to load map " << log_map_name;
597 if (!cfg[
"expand"].to_bool()) {
598 lg::log_to_chat() <<
"replace_map: Map dimension(s) increase but expand is not set\n";
599 ERR_WML <<
"replace_map: Map dimension(s) increase but expand is not set";
606 if (!cfg[
"shrink"].to_bool()) {
607 lg::log_to_chat() <<
"replace_map: Map dimension(s) decrease but shrink is not set\n";
608 ERR_WML <<
"replace_map: Map dimension(s) decrease but shrink is not set";
637 const std::string name = cfg[
"name"];
640 ERR_NG <<
"trying to set a variable with an empty name:\n" << cfg.get_config().debug();
644 std::vector<config>
data;
645 if(cfg.has_attribute(
"to_variable"))
657 ERR_NG <<
"Cannot do [set_variables] with invalid to_variable variable: " << cfg[
"to_variable"] <<
" with " << cfg.get_config().debug();
660 typedef std::pair<std::string, vconfig> vchild;
661 for (
const vchild&
p : cfg.all_ordered()) {
662 if(
p.first ==
"value") {
663 data.push_back(
p.second.get_parsed_config());
664 }
else if(
p.first ==
"literal") {
665 data.push_back(
p.second.get_config());
666 }
else if(
p.first ==
"split") {
667 const vconfig & split_element =
p.second;
669 std::string split_string=split_element[
"list"];
670 std::string separator_string=split_element[
"separator"];
671 std::string key_name=split_element[
"key"];
677 bool remove_empty = split_element[
"remove_empty"].to_bool();
679 char* separator = separator_string.
empty() ? nullptr : &separator_string[0];
680 if(separator_string.size() > 1){
681 ERR_NG <<
"[set_variables] [split] separator only supports 1 character, multiple passed: " << split_element[
"separator"] <<
" with " << cfg.
get_config().
debug();
684 std::vector<std::string> split_vector;
687 if(separator ==
nullptr)
691 split_vector.push_back(std::string(1, *
i));
700 data.emplace_back(key_name, *
i);
707 const std::string& mode = cfg[
"mode"];
715 merged_children.
append(ch);
717 data = {merged_children};
721 else if(mode ==
"insert")
725 else if(mode ==
"append")
736 ERR_NG <<
"Cannot do [set_variables] with invalid destination variable: " << name <<
" with " << cfg.get_config().debug();
747 if (!cfg.child(
"source")) {
748 WRN_NG <<
"No source in [store_relative_direction]";
751 if (!cfg.child(
"destination")) {
752 WRN_NG <<
"No destination in [store_relative_direction]";
755 if (!cfg.has_attribute(
"variable")) {
756 WRN_NG <<
"No variable in [store_relative_direction]";
763 std::string variable = cfg[
"variable"];
773 ERR_NG <<
"Cannot do [store_relative_direction] with invalid destination variable: " << variable <<
" with " << cfg.get_config().debug();
785 if (!cfg.child(
"source")) {
786 WRN_NG <<
"No source in [store_rotate_map_location]";
789 if (!cfg.child(
"destination")) {
790 WRN_NG <<
"No destination in [store_rotate_map_location]";
793 if (!cfg.has_attribute(
"variable")) {
794 WRN_NG <<
"No variable in [store_rotate_map_location]";
801 std::string variable = cfg[
"variable"];
802 int angle = cfg[
"angle"].to_int(1);
812 ERR_NG <<
"Cannot do [store_rotate_map_location] with invalid destination variable: " << variable <<
" with " << cfg.get_config().debug();
818 const bool remove = cfg[
"remove"].to_bool(
false);
819 const bool delay = cfg[
"delayed_variable_substitution"].to_bool(
true);
821 const std::vector<std::string> ids =
utils::split(cfg[
"id"]);
822 for (
const std::string &
id : ids) {
825 }
else if (cfg.get_children(
"source").empty() ||
826 cfg.get_children(
"target").empty() ||
827 cfg.get_children(
"filter").empty()) {
828 ERR_WML <<
"[tunnel] is missing a mandatory tag:\n"
829 << cfg.get_config().debug();
830 }
else if (cfg.get_children(
"source").size() > 1 ||
831 cfg.get_children(
"target").size() > 1 ||
832 cfg.get_children(
"filter").size() > 1) {
833 ERR_WML <<
"[tunnel] should have exactly one of each mandatory tag:\n"
834 << cfg.get_config().debug();
839 if(cfg[
"bidirectional"].to_bool(
true)) {
850 config parsed_cfg = cfg.get_parsed_config();
853 if (!to_variable.
blank())
861 new_unit->write(var);
867 ERR_NG <<
"Cannot do [unit] with invalid to_variable: " << to_variable <<
" with " << cfg.get_config().debug();
873 int side = parsed_cfg[
"side"].to_int(1);
899 ERR_WML <<
"Error occured inside [unit]: " <<
e.what();
static lg::log_domain log_engine("engine")
static lg::log_domain log_display("display")
static lg::log_domain log_wml("wml")
static lg::log_domain log_config("config")
Define actions for the game's events mechanism.
Managing the AIs lifecycle - headers TODO: Refactor history handling and internal commands.
static manager & get_singleton()
Variant for storing WML attributes.
int to_int(int def=0) const
bool blank() const
Tests for an attribute that was never set.
bool empty() const
Tests for an attribute that either was never set or was set to "".
A config object defines a single node in a WML file, with access to child nodes.
void append(const config &cfg)
Append data from another config object to this one.
void remove_attribute(config_key_type key)
std::string debug() const
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.
config & add_child(config_key_type key)
void reload_map()
Updates internals that cache map size.
static display * get_singleton()
Returns the display object if a display object exists.
Holds a temporary unit that can be drawn on the map without being placed in the unit_map.
internal_ptr get_unit_ptr()
Get a copy of the internal unit pointer.
unit * get()
Get a raw pointer to the underlying unit.
void place_on_fake_unit_manager(fake_unit_manager *d)
Place this on manager's fake_units_ dequeue.
virtual const std::vector< team > & teams() const override
utils::optional< std::string > replace_map(const gamemap &r)
virtual const unit_map & units() const override
virtual const gamemap & map() const override
@ 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.
@ TURN_PLAYING
The User is controlling the game and invoking actions The game can be saved here.
variable_access_create get_variable_access_write(const std::string &varname)
returns a variable_access that can be used to change the game variables
config & get_variable_cfg(const std::string &varname)
throws invalid_variablename_exception if varname is no valid variable name.
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
static game_display * get_singleton()
void new_turn()
Update lighting settings.
void needs_rebuild(bool b)
Sets whether the screen (map visuals) needs to be rebuilt.
static map registry_
Tracks the known action handlers.
std::map< std::string, handler > map
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...
int w() const
Effective map width.
int h() const
Effective map height.
int total_width() const
Real width of the map, including borders.
int total_height() const
Real height of the map, including borders.
bool on_board(const map_location &loc) const
Tell if a location is on the map.
location_map & special_locations()
Encapsulates the map of the game.
void read(const std::string &data, const bool allow_invalid=true)
A RAII object to temporary leave the synced context like in wesnoth.synchronize_choice.
void add(const teleport_group &group)
void remove(const std::string &id)
This class encapsulates the recall list of a team.
iterator end()
end iterator
iterator erase(const iterator &it)
Erase an iterator to this object.
iterator begin()
begin iterator
An object to leave the synced context during draw or unsynced wml items when we don’t know whether we...
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()
This class stores all the data for a single 'side' (in game nomenclature).
int number_of_turns() const
void modify_turns_by_wml(const std::string &mod)
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.
void set_number_of_turns_by_wml(int num)
unit_creator & allow_invalidate(bool b)
unit_creator & allow_get_village(bool b)
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)
unit_creator & allow_discover(bool b)
unit_creator & allow_show(bool b)
unit_creator & allow_rename_side(bool b)
unit_creator & allow_add_to_recall(bool b)
bool matches(const unit &u, const map_location &loc) const
Determine if *this matches filter at a specified location.
std::vector< unit_iterator > find_leaders(int side)
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.
A single unit type that the player may recruit.
This class represents a single unit of a specific type.
static unit_ptr create(const config &cfg, bool use_traits=false, const vconfig *vcfg=nullptr)
Initializes a unit from a config.
Additional functionality for a non-const variable_info.
config::child_itors insert_array(std::vector< config > children) const
void merge_array(std::vector< config > children) const
config::child_itors replace_array(std::vector< config > children) const
config::child_itors append_array(std::vector< config > children) const
Information on a WML variable.
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...
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...
maybe_const_t< config, V > & as_container() const
If instantiated with vi_policy_const, the lifetime of the returned const attribute_value reference mi...
bool explicit_index() const
A variable-expanding proxy for the config class.
std::vector< vconfig > child_list
vconfig child(const std::string &key) const
Returns a child of *this whose key is key.
const config & get_config() const
Various functions related to the creation of units (recruits, recalls, and placed units).
std::string deprecated_message(const std::string &elem_name, DEP_LEVEL level, const version_info &version, const std::string &detail)
Declarations for File-IO.
int side() const
The side this unit belongs to.
Standard logging facilities (interface).
place_recruit_result place_recruit(const 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::string read_map(const std::string &name)
WML_HANDLER_FUNCTION(clear_global_variable,, pcfg)
Experimental data persistence.
void remove()
Removes a tip.
std::stringstream & log_to_chat()
Use this to show WML errors in the ingame chat.
std::string tag(const std::string &tag_name, Args &&... contents)
config get_user_choice(const std::string &name, const user_choice &uch, int side=0)
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)
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,...
::tod_manager * tod_manager
fake_unit_manager * fake_units
pathfind::manager * tunnels
play_controller * controller
std::shared_ptr< wb::manager > whiteboard
void move_unit(const std::vector< map_location > &path, const unit_ptr &u, bool animate, map_location::direction dir, bool force_scroll)
Display a unit moving along a given path.
std::size_t size(std::string_view str)
Length in characters of a UTF-8 string.
@ STRIP_SPACES
REMOVE_EMPTY: remove empty elements.
int stoi(std::string_view str)
Same interface as std::stoi and meant as a drop in replacement, except:
std::vector< std::string > split(const config_attribute_value &val)
fake
For describing the type of faked display, if any.
std::string::const_iterator iterator
This module contains various pathfinding functions and utilities.
static void clear_global_variable(persist_context &ctx, const vconfig &pcfg)
static void set_global_variable(persist_context &ctx, const vconfig &pcfg)
void verify_and_set_global_variable(const vconfig &pcfg)
void verify_and_clear_global_variable(const vconfig &pcfg)
static void get_global_variable(persist_context &ctx, const vconfig &pcfg)
void verify_and_get_global_variable(const vconfig &pcfg)
std::shared_ptr< unit > unit_ptr
unit_race::GENDER string_gender(const std::string &str, unit_race::GENDER def)
rect dst
Location on the final composed sheet.
rect src
Non-transparent portion of the surface to compose.
std::string filename
Filename.
Encapsulates the map of the game.
static std::string write_direction(direction dir)
static const map_location & null_location()
static direction parse_direction(const std::string &str)
Interface for querying local choices.
Function which doesn't take anything into account.
Function which only uses terrain, ignoring shroud, enemies, etc.
Structure which holds a single route between one location and another.
std::vector< map_location > steps
Helper class, don't construct this directly.
unit_type_data unit_types
Display units performing various actions: moving, attacking, and dying.
Add a special kind of assert to validate whether the input from WML doesn't contain any problems that...