The Battle for Wesnoth  1.17.0-dev
undo_action.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2017 - 2021
3  by David White <dave@whitevine.net>
4  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY.
12 
13  See the COPYING file for more details.
14 */
15 
16 #include "actions/undo_action.hpp"
17 #include "game_board.hpp"
19 #include "resources.hpp"
20 #include "variable.hpp" // vconfig
21 #include "game_data.hpp"
22 #include "units/unit.hpp"
23 #include "sound.hpp"
24 
25 #include <cassert>
26 #include <iterator>
27 #include <algorithm>
28 
29 namespace actions
30 {
31 
33  : commands(cmds)
34  , data(ctx.data)
35  , loc1(ctx.loc1)
36  , loc2(ctx.loc2)
37  , filter_loc1(ctx.loc1.filter_loc())
38  , filter_loc2(ctx.loc2.filter_loc())
39  , uid1(), uid2()
40 {
41  unit_const_ptr u1 = ctx.loc1.get_unit(), u2 = ctx.loc2.get_unit();
42  if(u1) {
43  id1 = u1->id();
44  uid1 = u1->underlying_id();
45  }
46  if(u2) {
47  id2 = u2->id();
48  uid2 = u2->underlying_id();
49  }
50 }
51 
52 undo_event::undo_event(const config& first, const config& second, const config& weapons, const config& cmds)
53  : commands(cmds)
54  , data(weapons)
55  , loc1(first["x"], first["y"], wml_loc())
56  , loc2(second["x"], second["y"], wml_loc())
57  , filter_loc1(first["filter_x"], first["filter_y"], wml_loc())
58  , filter_loc2(second["filter_x"], second["filter_y"], wml_loc())
59  , uid1(first["underlying_id"])
60  , uid2(second["underlying_id"])
61  , id1(first["id"])
62  , id2(second["id"])
63 {
64 }
65 
68  , unit_id_diff(synced_context::get_unit_id_diff())
69 {
71  auto command_transformer = [](const std::pair<config, game_events::queued_event>& p) {
72  return undo_event(p.first, p.second);
73  };
74  std::transform(undo.begin(), undo.end(), std::back_inserter(umc_commands_undo), command_transformer);
75  undo.clear();
76 }
77 
80  , unit_id_diff(cfg["unit_id_diff"])
81 {
82  read_event_vector(umc_commands_undo, cfg, "undo_actions");
83 }
84 
85 namespace {
86  unit_ptr get_unit(std::size_t uid, const std::string& id) {
87  assert(resources::gameboard);
88  auto iter = resources::gameboard->units().find(uid);
89  if(!iter.valid() || iter->id() != id) {
90  return nullptr;
91  }
92  return iter.get_shared_ptr();
93  }
94  void execute_event(const undo_event& e, std::string tag) {
95  assert(resources::lua_kernel);
96  assert(resources::gamedata);
97 
102  int oldx1 = x1, oldy1 = y1, oldx2 = x2, oldy2 = y2;
103  x1 = e.filter_loc1.wml_x(); y1 = e.filter_loc1.wml_y();
104  x2 = e.filter_loc2.wml_x(); y2 = e.filter_loc2.wml_y();
105 
106  std::unique_ptr<scoped_xy_unit> u1, u2;
107  if(unit_ptr who = get_unit(e.uid1, e.id1)) {
108  u1.reset(new scoped_xy_unit("unit", who->get_location(), resources::gameboard->units()));
109  }
110  if(unit_ptr who = get_unit(e.uid2, e.id2)) {
111  u2.reset(new scoped_xy_unit("unit", who->get_location(), resources::gameboard->units()));
112  }
113 
114  scoped_weapon_info w1("weapon", e.data.child("first"));
115  scoped_weapon_info w2("second_weapon", e.data.child("second"));
116 
117  game_events::queued_event q(tag, "", map_location(x1, y1, wml_loc()), map_location(x2, y2, wml_loc()), e.data);
120 
121  x1 = oldx1; y1 = oldy1;
122  x2 = oldx2; y2 = oldy2;
123  }
124 }
125 
127 {
128  for(const undo_event& e : umc_commands_undo)
129  {
130  execute_event(e, "undo");
131  }
132 }
133 
134 
135 void undo_action::write(config & cfg) const
136 {
137  cfg["unit_id_diff"] = unit_id_diff;
138  write_event_vector(umc_commands_undo, cfg, "undo_actions");
140 }
141 
142 void undo_action::read_event_vector(event_vector& vec, const config& cfg, const std::string& tag)
143 {
144  for(auto c : cfg.child_range(tag)) {
145  vec.emplace_back(c.child("filter"), c.child("filter_second"), c.child("filter_weapons"), c.child("commands"));
146  }
147 }
148 
149 void undo_action::write_event_vector(const event_vector& vec, config& cfg, const std::string& tag)
150 {
151  for(const auto& evt : vec)
152  {
153  config& entry = cfg.add_child(tag);
154  config& first = entry.add_child("filter");
155  config& second = entry.add_child("filter_second");
156  entry.add_child("filter_weapons", evt.data);
157  entry.add_child("command", evt.commands);
158  // First location
159  first["filter_x"] = evt.filter_loc1.wml_x();
160  first["filter_y"] = evt.filter_loc1.wml_y();
161  first["underlying_id"] = evt.uid1;
162  first["id"] = evt.id1;
163  first["x"] = evt.loc1.wml_x();
164  first["y"] = evt.loc1.wml_y();
165  // Second location
166  second["filter_x"] = evt.filter_loc2.wml_x();
167  second["filter_y"] = evt.filter_loc2.wml_y();
168  second["underlying_id"] = evt.uid2;
169  second["id"] = evt.id2;
170  second["x"] = evt.loc2.wml_x();
171  second["y"] = evt.loc2.wml_y();
172  }
173 }
174 
175 }
config & child(config_key_type key, int n=0)
Returns the nth child with the given key, or a reference to an invalid config if there is none...
Definition: config.cpp:402
entity_location loc2
Definition: pump.hpp:66
virtual const unit_map & units() const override
Definition: game_board.hpp:112
map_location filter_loc1
Definition: undo_action.hpp:30
map_location loc1
Definition: undo_action.hpp:30
Variant for storing WML attributes.
undo_event(const config &cmds, const game_events::queued_event &ctx)
Definition: undo_action.cpp:32
child_itors child_range(config_key_type key)
Definition: config.cpp:344
int wml_x() const
Definition: location.hpp:153
virtual void write(config &cfg) const
Writes this into the provided config.
std::shared_ptr< unit > unit_ptr
Definition: ptr.hpp:26
game_data * gamedata
Definition: resources.cpp:23
config::attribute_value & get_variable(const std::string &varname)
throws invalid_variablename_exception if varname is no valid variable name.
Definition: game_data.cpp:63
Records information to be able to undo an action.
Definition: undo_action.hpp:42
event_vector umc_commands_undo
Definition: undo_action.hpp:93
std::vector< undo_event > event_vector
actions wml (specified by wml) that should be executed when undoing this command. ...
Definition: undo_action.hpp:92
static void read_event_vector(event_vector &vec, const config &cfg, const std::string &tag)
std::shared_ptr< const unit > unit_const_ptr
Definition: ptr.hpp:27
unit_const_ptr get_unit() const
int wml_y() const
Definition: location.hpp:154
game_board * gameboard
Definition: resources.cpp:21
Encapsulates the map of the game.
Definition: location.hpp:38
unit_iterator find(std::size_t id)
Definition: map.cpp:310
std::string id
Text to match against addon_info.tags()
Definition: manager.cpp:215
map_location loc2
Definition: undo_action.hpp:30
pointer get_shared_ptr() const
This is exactly the same as operator-> but it&#39;s slightly more readable, and can replace &*iter syntax...
Definition: map.hpp:218
static void write_event_vector(const event_vector &vec, config &cfg, const std::string &tag)
mock_party p
undo_action()
Default constructor.
Definition: undo_action.cpp:66
config & add_child(config_key_type key)
Definition: config.cpp:514
virtual void write(config &cfg) const
Writes this into the provided config.
Definition: undo_action.hpp:57
entity_location loc1
Definition: pump.hpp:65
A variable-expanding proxy for the config class.
Definition: variable.hpp:44
game_lua_kernel * lua_kernel
Definition: resources.cpp:26
#define e
void commit_music_changes()
Definition: sound.cpp:823
static event_list & get_undo_commands()
map_location filter_loc2
Definition: undo_action.hpp:30
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:61
mock_char c
int unit_id_diff
the difference in the unit ids TODO: does it really make sense to allow undoing if the unit id counte...
Definition: undo_action.hpp:90
virtual bool undo(int side)=0
Undoes this action.
bool run_wml_action(const std::string &, const vconfig &, const game_events::queued_event &)
Runs a command from an event handler.