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