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_recall_action.hpp"
15 #include "actions/create.hpp"
16 
17 #include "gui/dialogs/transient_message.hpp"
18 #include "game_board.hpp"
19 #include "resources.hpp"
20 #include "team.hpp"
21 #include "replay.hpp"
22 #include "units/animation_component.hpp"
23 #include "units/map.hpp"
24 #include "units/unit.hpp"
25 #include "statistics.hpp"
26 #include "log.hpp"
27 #include "game_display.hpp"
28 #include "whiteboard/manager.hpp"
29 
30 static lg::log_domain log_engine("engine");
31 #define ERR_NG LOG_STREAM(err, log_engine)
32 #define LOG_NG LOG_STREAM(info, log_engine)
33 
34 namespace actions
35 {
36 namespace undo
37 {
38 
recall_action(const unit_const_ptr recalled,const map_location & loc,const map_location & from,int orig_village_owner,bool time_bonus)39 recall_action::recall_action(const unit_const_ptr recalled, const map_location& loc,
40 			  const map_location& from, int orig_village_owner, bool time_bonus)
41 	: undo_action()
42 	, shroud_clearing_action(recalled, loc, orig_village_owner, time_bonus)
43 	, id(recalled->id())
44 	, recall_from(from)
45 {}
46 
recall_action(const config & cfg,const map_location & from)47 recall_action::recall_action(const config & cfg, const map_location & from)
48 	: undo_action(cfg)
49 	, shroud_clearing_action(cfg)
50 	, id(cfg["id"])
51 	, recall_from(from)
52 {}
53 
54 /**
55  * Writes this into the provided config.
56  */
write(config & cfg) const57 void recall_action::write(config & cfg) const
58 {
59 	undo_action::write(cfg);
60 	shroud_clearing_action::write(cfg);
61 
62 	recall_from.write(cfg.add_child("leader"));
63 	cfg["id"] = id;
64 }
65 
66 /**
67  * Undoes this action.
68  * @return true on success; false on an error.
69  */
undo(int side)70 bool recall_action::undo(int side)
71 {
72 	game_display & gui = *game_display::get_singleton();
73 	unit_map &   units = resources::gameboard->units();
74 	team &current_team = resources::gameboard->get_team(side);
75 
76 	const map_location & recall_loc = route.front();
77 	unit_map::iterator un_it = units.find(recall_loc);
78 	if ( un_it == units.end() ) {
79 		return false;
80 	}
81 
82 	unit_ptr un = un_it.get_shared_ptr();
83 	if (!un) {
84 		return false;
85 	}
86 
87 	statistics::un_recall_unit(*un);
88 	int cost = statistics::un_recall_unit_cost(*un);
89 	if (cost < 0) {
90 		current_team.spend_gold(-current_team.recall_cost());
91 	}
92 	else {
93 		current_team.spend_gold(-cost);
94 	}
95 
96 	current_team.recall_list().add(un);
97 	// Invalidate everything, not just recall_loc, in case the sprite
98 	// extends into adjacent hexes (Horseman) or even farther away (Fire
99 	// Dragon)
100 	gui.invalidate_all();
101 	units.erase(recall_loc);
102 	resources::whiteboard->on_kill_unit();
103 	un->anim_comp().clear_haloes();
104 	this->return_village();
105 	execute_undo_umc_wml();
106 	return true;
107 }
108 
109 }
110 }
111