The Battle for Wesnoth  1.15.1+dev
recall.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2010 - 2018 by Gabriel Morin <gabrielmorin (at) gmail (dot) com>
3  Part of the Battle for Wesnoth Project https://www.wesnoth.org
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY.
11 
12  See the COPYING file for more details.
13  */
14 
15 /**
16  * @file
17  */
18 
19 #include "whiteboard/recall.hpp"
20 
21 #include "whiteboard/manager.hpp"
23 #include "whiteboard/utility.hpp"
24 #include "whiteboard/visitor.hpp"
25 
26 #include "actions/create.hpp"
27 #include "display.hpp"
28 #include "fake_unit_manager.hpp"
29 #include "fake_unit_ptr.hpp"
30 #include "game_board.hpp"
31 #include "recall_list_manager.hpp"
32 #include "resources.hpp"
33 #include "replay_helper.hpp"
34 #include "statistics.hpp"
35 #include "synced_context.hpp"
36 #include "team.hpp"
37 #include "units/filter.hpp"
38 #include "units/unit.hpp"
40 
41 namespace wb
42 {
43 
44 std::ostream& operator<<(std::ostream& s, recall_ptr recall)
45 {
46  assert(recall);
47  return recall->print(s);
48 }
49 std::ostream& operator<<(std::ostream& s, recall_const_ptr recall)
50 {
51  assert(recall);
52  return recall->print(s);
53 }
54 
55 std::ostream& recall::print(std::ostream &s) const
56 {
57  s << "Recalling " << fake_unit_->name() << " [" << fake_unit_->id() << "] on hex " << recall_hex_;
58  return s;
59 }
60 
61 recall::recall(std::size_t team_index, bool hidden, const unit& u, const map_location& recall_hex)
62  : action(team_index,hidden)
63  , temp_unit_(u.clone())
64  , recall_hex_(recall_hex)
65  , fake_unit_(u.clone())
66  , original_mp_(0)
67  , original_ap_(0)
69 {
70  this->init();
71 }
72 
73 recall::recall(const config& cfg, bool hidden)
74  : action(cfg,hidden)
75  , temp_unit_()
76  , recall_hex_(cfg.child("recall_hex_")["x"],cfg.child("recall_hex_")["y"], wml_loc())
77  , fake_unit_()
78  , original_mp_(0)
79  , original_ap_(0)
81 {
82  // Construct and validate temp_unit_
83  std::size_t underlying_id = cfg["temp_unit_"];
84  for(const unit_ptr & recall_unit : resources::gameboard->teams().at(team_index()).recall_list())
85  {
86  if(recall_unit->underlying_id()==underlying_id)
87  {
89  break;
90  }
91  }
92  if(!temp_unit_.get()) {
93  throw action::ctor_err("recall: Invalid underlying_id");
94  }
95 
96  fake_unit_.reset(temp_unit_->clone()); //makes copy of temp_unit_
97 
98  this->init();
99 }
100 
102 {
103  fake_unit_->set_location(recall_hex_);
104  fake_unit_->set_movement(0, true);
105  fake_unit_->set_attacks(0);
106  fake_unit_->anim_comp().set_ghosted(false);
108 }
109 
111 {
112 }
113 
115 {
116  v.visit(shared_from_this());
117 }
118 
119 void recall::execute(bool& success, bool& complete)
120 {
121  team & current_team = resources::gameboard->teams().at(team_index());
122 
123  assert(valid());
124  assert(temp_unit_.get());
125  temporary_unit_hider const raii(*fake_unit_);
126  //Give back the spent gold so we don't get "not enough gold" message
127  int cost = current_team.recall_cost();
128  if (temp_unit_->recall_cost() > -1) {
129  cost=temp_unit_->recall_cost();
130  }
131  current_team.get_side_actions()->change_gold_spent_by(-cost);
132  bool const result = synced_context::run_and_throw("recall",
134  true,
135  true,
137 
138  if (!result) {
139  current_team.get_side_actions()->change_gold_spent_by(cost);
140  }
141  success = complete = result;
142 }
143 
145 {
146  assert(valid());
147 
148 
149  DBG_WB << "Inserting future recall " << temp_unit_->name() << " [" << temp_unit_->id()
150  << "] at position " << temp_unit_->get_location() << ".\n";
151 
152  //temporarily remove unit from recall list
153  unit_ptr it = resources::gameboard->teams().at(team_index()).recall_list().extract_if_matches_id(temp_unit_->id(), &original_recall_pos_);
154  assert(it);
155 
156  //Usually (temp_unit_ == it) is true here, but wml might have changed the original unit in which case not doing 'temp_unit_ = it' would result in a gamestate change.
157  temp_unit_ = it;
158  original_mp_ = temp_unit_->movement_left(true);
159  original_ap_ = temp_unit_->attacks_left(true);
160 
161  temp_unit_->set_movement(0, true);
162  temp_unit_->set_attacks(0);
163  temp_unit_->set_location(recall_hex_);
164 
165  //Add cost to money spent on recruits.
166  int cost = resources::gameboard->teams().at(team_index()).recall_cost();
167  if (it->recall_cost() > -1) {
168  cost = it->recall_cost();
169  }
170 
171  // Temporarily insert unit into unit_map
172  //unit map takes ownership of temp_unit
173  unit_map.insert(temp_unit_);
174 
175  resources::gameboard->teams().at(team_index()).get_side_actions()->change_gold_spent_by(cost);
176  // Update gold in top bar
178 }
179 
181 {
182  temp_unit_ = unit_map.extract(recall_hex_);
183  assert(temp_unit_.get());
184 
185  temp_unit_->set_movement(original_mp_, true);
186  temp_unit_->set_attacks(original_ap_);
187 
188  original_mp_ = 0;
189  original_ap_ = 0;
190  //Put unit back into recall list
192 }
193 
195 {
196  if (hex == recall_hex_)
197  {
198  const double x_offset = 0.5;
199  const double y_offset = 0.7;
200  //position 0,0 in the hex is the upper left corner
201  std::stringstream number_text;
202  unit &it = *get_unit();
203  int cost = statistics::un_recall_unit_cost(it);
204  if (cost < 0) {
205  number_text << font::unicode_minus << resources::gameboard->teams().at(team_index()).recall_cost();
206  }
207  else {
208  number_text << font::unicode_minus << cost;
209  }
210  std::size_t font_size = 16;
211  color_t color {255, 0, 0}; //red
213  number_text.str(), font_size, color, x_offset, y_offset);
214  }
215 }
216 
218 {
220 }
221 
223 {
224  //Check that destination hex is still free
225  if(resources::gameboard->units().find(recall_hex_) != resources::gameboard->units().end()) {
226  return LOCATION_OCCUPIED;
227  }
228  //Check that unit to recall is still in side's recall list
229  if( !resources::gameboard->teams()[team_index()].recall_list().find_if_matches_id(temp_unit_->id()) ) {
230  return UNIT_UNAVAILABLE;
231  }
232  //Check that there is still enough gold to recall this unit
233  if(resources::gameboard->teams()[team_index()].recall_cost() > resources::gameboard->teams()[team_index()].gold()) {
234  return NOT_ENOUGH_GOLD;
235  }
236  //Check that there is a leader available to recall this unit
237  bool has_recruiter = any_recruiter(team_index() + 1, get_recall_hex(), [&](unit& leader) {
238  const unit_filter ufilt(vconfig(leader.recall_filter()));
239  return ufilt(*temp_unit_, map_location::null_location());
240  });
241 
242  if(!has_recruiter) {
243  return NO_LEADER;
244  }
245 
246  return OK;
247 }
248 
249 ///@todo Find a better way to serialize unit_ because underlying_id isn't cutting it
251 {
252  config final_cfg = action::to_config();
253 
254  final_cfg["type"] = "recall";
255  final_cfg["temp_unit_"] = static_cast<int>(temp_unit_->underlying_id());
256 // final_cfg["temp_cost_"] = temp_cost_; //Unnecessary
257 
258  config loc_cfg;
259  loc_cfg["x"]=recall_hex_.wml_x();
260  loc_cfg["y"]=recall_hex_.wml_y();
261  final_cfg.add_child("recall_hex_", std::move(loc_cfg));
262 
263  return final_cfg;
264 }
265 
266 void recall::do_hide() {fake_unit_->set_hidden(true);}
267 void recall::do_show() {fake_unit_->set_hidden(false);}
268 
269 } //end namespace wb
void reset()
Reset the internal unit pointer, and deregister from the manager. This fake_unit_ptr is now dissassoc...
std::shared_ptr< wb::side_actions > get_side_actions() const
get the whiteboard planned actions for this team
Definition: team.hpp:382
bool recall_unit(const std::string &id, team &current_team, const map_location &loc, const map_location &from, map_location::DIRECTION facing, bool show, bool use_undo)
Recalls the unit with the indicated ID for the provided team.
Definition: create.cpp:740
Move numbering for the whiteboard.
Definition: display.hpp:846
virtual void do_show()
Definition: recall.cpp:267
static display * get_singleton()
Returns the display object if a display object exists.
Definition: display.hpp:88
virtual const std::vector< team > & teams() const override
Definition: game_board.hpp:92
void invalidate_game_status()
Function to invalidate the game status displayed on the sidebar.
Definition: display.hpp:291
bool invalidate(const map_location &loc)
Function to invalidate a specific tile for redrawing.
Definition: display.cpp:2975
This class represents a single unit of a specific type.
Definition: unit.hpp:99
fake_unit_ptr fake_unit_
Definition: recall.hpp:88
umap_retval_pair_t insert(unit_ptr p)
Inserts the unit pointed to by p into the map.
Definition: map.cpp:135
static config get_recall(const std::string &unit_id, const map_location &loc, const map_location &from)
virtual void do_hide()
Called by the non-virtual hide() and show(), respectively.
Definition: recall.cpp:266
int original_mp_
Definition: recall.hpp:90
void place_on_fake_unit_manager(fake_unit_manager *d)
Place this on manager&#39;s fake_units_ dequeue.
std::shared_ptr< recall const > recall_const_ptr
Definition: typedefs.hpp:74
virtual void execute(bool &success, bool &complete)
Output parameters: success: Whether or not to continue an execute-all after this execution complete: ...
Definition: recall.cpp:119
virtual void accept(visitor &v)
Definition: recall.cpp:114
virtual void remove_temp_modifier(unit_map &unit_map)
Removes the result of this action from the specified unit map.
Definition: recall.cpp:180
int wml_x() const
Definition: location.hpp:157
virtual void visit(move_ptr move)=0
virtual void apply_temp_modifier(unit_map &unit_map)
Applies temporarily the result of this action to the specified unit map.
Definition: recall.cpp:144
-file sdl_utils.hpp
std::size_t team_index() const
Returns the index of the team that owns this action.
Definition: action.hpp:83
virtual void draw_hex(const map_location &hex)
Gets called by display when drawing a hex, to allow actions to draw to the screen.
Definition: recall.cpp:194
bool valid()
Returns whether this action is valid or not.
Definition: action.hpp:134
This class stores all the data for a single &#39;side&#39; (in game nomenclature).
Definition: team.hpp:44
static std::string at(const std::string &file, int line)
const std::string unicode_minus
Definition: constants.cpp:38
error
Possible errors.
Definition: action.hpp:105
int wml_y() const
Definition: location.hpp:158
static void ignore_error_function(const std::string &message, bool heavy)
a function to be passed to run_in_synced_context to ignore the error.
const config & recall_filter() const
Gets the filter constraints upon which units this unit may recall, if able.
Definition: unit.hpp:609
int un_recall_unit_cost(const unit &u)
Definition: statistics.cpp:671
game_board * gameboard
Definition: resources.cpp:20
fake_unit_manager * fake_units
Definition: resources.cpp:30
void draw_text_in_hex(const map_location &loc, const drawing_layer layer, const std::string &text, std::size_t font_size, color_t color, double x_in_hex=0.5, double y_in_hex=0.5)
Draw text on a hex.
Definition: display.cpp:1491
map_display and display: classes which take care of displaying the map and game-data on the screen...
map_location recall_hex_
Definition: recall.hpp:87
std::shared_ptr< recall > shared_from_this()
Definition: recall.hpp:75
int recall_cost() const
Definition: team.hpp:193
Encapsulates the map of the game.
Definition: location.hpp:42
Various functions related to the creation of units (recruits, recalls, and placed units)...
virtual error check_validity() const
Check the validity of the action.
Definition: recall.cpp:222
virtual std::ostream & print(std::ostream &s) const
Definition: recall.cpp:55
virtual void redraw()
Redrawing function, called each time the action situation might have changed.
Definition: recall.cpp:217
static map_location::DIRECTION s
map_location const get_recall_hex() const
Definition: recall.hpp:69
void init()
Definition: recall.cpp:101
config & add_child(config_key_type key)
Definition: config.cpp:476
bool any_recruiter(int team_num, const map_location &loc, std::function< bool(unit &)> func)
executes func for each unti of side of side_num that can recruit on loc.
Definition: utility.cpp:92
static bool run_and_throw(const std::string &commandname, const config &data, bool use_undo=true, bool show=true, synced_command::error_handler_function error_handler=default_error_function)
boost::intrusive_ptr< unit > unit_ptr
Definition: ptr.hpp:29
bool hidden() const
Definition: action.hpp:63
bool find(E event, F functor)
Tests whether an event handler is available.
#define DBG_WB
Definition: typedefs.hpp:27
A variable-expanding proxy for the config class.
Definition: variable.hpp:42
unit_ptr extract(const map_location &loc)
Extracts a unit from the map.
Definition: map.cpp:268
virtual config to_config() const
Definition: recall.cpp:250
static const map_location & null_location()
Definition: location.hpp:85
Container associating units to locations.
Definition: map.hpp:99
virtual ~recall()
Definition: recall.cpp:110
std::ostream & operator<<(std::ostream &s, action_ptr action)
Definition: action.cpp:33
std::shared_ptr< recall > recall_ptr
Definition: typedefs.hpp:73
visitor is an abstract interface : action.accept(visitor) calls visitor.visit(action) ...
Abstract base class for all the whiteboard planned actions.
Definition: action.hpp:32
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:92
recall(std::size_t team_index, bool hidden, const unit &unit, const map_location &recall_hex)
Definition: recall.cpp:61
unit_ptr temp_unit_
Definition: recall.hpp:86
int original_ap_
Definition: recall.hpp:91
const int font_size
Definition: button.cpp:40
virtual config to_config() const
Constructs and returns a config object representing this object.
Definition: action.cpp:50
virtual unit_ptr get_unit() const
Definition: recall.hpp:64
int original_recall_pos_
Definition: recall.hpp:92
Definition: display.hpp:48
Abstract base class for all the visitors (cf GoF Visitor Design Pattern) the whiteboard uses...
Definition: visitor.hpp:31