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