1 /*
2    Copyright (C) 2017-2018 the Battle for Wesnoth Project https://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_move_action.hpp"
15 #include "actions/move.hpp"
16 
17 #include "resources.hpp"
18 #include "replay.hpp"
19 #include "units/map.hpp"
20 #include "units/animation_component.hpp"
21 #include "log.hpp"
22 #include "game_display.hpp"
23 #include "units/udisplay.hpp"
24 #include "units/unit.hpp"
25 #include "game_board.hpp"
26 #include "map/map.hpp"
27 
28 static lg::log_domain log_engine("engine");
29 #define ERR_NG LOG_STREAM(err, log_engine)
30 #define LOG_NG LOG_STREAM(info, log_engine)
31 
32 namespace actions
33 {
34 namespace undo
35 {
36 
move_action(const unit_const_ptr moved,const std::vector<map_location>::const_iterator & begin,const std::vector<map_location>::const_iterator & end,int sm,int timebonus,int orig,const map_location::DIRECTION dir)37 move_action::move_action(const unit_const_ptr moved,
38 			const std::vector<map_location>::const_iterator & begin,
39 			const std::vector<map_location>::const_iterator & end,
40 			int sm, int timebonus, int orig, const map_location::DIRECTION dir)
41 	: undo_action()
42 	, shroud_clearing_action(moved, begin, end, orig, timebonus != 0)
43 	, starting_moves(sm)
44 	, starting_dir(dir == map_location::NDIRECTIONS ? moved->facing() : dir)
45 	, goto_hex(moved->get_goto())
46 {
47 }
48 
49 /**
50  * Writes this into the provided config.
51  */
write(config & cfg) const52 void move_action::write(config & cfg) const
53 {
54 	undo_action::write(cfg);
55 	shroud_clearing_action::write(cfg);
56 	cfg["starting_direction"] = map_location::write_direction(starting_dir);
57 	cfg["starting_moves"] = starting_moves;
58 	config & child = cfg.child("unit");
59 	child["goto_x"] = goto_hex.wml_x();
60 	child["goto_y"] = goto_hex.wml_y();
61 }
62 
63 /**
64  * Undoes this action.
65  * @return true on success; false on an error.
66  */
undo(int)67 bool move_action::undo(int)
68 {
69 	game_display & gui = *game_display::get_singleton();
70 	unit_map &   units = resources::gameboard->units();
71 
72 	// Copy some of our stored data.
73 	const int saved_moves = starting_moves;
74 	std::vector<map_location> rev_route = route;
75 	std::reverse(rev_route.begin(), rev_route.end());
76 
77 	// Check units.
78 	unit_map::iterator u = units.find(rev_route.front());
79 	const unit_map::iterator u_end = units.find(rev_route.back());
80 	if ( u == units.end()  ||  u_end != units.end() ) {
81 		//this can actually happen if the scenario designer has abused the [allow_undo] command
82 		ERR_NG << "Illegal 'undo' found. Possible abuse of [allow_undo]?" << std::endl;
83 		return false;
84 	}
85 	this->return_village();
86 
87 	// Record the unit's current state so it can be redone.
88 	starting_moves = u->movement_left();
89 	goto_hex = u->get_goto();
90 
91 	// Move the unit.
92 	unit_display::move_unit(rev_route, u.get_shared_ptr(), true, starting_dir);
93 	units.move(u->get_location(), rev_route.back());
94 	unit::clear_status_caches();
95 
96 	// Restore the unit's old state.
97 	u = units.find(rev_route.back());
98 	u->set_goto(map_location());
99 	u->set_movement(saved_moves, true);
100 	u->anim_comp().set_standing();
101 
102 	gui.invalidate_unit_after_move(rev_route.front(), rev_route.back());
103 	execute_undo_umc_wml();
104 	return true;
105 }
106 
107 
108 }
109 }
110