16#define GETTEXT_DOMAIN "wesnoth-editor"
35#include <boost/algorithm/string/predicate.hpp>
36#include <boost/algorithm/string/trim.hpp>
37#include <boost/regex.hpp>
44 , name(
t.user_team_name())
45 , recruit_list(
utils::join(
t.recruits(),
","))
47 , income(
t.base_income())
48 , village_income(
t.village_gold())
49 , village_support(
t.village_support())
51 , shroud(
t.uses_shroud())
52 , share_vision(
t.share_vision())
53 , controller(
t.controller())
54 , no_leader(
t.no_leader())
62 static const int editor_team_default_gold = 100;
73 , actions_since_save_(0)
74 , needs_reload_(false)
75 , needs_terrain_rebuild_(false)
76 , needs_labels_reset_(false)
77 , everything_changed_(false)
78 , changed_locations_()
79 , starting_position_label_locs_()
84 , scenario_description_()
86 , victory_defeated_(true)
94 , game_classification_()
96 , last_map_generator_(nullptr)
101static std::string
get_map_location(
const std::string& file_contents,
const std::string& attr)
103 std::size_t attr_name_start = file_contents.find(attr);
104 if(attr_name_start == std::string::npos)
return "";
106 std::size_t attr_value_start = file_contents.find(
"=", attr_name_start);
107 std::size_t line_end = file_contents.find(
"\n", attr_name_start);
108 if(line_end < attr_value_start)
return "";
111 std::string attr_value = file_contents.substr(attr_value_start, line_end - attr_value_start);
113 return boost::trim_copy(attr_value);
124 , actions_since_save_(0)
125 , needs_reload_(false)
126 , needs_terrain_rebuild_(false)
127 , needs_labels_reset_(false)
128 , everything_changed_(false)
129 , changed_locations_()
130 , starting_position_label_locs_()
131 , addon_id_(addon_id)
135 , scenario_description_()
137 , victory_defeated_(true)
138 , random_time_(false)
145 , game_classification_()
147 , last_map_generator_(nullptr)
195 std::string message =
_(
"Empty file");
204 std::string message =
_(
"File does not have .map, .cfg, or .mask extension");
211 LOG_ED <<
"Loading map or mask file";
220 LOG_ED <<
"Try loading scenario file";
224 }
catch(
const std::exception&
e) {
227 const std::string msg =
VGETTEXT(
"Failed to load the scenario: $error\n\nAttempting to load only the map.",
symbols);
236 LOG_ED <<
"Loading embedded map_data";
253 std::string message =
_(
"The file looks like a scenario, but the map_data attribute does not point to an existing file") + std::string(
"\n") +
macro_argument;
268 std::string message =
_(
"The file looks like a scenario, but the map_file attribute does not point to an existing file") + std::string(
"\n") +
map_file_loc;
300 cfg[
"hidden"] =
false;
310 assert(
teams_.size() >=
static_cast<unsigned int>(info.side));
315 t.have_leader(!info.no_leader);
316 t.change_controller(info.controller);
317 t.set_gold(info.gold);
318 t.set_base_income(info.income);
319 t.set_hidden(info.hidden);
321 t.set_shroud(info.shroud);
322 t.set_share_vision(info.share_vision);
323 t.set_village_gold(info.village_income);
324 t.set_village_support(info.village_support);
330 const std::string& name,
331 const std::string& description,
334 bool victory_defeated,
383 std::string map_data = multiplayer[
"map_data"];
387 if(!map_data.empty()) {
398 ERR_ED <<
"Cannot convert " <<
filename_ <<
" due to missing map_data attribute.";
403 event[
"name"] =
"prestart";
404 event[
"id"] =
"editor_event-prestart";
425 c1.append_attributes(side_cfg);
428 c1.append_attributes(side_cfg);
447 if(!boost::algorithm::starts_with(
scenario_text,
"# This file was generated using the scenario editor.")) {
455 if(
scen.has_child(
"scenario")) {
456 scenario =
scen.mandatory_child(
"scenario");
457 }
else if(
scen.has_child(
"multiplayer")) {
458 scenario =
scen.mandatory_child(
"multiplayer");
459 }
else if(
scen.has_child(
"test")) {
460 scenario =
scen.mandatory_child(
"test");
462 ERR_ED <<
"Found no [scenario], [multiplayer], or [test] tag in " <<
filename_ <<
", assuming old-style editor scenario and defaulting to [multiplayer]";
464 scenario =
scen.mandatory_child(
"multiplayer");
475 random_time_ = scenario[
"random_start_time"].to_bool(
false);
477 if(!scenario[
"map_data"].str().empty()) {
479 }
else if(!scenario[
"map_file"].str().empty()) {
488 if(!side[
"recruit"].str().empty()) {
495 auto event = scenario.
find_child(
"event",
"id",
"editor_event-start");
497 event = scenario.
find_child(
"event",
"id",
"editor_event-prestart");
508 for(
const config& item :
evt.child_range(
"item")) {
513 for(
const config& music :
evt.child_range(
"music")) {
560 LOG_ED <<
"Attempted to draw terrain off the map (" <<
loc <<
")";
657 config& scenario =
scen.has_child(
"multiplayer")
658 ?
scen.mandatory_child(
"multiplayer")
659 :
scen.has_child(
"scenario")
660 ?
scen.mandatory_child(
"scenario")
661 :
scen.has_child(
"test")
662 ?
scen.mandatory_child(
"test")
663 :
scen.add_child(
"multiplayer");
667 return cfg[
"id"].str() ==
"editor_event-start" ||
cfg[
"id"].str() ==
"editor_event-prestart";
676 scenario[
"experience_modifier"] = *
xp_mod_;
689 event[
"name"] =
"prestart";
690 event[
"id"] =
"editor_event-prestart";
691 event[
"priority"] = 1000;
701 if(times[
"turns"].to_int() == -1) {
705 if(times[
"current_time"].to_int() == 0) {
713 event.append_children_by_move(times,
"time_area");
727 item[
"image"] = o.image;
728 item[
"visible_in_fog"] = o.visible_in_fog;
731 item[
"id"].write_if_not_empty(o.id);
733 item[
"team_name"].write_if_not_empty(o.team_name);
734 item[
"halo"].write_if_not_empty(o.halo);
736 item[
"submerge"] = o.submerge;
743 track->write(event,
true);
760 if(!boost::regex_match(
unit.
id(), boost::regex(
".*-[0-9]+"))) {
795 side[
"faction"] =
"Custom";
806 village.write(side.
add_child(
"village"));
835 const std::string msg =
VGETTEXT(
"Could not save time schedule: $msg",
symbols);
856 <<
"# This file was generated using the scenario editor.\n"
858 <<
"#ifdef EDITOR\n";
875 const std::string msg =
VGETTEXT(
"Could not save time schedule: $msg",
symbols);
895 <<
"# This file was generated using the scenario editor.\n"
897 <<
"# If you edit this file by hand, then do not expect common macros to be available when the editor loads the file.\n"
898 <<
"# Also expect any preprocessor constructs (which includes macros and comments) to be expanded/vanish on saving.\n"
899 <<
"# Additionally, the contents of all [side] and [time] tags as well as any events that have an id starting with 'editor_event-' are replaced entirely.\n"
900 <<
"# Any manual changes made to those will be lost.\n"
915 const std::string msg =
VGETTEXT(
"Could not save the scenario: $msg",
symbols);
938 boost::regex_constants::match_not_dot_null)) {
939 std::stringstream ss;
956 const std::string msg =
VGETTEXT(
"Could not save the map: $msg",
symbols);
975 LOG_ED <<
"Performing action " << action.
get_id() <<
": " << action.
get_name() <<
", actions count is "
995 LOG_ED <<
"Performing (partial) action " << action.
get_id() <<
": " << action.
get_name() <<
", actions count is "
1067 WRN_ED <<
"undo() called with an empty undo stack";
1081 WRN_ED <<
"redo() called with an empty redo stack";
1128 std::unique_ptr<editor_action> action;
1129 action.swap(from.back());
Variant for storing WML attributes.
Class for writing a config out to a file in pieces.
A config object defines a single node in a WML file, with access to child nodes.
void remove_attribute(std::string_view key)
config & add_child(std::string_view key)
void remove_attributes(T... keys)
void append_children_by_move(config &cfg, std::string_view key)
Moves children with the given name from the given config to this one.
void merge_attributes(const config &)
child_itors child_range(std::string_view key)
const attribute_value * get(std::string_view key) const
Returns a pointer to the attribute with the given key or nullptr if it does not exist.
optional_config_impl< config > find_child(std::string_view key, const std::string &name, const std::string &value)
Returns the first child of tag key with a name attribute containing value.
void append_attributes(const config &cfg)
Adds attributes from cfg.
std::size_t child_count(std::string_view key) const
void remove_children(std::string_view key, const std::function< bool(const config &)> &p={})
Removes all children with tag key for which p returns true.
Sort-of-Singleton that many classes, both GUI and non-GUI, use to access the game data.
Container action wrapping several actions into one.
Base class for all editor actions.
virtual const std::string & get_name() const
int get_id() const
Debugging aid.
virtual std::unique_ptr< editor_action > perform(map_context &) const
Perform the action, returning an undo action that, when performed, shall reverse any effects of this ...
static int get_instance_count()
Debugging aid.
This class adds extra editor-specific functionality to a normal gamemap.
std::set< map_location > set_starting_position_labels(display &disp)
Set labels for staring positions in the given display object.
static editor_map from_string(std::string_view data)
Wrapper around editor_map(cfg, data) that catches possible exceptions and wraps them in a editor_map_...
void set_selection(const std::set< map_location > &area)
Select the given area.
std::set< map_location > starting_position_label_locs_
Cache of set starting position labels.
std::string filename_
The actual filename of this map.
utils::optional< config > previous_cfg_
void perform_partial_action(const editor_action &action)
Performs a partial action, assumes that the top undo action has been modified to maintain coherent st...
bool playlist_contains(const std::shared_ptr< sound::music_track > &track) const
Checks whether the given track is part of current playlist.
bool pure_map_
Whether the map context refers to a file containing only the pure map data.
action_stack redo_stack_
The redo stack.
std::unique_ptr< tod_manager > tod_manager_
bool embedded_
Whether the map context refers to a map embedded in a scenario file.
void set_needs_labels_reset(bool value=true)
Setter for the labels reset flag.
void set_needs_reload(bool value=true)
Setter for the reload flag.
std::string scenario_name_
void toggle_track(const std::shared_ptr< sound::music_track > &track)
Remove the given track from the current playlist if present, else appends it.
void clear_starting_position_labels(display &disp)
editor_map map_
The map object of this map_context.
void new_side()
Adds a new side to the map.
static const std::size_t max_action_stack_size_
Action stack (i.e.
action_stack undo_stack_
The undo stack.
editor_action * last_undo_action()
void redo()
Re-does a previously undid action, and puts it back in the undo stack.
const std::string & get_filename() const
std::set< map_location > changed_locations_
void set_starting_time(int time)
void draw_terrain(const t_translation::terrain_code &terrain, const map_location &loc, bool one_layer_only=false)
Draw a terrain on a single location on the map.
virtual const editor_map & map() const override
Const map accessor.
void set_map(const editor_map &map)
void set_side_setup(editor_team_info &info)
void trim_stack(action_stack &stack)
Checks if an action stack reached its capacity and removes the front element if so.
int actions_since_save_
Number of actions performed since the map was saved.
std::string scenario_description_
void save_scenario()
Saves the scenario under the current filename.
std::vector< team > teams_
void perform_action_between_stacks(action_stack &from, action_stack &to)
Perform an action at the back of one stack, and then move it to the back of the other stack.
void perform_action(const editor_action &action)
Performs an action (thus modifying the map).
void undo()
Un-does the last action, and puts it in the redo stack for a possible redo.
void replace_schedule(const std::vector< time_of_day > &schedule)
utils::optional< bool > victory_defeated_
void remove_area(int index)
void select_area(int index)
Select the nth tod area.
void clear_undo_redo()
Clear the undo and redo stacks.
virtual ~map_context()
Map context destructor.
std::list< std::shared_ptr< sound::music_track > > music_tracks_
void draw_terrain_actual(const t_translation::terrain_code &terrain, const map_location &loc, bool one_layer_only=false)
Actual drawing function used by both overloaded variants of draw_terrain.
void clear_changed_locations()
map_context(const map_context &)=delete
utils::optional< int > xp_mod_
void add_to_recent_files()
Adds the map to the editor's recent files list.
void replace_local_schedule(const std::vector< time_of_day > &schedule)
Replace the [time]s of the currently active area.
void save_map()
Saves the map under the current filename.
void reset_starting_position_labels(display &disp)
editor_action * last_redo_action()
void partial_undo()
Un-does a single step from a undo action chain.
void set_everything_changed()
void set_needs_terrain_rebuild(bool value=true)
Setter for the terrain rebuild flag.
config convert_scenario(const config &old_scenario)
Convert an old-style editor scenario config to a config with a top level [multiplayer] tag.
bool everything_changed() const
const t_string get_default_context_name() const
void set_starting_position_labels(display &disp)
void clear_modified()
Clear the modified state.
bool victory_defeated() const
void set_scenario_setup(const std::string &id, const std::string &name, const std::string &description, int turns, int xp_mod, bool victory_defeated, bool random_time)
void add_changed_location(const map_location &loc)
void save_schedule(const std::string &schedule_id, const std::string &schedule_name)
Save custom time of day schedule in the utils directory.
terrain_code get_terrain(const map_location &loc) const
Looks up terrain at a particular location.
int w() const
Effective map width.
int h() const
Effective map height.
bool on_board_with_border(const map_location &loc) const
bool empty() const
Tell if the map is of 0 size.
std::string write() const
gamemap_base::set_terrain_result set_terrain(const map_location &loc, const terrain_code &terrain, const terrain_type_data::merge_mode mode=terrain_type_data::BOTH, bool replace_if_failed=false) override
Clobbers over the terrain at location 'loc', with the given terrain.
const terrain_type & get_terrain_info(const t_translation::terrain_code &terrain) const
@ yes_no_buttons
Shows a yes and no button.
@ auto_close
Enables auto close.
void write(config &res) const
void read(const config &cfg)
void add_recent_files_entry(const std::string &path)
Adds an entry to the recent files list.
static std::shared_ptr< music_track > create(const config &cfg)
This class stores all the data for a single 'side' (in game nomenclature).
const std::set< std::string > & recruits() const
team_shared_vision::type share_vision() const
void change_team(const std::string &name, const t_string &user_name)
const std::set< map_location > & villages() const
side_controller::type controller() const
const std::string & team_name() const
const t_string & user_team_name() const
t_translation::terrain_code terrain_with_default_base() const
Return the overlay part of this terrain, on the default_base().
umap_retval_pair_t insert(const unit_ptr &p)
Inserts the unit pointed to by p into the map.
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.
map_display and display: classes which take care of displaying the map and game-data on the screen.
lg::log_domain log_editor
Declarations for File-IO.
static std::string _(const char *str)
bool unrenamable() const
Whether this unit can be renamed.
const std::string & type_id() const
The id of this unit's type.
bool can_recruit() const
Whether this unit can recruit other units - ie, are they a leader unit.
const std::string & id() const
Gets this unit's id.
int side() const
The side this unit belongs to.
const t_string & name() const
Gets this unit's translatable display name.
const map_location & get_location() const
The current map location this unit is at.
map_location::direction facing() const
The current direction this unit is facing within its hex.
bool loyal() const
Gets whether this unit is loyal - ie, it costs no upkeep.
std::string id
Text to match against addon_info.tags()
#define log_scope2(domain, description)
std::map< std::string, config > traits_map
Manage the empty-palette in the editor.
static std::string get_map_location(const std::string &file_contents, const std::string &attr)
std::deque< std::unique_ptr< editor_action > > action_stack
Action stack typedef.
EXIT_STATUS start(bool clear_id, const std::string &filename, bool take_screenshot, const std::string &screenshot_filename)
Main interface for launching the editor from the title screen.
bool file_exists(const std::string &name)
Returns true if a file or directory with such name already exists.
bool is_cfg(const std::string &filename)
Returns true if the file ends with the wmlfile extension.
std::string base_name(const std::string &file, const bool remove_extension=false)
Returns the base filename of a file, with directory name stripped.
std::string get_map_file(const std::string &name)
bool is_directory(const std::string &fname)
Returns true if the given file is a directory.
utils::optional< std::string > get_wml_location(const std::string &path, const utils::optional< std::string > ¤t_dir=utils::nullopt)
Returns a translated path to the actual file or directory, if it exists.
std::string read_file(const std::string &fname)
Basic disk I/O - read file.
const std::string map_extension
bool is_mask(const std::string &filename)
Returns true if the file ends with the maskfile extension.
void write_file(const std::string &fname, const std::string &data, std::ios_base::openmode mode=std::ios_base::binary)
Throws io_exception if an error occurs.
std::string get_short_wml_path(const std::string &filename)
Returns a short path to filename, skipping the (user) data directory.
std::string directory_name(const std::string &file)
Returns the directory name of a file, with filename stripped.
bool is_map(const std::string &filename)
Returns true if the file ends with the mapfile extension.
std::string get_next_filename(const std::string &name, const std::string &extension)
Get the next free filename using "name + number (3 digits) + extension" maximum 1000 files then start...
std::string get_current_editor_dir(const std::string &addon_id)
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_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.
@ OK
Dialog was closed with the OK button.
config read(std::istream &in, abstract_validator *validator)
constexpr ter_layer NO_LAYER
std::set< std::string > split_set(std::string_view s, char sep, const int flags)
bool contains(const Container &container, const Value &value)
Returns true iff value is found in container.
std::string join(const Range &v, const std::string &s=",")
Generates a new string joining container items in a list.
std::map< std::string, t_string > string_map
filesystem::scoped_istream preprocess_string(const std::string &contents, const std::string &textdomain)
filesystem::scoped_istream preprocess_file(const std::string &fname, preproc_map &defines)
Function to use the WML preprocessor on a file.
std::map< std::string, struct preproc_define > preproc_map
std::string filename
Filename.
editor_team_info(const team &t)
An exception object used when an IO error occurs.
Encapsulates the map of the game.
static std::string write_direction(direction dir)
void write(config &cfg) const
static std::string get_string(enum_type key)
Converts a enum to its string equivalent.
A terrain string which is converted to a terrain is a string with 1 or 2 layers the layers are separa...