The Battle for Wesnoth  1.17.0-dev
recruit.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2010 - 2021
3  by Gabriel Morin <gabrielmorin (at) gmail (dot) com>
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 /**
17  * @file
18  */
19 
20 #include "whiteboard/recruit.hpp"
21 
22 #include "whiteboard/manager.hpp"
24 #include "whiteboard/utility.hpp"
25 #include "whiteboard/visitor.hpp"
26 
27 #include "fake_unit_manager.hpp"
28 #include "fake_unit_ptr.hpp"
29 #include "menu_events.hpp"
30 #include "play_controller.hpp"
31 #include "resources.hpp"
32 #include "units/unit.hpp"
34 #include "units/map.hpp"
35 #include "units/types.hpp"
36 
37 namespace wb
38 {
39 
40 std::ostream& operator<<(std::ostream& s, recruit_ptr recruit)
41 {
42  assert(recruit);
43  return recruit->print(s);
44 }
45 std::ostream& operator<<(std::ostream& s, recruit_const_ptr recruit)
46 {
47  assert(recruit);
48  return recruit->print(s);
49 }
50 
51 std::ostream& recruit::print(std::ostream &s) const
52 {
53  s << "Recruiting " << unit_name_ << " on hex " << recruit_hex_;
54  return s;
55 }
56 
57 recruit::recruit(std::size_t team_index, bool hidden, const std::string& unit_name, const map_location& recruit_hex):
58  action(team_index,hidden),
59  unit_name_(unit_name),
60  recruit_hex_(recruit_hex),
61  temp_unit_(create_corresponding_unit()), //auto-ptr ownership transfer
62  fake_unit_(temp_unit_->clone()), //temp_unit_ *copied* into new fake unit
63  cost_(0)
64 {
65  this->init();
66 }
67 
68 recruit::recruit(const config& cfg, bool hidden)
69  : action(cfg,hidden)
70  , unit_name_(cfg["unit_name_"])
71  , recruit_hex_(cfg.child("recruit_hex_")["x"],cfg.child("recruit_hex_")["y"], wml_loc())
72  , temp_unit_()
73  , fake_unit_()
74  , cost_(0)
75 {
76  // Validate unit_name_
78  throw action::ctor_err("recruit: Invalid recruit unit type");
79 
80  // Construct temp_unit_ and fake_unit_
81  temp_unit_ = create_corresponding_unit(); //auto-ptr ownership transfer
82  fake_unit_.reset(temp_unit_->clone()); //temp_unit_ copied into new fake_unit
83 
84  this->init();
85 }
86 
88 {
89  temp_unit_->set_movement(0, true);
90  temp_unit_->set_attacks(0);
91 
92  fake_unit_->set_location(recruit_hex_);
93  fake_unit_->set_movement(0, true);
94  fake_unit_->set_attacks(0);
95  fake_unit_->anim_comp().set_ghosted(false);
97 
98  cost_ = fake_unit_->type().cost();
99 }
100 
102 {
103 }
104 
106 {
107  v.visit(shared_from_this());
108 }
109 
110 void recruit::execute(bool& success, bool& complete)
111 {
112  assert(valid());
113  temporary_unit_hider const raii(*fake_unit_);
114  const std::size_t old_id = fake_unit_->underlying_id();
116  const int side_num = team_index() + 1;
117  //Give back the spent gold so we don't get "not enough gold" message
118  resources::gameboard->teams().at(team_index()).get_side_actions()->change_gold_spent_by(-cost_);
119  bool const result = resources::controller->get_menu_handler().do_recruit(unit_name_, side_num, loc);
120  //If it failed, take back the gold
121  if (!result) {
122  resources::gameboard->teams().at(team_index()).get_side_actions()->change_gold_spent_by(cost_);
123  }
124  else {
125  auto mit = resources::gameboard->units().find(loc);
126  if(mit != resources::gameboard->units().end()) {
127  viewer_actions()->update_recruited_unit(old_id, *mit);
128  }
129 
130  }
131  success = complete = result;
132 }
133 
135 {
136  assert(valid());
137  temp_unit_->set_location(recruit_hex_);
138 
139  DBG_WB << "Inserting future recruit [" << temp_unit_->id()
140  << "] at position " << temp_unit_->get_location() << ".\n";
141 
142  // Add cost to money spent on recruits.
143  resources::gameboard->teams().at(team_index()).get_side_actions()->change_gold_spent_by(cost_);
144 
145  // Temporarily insert unit into unit_map
146  // unit map takes ownership of temp_unit
147  const size_t old_id = temp_unit_->underlying_id();
148  unit_map.insert(temp_unit_);
149 
150  //in the past there was a bug where the map changed the unit ids here (because a unit with that id already existed) which caused crashes later.
151  assert(temp_unit_->underlying_id() == old_id);
152 
153  // Update gold in the top bar
155 }
156 
158 {
159  //Unit map gives back ownership of temp_unit_
160  temp_unit_ = unit_map.extract(recruit_hex_);
161 
162  //remove simulated unit refresh on new turn done by mapbuilder.
163  temp_unit_->set_movement(0, true);
164  temp_unit_->set_attacks(0);
165 
166  assert(temp_unit_.get());
167 }
168 
170 {
171  if (hex == recruit_hex_)
172  {
173  const double x_offset = 0.5;
174  const double y_offset = 0.7;
175  //position 0,0 in the hex is the upper left corner
176  std::stringstream number_text;
177  number_text << font::unicode_minus << cost_;
178  std::size_t font_size = 16;
179  color_t color {255, 0, 0}; //red
181  number_text.str(), font_size, color, x_offset, y_offset);
182  }
183 }
184 
186 {
188 }
189 
190 
192 {
194  assert(type);
195  int side_num = team_index() + 1;
196  //real_unit = false needed to avoid generating random traits and causing OOS
197  bool real_unit = false;
198  unit_ptr result = unit::create(*type, side_num, real_unit);
199  result->set_movement(0, true);
200  result->set_attacks(0);
201  return result; //ownership gets transferred to returned unique_ptr copy
202 }
203 
205 {
206  //Check that destination hex is still free
207  if(resources::gameboard->units().find(recruit_hex_) != resources::gameboard->units().end()) {
208  return LOCATION_OCCUPIED;
209  }
210  //Check that unit to recruit is still in side's recruit list
211  const std::set<std::string>& recruits = resources::gameboard->teams()[team_index()].recruits();
212  if(recruits.find(unit_name_) == recruits.end()) {
213  bool in_extra_recruit = any_recruiter(team_index() + 1, get_recruit_hex(), [&](unit& leader) {
214  return std::find(leader.recruits().begin(), leader.recruits().end(), unit_name_) != leader.recruits().end();
215  });
216  if (!in_extra_recruit) {
217  return UNIT_UNAVAILABLE;
218  }
219  }
220  //Check that there is still enough gold to recruit this unit
221  if(temp_unit_->cost() > resources::gameboard->teams()[team_index()].gold()) {
222  return NOT_ENOUGH_GOLD;
223  }
224  //Check that there is a leader available to recruit this unit
226  return NO_LEADER;
227  }
228 
229  return OK;
230 }
231 
233 {
234  config final_cfg = action::to_config();
235 
236  final_cfg["type"] = "recruit";
237  final_cfg["unit_name_"] = unit_name_;
238 // final_cfg["temp_cost_"] = temp_cost_; //Unnecessary
239 
240  config loc_cfg;
241  loc_cfg["x"]=recruit_hex_.wml_x();
242  loc_cfg["y"]=recruit_hex_.wml_y();
243  final_cfg.add_child("recruit_hex_", std::move(loc_cfg));
244 
245  return final_cfg;
246 }
247 
248 void recruit::do_hide() {fake_unit_->set_hidden(true);}
249 void recruit::do_show() {fake_unit_->set_hidden(false);}
250 
251 }
play_controller * controller
Definition: resources.cpp:22
void reset()
Reset the internal unit pointer, and deregister from the manager.
Move numbering for the whiteboard.
Definition: display.hpp:855
static display * get_singleton()
Returns the display object if a display object exists.
Definition: display.hpp:92
const unit_type * find(const std::string &key, unit_type::BUILD_STATUS status=unit_type::FULL) const
Finds a unit_type by its id() and makes sure it is built to the specified level.
Definition: types.cpp:1262
virtual const std::vector< team > & teams() const override
Definition: game_board.hpp:85
void invalidate_game_status()
Function to invalidate the game status displayed on the sidebar.
Definition: display.hpp:296
virtual error check_validity() const
Check the validity of the action.
Definition: recruit.cpp:204
virtual ~recruit()
Definition: recruit.cpp:101
virtual const unit_map & units() const override
Definition: game_board.hpp:112
std::shared_ptr< recruit const > recruit_const_ptr
Definition: typedefs.hpp:73
bool invalidate(const map_location &loc)
Function to invalidate a specific tile for redrawing.
Definition: display.cpp:3026
This class represents a single unit of a specific type.
Definition: unit.hpp:121
umap_retval_pair_t insert(unit_ptr p)
Inserts the unit pointed to by p into the map.
Definition: map.cpp:134
void place_on_fake_unit_manager(fake_unit_manager *d)
Place this on manager&#39;s fake_units_ dequeue.
void init()
Definition: recruit.cpp:87
unit * find_recruiter(std::size_t team_index, const map_location &hex)
Definition: utility.cpp:80
int wml_x() const
Definition: location.hpp:153
virtual void visit(move_ptr move)=0
unit_type_data unit_types
Definition: types.cpp:1481
virtual void execute(bool &success, bool &complete)
Output parameters: success: Whether or not to continue an execute-all after this execution complete: ...
Definition: recruit.cpp:110
virtual void apply_temp_modifier(unit_map &unit_map)
Applies temporarily the result of this action to the specified unit map.
Definition: recruit.cpp:134
bool do_recruit(const std::string &name, int side_num, map_location &target_hex)
virtual void do_hide()
Called by the non-virtual hide() and show(), respectively.
Definition: recruit.cpp:248
static config unit_name(const unit *u)
Definition: reports.cpp:160
std::shared_ptr< unit > unit_ptr
Definition: ptr.hpp:26
static unit_ptr create(const config &cfg, bool use_traits=false, const vconfig *vcfg=nullptr)
Initializes a unit from a config.
Definition: unit.hpp:190
A single unit type that the player may recruit.
Definition: types.hpp:45
std::size_t team_index() const
Returns the index of the team that owns this action.
Definition: action.hpp:84
virtual config to_config() const
Constructs and returns a config object representing this object.
Definition: recruit.cpp:232
unit_ptr temp_unit_
Definition: recruit.hpp:88
bool valid()
Returns whether this action is valid or not.
Definition: action.hpp:135
fake_unit_ptr fake_unit_
Definition: recruit.hpp:89
const std::string unicode_minus
Definition: constants.cpp:42
map_location const get_recruit_hex() const
Definition: recruit.hpp:75
std::shared_ptr< recruit > recruit_ptr
Definition: typedefs.hpp:72
error
Possible errors.
Definition: action.hpp:106
unit_ptr create_corresponding_unit()
Definition: recruit.cpp:191
int wml_y() const
Definition: location.hpp:154
game_board * gameboard
Definition: resources.cpp:21
fake_unit_manager * fake_units
Definition: resources.cpp:31
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:1523
recruit(std::size_t team_index, bool hidden, const std::string &unit_name, const map_location &recruit_hex)
Definition: recruit.cpp:57
virtual void do_show()
Definition: recruit.cpp:249
virtual void accept(visitor &v)
Definition: recruit.cpp:105
std::string unit_name_
Definition: recruit.hpp:85
Encapsulates the map of the game.
Definition: location.hpp:38
unit_iterator find(std::size_t id)
Definition: map.cpp:310
std::shared_ptr< recruit > shared_from_this()
Definition: recruit.hpp:81
static map_location::DIRECTION s
virtual void redraw()
Redrawing function, called each time the action situation might have changed.
Definition: recruit.cpp:185
side_actions_ptr viewer_actions()
Definition: utility.cpp:51
config & add_child(config_key_type key)
Definition: config.cpp:514
const std::vector< std::string > & recruits() const
The type IDs of the other units this unit may recruit, if possible.
Definition: unit.hpp:615
virtual std::ostream & print(std::ostream &s) const
Definition: recruit.cpp:51
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:93
map_location recruit_hex_
Definition: recruit.hpp:86
bool hidden() const
Definition: action.hpp:64
events::menu_handler & get_menu_handler()
#define DBG_WB
Definition: typedefs.hpp:28
unit_ptr extract(const map_location &loc)
Extracts a unit from the map.
Definition: map.cpp:267
Container associating units to locations.
Definition: map.hpp:98
std::ostream & operator<<(std::ostream &s, action_ptr action)
Definition: action.cpp:34
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: recruit.cpp:169
visitor is an abstract interface : action.accept(visitor) calls visitor.visit(action) ...
Abstract base class for all the whiteboard planned actions.
Definition: action.hpp:33
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:61
virtual config to_config() const
Constructs and returns a config object representing this object.
Definition: action.cpp:51
virtual void remove_temp_modifier(unit_map &unit_map)
Removes the result of this action from the specified unit map.
Definition: recruit.cpp:157
Definition: display.hpp:49
Abstract base class for all the visitors (cf GoF Visitor Design Pattern) the whiteboard uses...
Definition: visitor.hpp:32