The Battle for Wesnoth 1.21.0-dev
 
Loading...
Searching...
No Matches
recall.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2010 - 2025
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/recall.hpp"
21
25
26#include "display.hpp"
27#include "fake_unit_ptr.hpp"
28#include "game_board.hpp"
30#include "resources.hpp"
31#include "replay_helper.hpp"
32#include "synced_context.hpp"
33#include "team.hpp"
34#include "units/filter.hpp"
35#include "units/unit.hpp"
37
38namespace wb
39{
40
41std::ostream& operator<<(std::ostream& s, const recall_ptr& recall)
42{
43 assert(recall);
44 return recall->print(s);
45}
46std::ostream& operator<<(std::ostream& s, const recall_const_ptr& recall)
47{
48 assert(recall);
49 return recall->print(s);
50}
51
52std::ostream& recall::print(std::ostream &s) const
53{
54 s << "Recalling " << fake_unit_->name() << " [" << fake_unit_->id() << "] on hex " << recall_hex_;
55 return s;
56}
57
58recall::recall(std::size_t team_index, bool hidden, const unit& u, const map_location& recall_hex)
59 : action(team_index,hidden)
60 , temp_unit_(u.clone())
61 , recall_hex_(recall_hex)
62 , fake_unit_(u.clone())
63 , original_mp_(0)
64 , original_ap_(0)
65 , original_recall_pos_(0)
66{
67 this->init();
68}
69
70recall::recall(const config& cfg, bool hidden)
71 : action(cfg,hidden)
72 , temp_unit_()
73 , recall_hex_(cfg.mandatory_child("recall_hex_")["x"],cfg.mandatory_child("recall_hex_")["y"], wml_loc())
74 , fake_unit_()
75 , original_mp_(0)
76 , original_ap_(0)
77 , original_recall_pos_(0)
78{
79 // Construct and validate temp_unit_
80 std::size_t underlying_id = cfg["temp_unit_"].to_size_t();
81 for(const unit_ptr & recall_unit : resources::gameboard->teams().at(team_index()).recall_list())
82 {
83 if(recall_unit->underlying_id()==underlying_id)
84 {
85 temp_unit_ = recall_unit;
86 break;
87 }
88 }
89 if(!temp_unit_.get()) {
90 throw action::ctor_err("recall: Invalid underlying_id");
91 }
92
93 fake_unit_.reset(temp_unit_->clone()); //makes copy of temp_unit_
94
95 this->init();
96}
97
99{
100 fake_unit_->set_location(recall_hex_);
101 fake_unit_->set_movement(0, true);
102 fake_unit_->set_attacks(0);
103 fake_unit_->anim_comp().set_ghosted(false);
105}
106
108{
109}
110
112{
114}
115
116void recall::execute(bool& success, bool& complete)
117{
118 team & current_team = resources::gameboard->teams().at(team_index());
119
120 assert(valid());
121 assert(temp_unit_.get());
122 temporary_unit_hider const raii(*fake_unit_);
123 //Give back the spent gold so we don't get "not enough gold" message
124 int cost = current_team.recall_cost();
125 if (temp_unit_->recall_cost() > -1) {
126 cost=temp_unit_->recall_cost();
127 }
128 current_team.get_side_actions()->change_gold_spent_by(-cost);
129 bool const result = synced_context::run_and_throw("recall",
131
132 if (!result) {
133 current_team.get_side_actions()->change_gold_spent_by(cost);
134 }
135 success = complete = result;
136}
137
139{
140 assert(valid());
141
142
143 DBG_WB << "Inserting future recall " << temp_unit_->name() << " [" << temp_unit_->id()
144 << "] at position " << temp_unit_->get_location() << ".";
145
146 //temporarily remove unit from recall list
147 unit_ptr it = resources::gameboard->teams().at(team_index()).recall_list().extract_if_matches_id(temp_unit_->id(), &original_recall_pos_);
148 assert(it);
149
150 //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.
151 temp_unit_ = it;
152 original_mp_ = temp_unit_->movement_left(true);
153 original_ap_ = temp_unit_->attacks_left(true);
154
155 temp_unit_->set_movement(0, true);
156 temp_unit_->set_attacks(0);
157 temp_unit_->set_location(recall_hex_);
158
159 //Add cost to money spent on recruits.
160 int cost = resources::gameboard->teams().at(team_index()).recall_cost();
161 if (it->recall_cost() > -1) {
162 cost = it->recall_cost();
163 }
164
165 // Temporarily insert unit into unit_map
166 //unit map takes ownership of temp_unit
168
169 resources::gameboard->teams().at(team_index()).get_side_actions()->change_gold_spent_by(cost);
170 // Update gold in top bar
172}
173
175{
177 assert(temp_unit_.get());
178
179 temp_unit_->set_movement(original_mp_, true);
180 temp_unit_->set_attacks(original_ap_);
181
182 original_mp_ = 0;
183 original_ap_ = 0;
184 //Put unit back into recall list
186}
187
189{
190 if (hex == recall_hex_)
191 {
192 const double x_offset = 0.5;
193 const double y_offset = 0.7;
194 //position 0,0 in the hex is the upper left corner
195 std::stringstream number_text;
196 unit &it = *get_unit();
197 int cost = it.recall_cost();
198 if (cost < 0) {
199 number_text << font::unicode_minus << resources::gameboard->teams().at(team_index()).recall_cost();
200 }
201 else {
202 number_text << font::unicode_minus << cost;
203 }
204 std::size_t font_size = 16;
205 color_t color {255, 0, 0}; //red
207 number_text.str(), font_size, color, x_offset, y_offset);
208 }
209}
210
215
217{
218 //Check that destination hex is still free
219 if(resources::gameboard->units().find(recall_hex_) != resources::gameboard->units().end()) {
220 return LOCATION_OCCUPIED;
221 }
222 //Check that unit to recall is still in side's recall list
223 if( !resources::gameboard->teams()[team_index()].recall_list().find_if_matches_id(temp_unit_->id()) ) {
224 return UNIT_UNAVAILABLE;
225 }
226 //Check that there is still enough gold to recall this unit
227 if(resources::gameboard->teams()[team_index()].recall_cost() > resources::gameboard->teams()[team_index()].gold()) {
228 return NOT_ENOUGH_GOLD;
229 }
230 //Check that there is a leader available to recall this unit
231 bool has_recruiter = any_recruiter(team_index() + 1, get_recall_hex(), [&](unit& leader) {
232 const unit_filter ufilt(vconfig(leader.recall_filter()));
233 return ufilt(*temp_unit_, map_location::null_location());
234 });
235
236 if(!has_recruiter) {
237 return NO_LEADER;
238 }
239
240 return OK;
241}
242
243/** @todo Find a better way to serialize unit_ because underlying_id isn't cutting it */
245{
246 config final_cfg = action::to_config();
247
248 final_cfg["type"] = "recall";
249 final_cfg["temp_unit_"] = static_cast<int>(temp_unit_->underlying_id());
250// final_cfg["temp_cost_"] = temp_cost_; //Unnecessary
251
252 config loc_cfg;
253 loc_cfg["x"]=recall_hex_.wml_x();
254 loc_cfg["y"]=recall_hex_.wml_y();
255 final_cfg.add_child("recall_hex_", std::move(loc_cfg));
256
257 return final_cfg;
258}
259
260void recall::do_hide() {fake_unit_->set_hidden(true);}
261void recall::do_show() {fake_unit_->set_hidden(false);}
262
263} //end namespace wb
A config object defines a single node in a WML file, with access to child nodes.
Definition config.hpp:157
config & add_child(std::string_view key)
Definition config.cpp:436
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:1358
bool invalidate(const map_location &loc)
Function to invalidate a specific tile for redrawing.
Definition display.cpp:2927
void invalidate_game_status()
Function to invalidate the game status displayed on the sidebar.
Definition display.hpp:308
static display * get_singleton()
Returns the display object if a display object exists.
Definition display.hpp:102
void reset()
Reset the internal unit pointer, and deregister from the manager.
void place_on_fake_unit_manager(fake_unit_manager *d)
Place this on manager's fake_units_ dequeue.
virtual const std::vector< team > & teams() const override
static config get_recall(const std::string &unit_id, const map_location &loc, const map_location &from)
static bool run_and_throw(const std::string &commandname, const config &data, action_spectator &spectator=get_default_spectator())
This class stores all the data for a single 'side' (in game nomenclature).
Definition team.hpp:74
int recall_cost() const
Definition team.hpp:198
std::shared_ptr< wb::side_actions > get_side_actions() const
get the whiteboard planned actions for this team
Definition team.hpp:413
Container associating units to locations.
Definition map.hpp:98
unit_ptr extract(const map_location &loc)
Extracts a unit from the map.
Definition map.cpp:259
umap_retval_pair_t insert(const unit_ptr &p)
Inserts the unit pointed to by p into the map.
Definition map.cpp:135
This class represents a single unit of a specific type.
Definition unit.hpp:39
A variable-expanding proxy for the config class.
Definition variable.hpp:45
Abstract base class for all the whiteboard planned actions.
Definition action.hpp:34
bool valid()
Returns whether this action is valid or not.
Definition action.hpp:135
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 action.cpp:51
error
Possible errors.
Definition action.hpp:107
@ NOT_ENOUGH_GOLD
Definition action.hpp:118
@ LOCATION_OCCUPIED
Definition action.hpp:112
@ UNIT_UNAVAILABLE
Definition action.hpp:117
unit_ptr temp_unit_
Definition recall.hpp:87
virtual void remove_temp_modifier(unit_map &unit_map)
Removes the result of this action from the specified unit map.
Definition recall.cpp:174
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:116
virtual ~recall()
Definition recall.cpp:107
map_location recall_hex_
Definition recall.hpp:88
virtual void apply_temp_modifier(unit_map &unit_map)
Applies temporarily the result of this action to the specified unit map.
Definition recall.cpp:138
int original_mp_
Definition recall.hpp:91
virtual void do_hide()
Called by the non-virtual hide() and show(), respectively.
Definition recall.cpp:260
virtual void redraw()
Redrawing function, called each time the action situation might have changed.
Definition recall.cpp:211
std::shared_ptr< recall > shared_from_this()
Definition recall.hpp:76
int original_recall_pos_
Definition recall.hpp:93
void init()
Definition recall.cpp:98
virtual std::ostream & print(std::ostream &s) const
Definition recall.cpp:52
virtual void do_show()
Definition recall.cpp:261
virtual error check_validity() const
Check the validity of the action.
Definition recall.cpp:216
map_location const get_recall_hex() const
Definition recall.hpp:70
recall(std::size_t team_index, bool hidden, const unit &unit, const map_location &recall_hex)
Definition recall.cpp:58
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:188
virtual unit_ptr get_unit() const
Definition recall.hpp:65
virtual void accept(visitor &v)
Definition recall.cpp:111
virtual config to_config() const
Definition recall.cpp:244
int original_ap_
Definition recall.hpp:92
fake_unit_ptr fake_unit_
Definition recall.hpp:89
Abstract base class for all the visitors (cf GoF Visitor Design Pattern) the whiteboard uses.
Definition visitor.hpp:33
virtual void visit(move_ptr move)=0
map_display and display: classes which take care of displaying the map and game-data on the screen.
@ actions_numbering
Move numbering for the whiteboard.
const config * cfg
int recall_cost() const
How much gold it costs to recall this unit, or -1 if the side's default recall cost is used.
Definition unit.hpp:562
const config & recall_filter() const
Gets the filter constraints upon which units this unit may recall, if able.
Definition unit.hpp:574
const std::string unicode_minus
Definition constants.cpp:42
game_board * gameboard
Definition resources.cpp:20
fake_unit_manager * fake_units
Definition resources.cpp:30
Definition display.hpp:45
std::shared_ptr< recall const > recall_const_ptr
Definition typedefs.hpp:75
bool any_recruiter(int team_num, const map_location &loc, const std::function< bool(unit &)> &func)
executes func for each unti of side of side_num that can recruit on loc.
Definition utility.cpp:83
std::ostream & operator<<(std::ostream &s, const action_ptr &action)
Definition action.cpp:34
std::shared_ptr< recall > recall_ptr
Definition typedefs.hpp:74
std::shared_ptr< unit > unit_ptr
Definition ptr.hpp:26
The basic class for representing 8-bit RGB or RGBA colour values.
Definition color.hpp:51
Encapsulates the map of the game.
Definition location.hpp:46
int wml_y() const
Definition location.hpp:187
int wml_x() const
Definition location.hpp:186
static const map_location & null_location()
Definition location.hpp:103
static map_location::direction s
#define DBG_WB
Definition typedefs.hpp:28
visitor is an abstract interface : action.accept(visitor) calls visitor.visit(action)