The Battle for Wesnoth  1.19.0-dev
attack.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2010 - 2024
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/attack.hpp"
21 
22 #include "whiteboard/visitor.hpp"
23 
24 #include "config.hpp"
25 #include "draw.hpp"
26 #include "fake_unit_ptr.hpp"
27 #include "game_board.hpp"
28 #include "play_controller.hpp"
29 #include "resources.hpp"
30 #include "units/unit.hpp"
31 #include "units/map.hpp"
32 
33 namespace wb
34 {
35 
36 std::ostream &operator<<(std::ostream &s, attack_ptr attack)
37 {
38  assert(attack);
39  return attack->print(s);
40 }
41 
42 std::ostream &operator<<(std::ostream &s, attack_const_ptr attack)
43 {
44  assert(attack);
45  return attack->print(s);
46 }
47 
48 std::ostream& attack::print(std::ostream& s) const
49 {
50  s << "Attack on (" << get_target_hex() << ") preceded by ";
51  move::print(s);
52  return s;
53 }
54 
55 attack::attack(std::size_t team_index, bool hidden, unit& u, const map_location& target_hex, int weapon_choice, const pathfind::marked_route& route,
56  arrow_ptr arrow, fake_unit_ptr fake_unit)
57  : move(team_index, hidden, u, route, arrow, std::move(fake_unit)),
58  target_hex_(target_hex),
59  weapon_choice_(weapon_choice),
60  attack_movement_cost_(u.attacks()[weapon_choice_].movement_used()),
61  temp_movement_subtracted_(0),
62  attack_count_(u.attacks()[weapon_choice_].attacks_used()),
63  temp_attacks_subtracted_(0)
64 {
65  this->init();
66 }
67 
68 attack::attack(const config& cfg, bool hidden)
69  : move(cfg,hidden)
70  , target_hex_(cfg.mandatory_child("target_hex_")["x"], cfg.mandatory_child("target_hex_")["y"], wml_loc())
71  , weapon_choice_(cfg["weapon_choice_"].to_int(-1)) //default value: -1
72  , attack_movement_cost_()
73  , temp_movement_subtracted_(0)
74  , attack_count_()
75  , temp_attacks_subtracted_(0)
76 {
77  // Validate target_hex
79  throw action::ctor_err("attack: Invalid target_hex_");
80 
81  // Validate weapon_choice_
82  if(weapon_choice_ < 0 || weapon_choice_ >= static_cast<int>(get_unit()->attacks().size()))
83  throw action::ctor_err("attack: Invalid weapon_choice_");
84 
85  // Construct attack_movement_cost_
86  assert(get_unit());
87  attack_movement_cost_ = get_unit()->attacks()[weapon_choice_].movement_used();
88  attack_count_ = get_unit()->attacks()[weapon_choice_].attacks_used();
89 
90  this->init();
91 }
92 
94 {
96 }
97 
99 {
100  invalidate();
101 }
102 
104 {
105  v.visit(shared_from_this());
106 }
107 
108 /* private */
110 {
112  {
113  //invalidate dest and target hex so attack indicator is properly cleared
116  }
117 }
118 
119 void attack::execute(bool& success, bool& complete)
120 {
121  if(!valid()) {
122  success = false;
123  //Setting complete to true signifies to side_actions to delete the planned action: nothing more to do with it.
124  complete = true;
125  return;
126  }
127 
128  LOG_WB << "Executing: " << shared_from_this();
129 
130  if (route_->steps.size() >= 2)
131  {
132  bool m_success, m_complete;
133  move::execute(m_success,m_complete);
134  if(!m_success) {
135  //Move failed for some reason, so don't attack.
136  success = false;
137  complete = true;
138  return;
139  }
140  }
141 
143  complete = true;
144 
145  //check that attacking unit is still alive, if not, consider the attack a failure
147  if(!survivor.valid() || (!unit_id_.empty() && (survivor->id() != unit_id_)))
148  {
149  success = false;
150  }
151 
152  success = true;
153 }
154 
156 {
158  assert(get_unit());
159  unit& unit = *get_unit();
160  DBG_WB << unit.name() << " [" << unit.id()
161  << "] has " << unit.attacks_left() << " attacks, decreasing by " << attack_count_;
162  assert(unit.attacks_left() > 0);
163 
164  //Calculate movement to subtract
167  DBG_WB << "Attack: Changing movement points for unit " << unit.name() << " [" << unit.id()
168  << "] from " << unit.movement_left() << " to "
172 
173  //Update status of fake unit (not undone by remove_temp_modifiers)
174  //@todo this contradicts the name "temp_modifiers"
175  if (fake_unit_) { //Attacks that are not attack-moves don't have fake units
176  fake_unit_->set_movement(unit.movement_left(), true);
177  fake_unit_->set_attacks(unit.attacks_left());
178  }
179 }
180 
182 {
183  assert(get_unit());
184  unit& unit = *get_unit();
185  DBG_WB << unit.name() << " [" << unit.id()
186  << "] has " << unit.attacks_left() << " attacks, increasing by one";
188  DBG_WB << "Attack: Changing movement points for unit " << unit.name() << " [" << unit.id()
189  << "] from " << unit.movement_left() << " to "
195 }
196 
197 // Draws the attack indicator.
199 {
200  if(hex != get_dest_hex() && hex != target_hex_) {
201  return;
202  }
203 
204  //@todo: replace this by either the use of transparency + LAYER_ATTACK_INDICATOR,
205  //or a dedicated layer
207 
208  //calculate direction (valid for both hexes)
209  const std::string direction_text = map_location::write_direction(get_dest_hex().get_relative_dir(target_hex_));
210 
211  texture indicator = (hex == get_dest_hex())
212  ? image::get_texture("whiteboard/attack-indicator-src-" + direction_text + ".png", image::HEXED)
213  : image::get_texture("whiteboard/attack-indicator-dst-" + direction_text + ".png", image::HEXED);
214 
215  // hex is either the dst or target here. Whichever it is, we want to draw there.
217  layer, hex, [tex = std::move(indicator)](const rect& d) { draw::blit(tex, d); });
218 }
219 
221 {
222  move::redraw();
224 }
225 
227 {
228  // Verify that the unit that planned this attack exists
229  if(!get_unit()) {
230  return NO_UNIT;
231  }
232  // Verify that the target hex is still valid
233  if(!target_hex_.valid()) {
234  return INVALID_LOCATION;
235  }
236  // Verify that the target hex isn't empty
237  if(resources::gameboard->units().find(target_hex_) == resources::gameboard->units().end()){
238  return NO_TARGET;
239  }
240  // Verify that the attacking unit has attacks left
241  if(get_unit()->attacks_left() <= 0) {
242  return NO_ATTACK_LEFT;
243  }
244  // Verify that the attacker and target are enemies
245  if(!resources::gameboard->get_team(get_unit()->side()).is_enemy(resources::gameboard->units().find(target_hex_)->side())){
246  return NOT_AN_ENEMY;
247  }
248  //@todo: (maybe) verify that the target hex contains the same unit that before,
249  // comparing for example the unit ID
250 
251  return move::check_validity();
252 }
253 
255 {
256  config final_cfg = move::to_config();
257 
258  final_cfg["type"] = "attack";
259  final_cfg["weapon_choice_"] = weapon_choice_;
260 // final_cfg["attack_movement_cost_"] = attack_movement_cost_; //Unnecessary
261 // final_cfg["temp_movement_subtracted_"] = temp_movement_subtracted_; //Unnecessary
262 
263  config target_hex_cfg;
264  target_hex_cfg["x"]=target_hex_.wml_x();
265  target_hex_cfg["y"]=target_hex_.wml_y();
266  final_cfg.add_child("target_hex_", std::move(target_hex_cfg));
267 
268  return final_cfg;
269 }
270 
271 } // end namespace wb
Arrows destined to be drawn on the map.
Definition: arrow.hpp:30
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:159
config & add_child(config_key_type key)
Definition: config.cpp:441
bool invalidate(const map_location &loc)
Function to invalidate a specific tile for redrawing.
Definition: display.cpp:3137
drawing_layer
The layers to render something on.
Definition: display.hpp:802
@ LAYER_FOOTSTEPS
Footsteps showing path from unit to mouse.
Definition: display.hpp:809
void drawing_buffer_add(const drawing_layer layer, const map_location &loc, decltype(draw_helper::do_draw) draw_func)
Add an item to the drawing buffer.
Definition: display.cpp:1287
static display * get_singleton()
Returns the display object if a display object exists.
Definition: display.hpp:95
void attack_enemy(const map_location &attacker_loc, const map_location &defender_loc, int choice)
Holds a temporary unit that can be drawn on the map without being placed in the unit_map.
virtual const unit_map & units() const override
Definition: game_board.hpp:106
events::mouse_handler & get_mouse_handler_base() override
Get a reference to a mouse handler member a derived class uses.
Wrapper class to encapsulate creation and management of an SDL_Texture.
Definition: texture.hpp:33
Container associating units to locations.
Definition: map.hpp:98
unit_iterator find(std::size_t id)
Definition: map.cpp:302
This class represents a single unit of a specific type.
Definition: unit.hpp:133
bool valid()
Returns whether this action is valid or not.
Definition: action.hpp:135
error
Possible errors.
Definition: action.hpp:107
@ INVALID_LOCATION
Definition: action.hpp:109
@ NO_ATTACK_LEFT
Definition: action.hpp:115
@ NOT_AN_ENEMY
Definition: action.hpp:116
int temp_movement_subtracted_
Definition: attack.hpp:84
virtual ~attack()
Definition: attack.cpp:98
virtual void remove_temp_modifier(unit_map &unit_map)
Removes the result of this action from the specified unit map.
Definition: attack.cpp:181
int attack_count_
Definition: attack.hpp:85
int temp_attacks_subtracted_
Definition: attack.hpp:86
void invalidate()
invalidates the move-destination and attack-target hexes
Definition: attack.cpp:109
virtual void redraw()
Redrawing function, called each time the action situation might have changed.
Definition: attack.cpp:220
virtual error check_validity() const
Check the validity of the action.
Definition: attack.cpp:226
virtual void accept(visitor &v)
Definition: attack.cpp:103
int attack_movement_cost_
Definition: attack.hpp:83
virtual void apply_temp_modifier(unit_map &unit_map)
Applies temporarily the result of this action to the specified unit map.
Definition: attack.cpp:155
attack(std::size_t team_index, bool hidden, unit &mover, const map_location &target_hex, int weapon_choice, const pathfind::marked_route &route, arrow_ptr arrow, fake_unit_ptr fake_unit)
Definition: attack.cpp:55
virtual void execute(bool &success, bool &complete)
Output parameters: success: Whether or not to continue an execute-all after this execution complete: ...
Definition: attack.cpp:119
map_location target_hex_
the target of the attack
Definition: attack.hpp:80
const map_location & get_target_hex() const
Definition: attack.hpp:59
int weapon_choice_
Definition: attack.hpp:82
virtual config to_config() const
Constructs and returns a config object representing this object.
Definition: attack.cpp:254
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: attack.cpp:198
std::shared_ptr< attack > shared_from_this()
Definition: attack.hpp:65
virtual std::ostream & print(std::ostream &s) const
Definition: attack.cpp:48
void init()
Definition: attack.cpp:93
A planned move, represented on the map by an arrow and a ghosted unit in the destination hex.
Definition: move.hpp:36
void redraw()
Redrawing function, called each time the action situation might have changed.
Definition: move.cpp:565
virtual void remove_temp_modifier(unit_map &unit_map)
Removes the result of this action from the specified unit map.
Definition: move.cpp:371
virtual unit_ptr get_unit() const
Return the unit targeted by this action.
Definition: move.cpp:287
virtual error check_validity() const
Check the validity of the action.
Definition: move.cpp:438
std::string unit_id_
Definition: move.hpp:111
std::unique_ptr< pathfind::marked_route > route_
Definition: move.hpp:112
virtual std::ostream & print(std::ostream &s) const
Definition: move.cpp:56
virtual map_location get_dest_hex() const
Definition: move.cpp:302
virtual config to_config() const
Constructs and returns a config object representing this object.
Definition: move.cpp:504
virtual void execute(bool &success, bool &complete)
Output parameters: success: Whether or not to continue an execute-all after this execution complete: ...
Definition: move.cpp:204
fake_unit_ptr fake_unit_
Definition: move.hpp:118
virtual void apply_temp_modifier(unit_map &unit_map)
Applies temporarily the result of this action to the specified unit map.
Definition: move.cpp:333
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
Drawing functions, for drawing things on the screen.
const std::string & id() const
Gets this unit's id.
Definition: unit.hpp:380
const t_string & name() const
Gets this unit's translatable display name.
Definition: unit.hpp:403
int attacks_left() const
Gets the remaining number of attacks this unit can perform this turn.
Definition: unit.hpp:994
void set_attacks(int left)
Sets the number of attacks this unit has left this turn.
Definition: unit.hpp:1015
void set_movement(int moves, bool unit_action=false)
Set this unit's remaining movement to moves.
Definition: unit.cpp:1200
int movement_left() const
Gets how far a unit can move, considering the incapacitated flag.
Definition: unit.hpp:1282
bool tiles_adjacent(const map_location &a, const map_location &b)
Function which tells if two locations are adjacent.
Definition: location.cpp:502
void blit(const texture &tex, const SDL_Rect &dst)
Draws a texture, or part of a texture, at the given location.
Definition: draw.cpp:310
@ HEXED
Standard hexagonal tile mask applied, removing portions that don't fit.
Definition: picture.hpp:228
texture get_texture(const image::locator &i_locator, TYPE type, bool skip_cache)
Returns an image texture suitable for hardware-accelerated rendering.
Definition: picture.cpp:959
game_board * gameboard
Definition: resources.cpp:20
play_controller * controller
Definition: resources.cpp:21
std::size_t size(const std::string &str)
Length in characters of a UTF-8 string.
Definition: unicode.cpp:85
Definition: display.hpp:45
std::ostream & operator<<(std::ostream &s, action_ptr action)
Definition: action.cpp:34
std::shared_ptr< attack > attack_ptr
Definition: typedefs.hpp:70
std::shared_ptr< arrow > arrow_ptr
Definition: typedefs.hpp:60
std::shared_ptr< attack const > attack_const_ptr
Definition: typedefs.hpp:71
Encapsulates the map of the game.
Definition: location.hpp:38
bool valid() const
Definition: location.hpp:89
int wml_y() const
Definition: location.hpp:154
int wml_x() const
Definition: location.hpp:153
static std::string write_direction(DIRECTION dir)
Definition: location.cpp:140
Structure which holds a single route and marks for special events.
Definition: pathfind.hpp:142
An abstract description of a rectangle with integer coordinates.
Definition: rect.hpp:47
bool valid() const
Definition: map.hpp:273
static map_location::DIRECTION s
#define DBG_WB
Definition: typedefs.hpp:28
#define LOG_WB
Definition: typedefs.hpp:27
visitor is an abstract interface : action.accept(visitor) calls visitor.visit(action)
#define d