The Battle for Wesnoth  1.19.7+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 <utility>
23 
24 #include "whiteboard/visitor.hpp"
25 
26 #include "config.hpp"
27 #include "draw.hpp"
28 #include "fake_unit_ptr.hpp"
29 #include "game_board.hpp"
30 #include "play_controller.hpp"
31 #include "resources.hpp"
32 #include "units/unit.hpp"
33 #include "units/map.hpp"
34 
35 namespace wb
36 {
37 
38 std::ostream &operator<<(std::ostream &s, const attack_ptr& attack)
39 {
40  assert(attack);
41  return attack->print(s);
42 }
43 
44 std::ostream &operator<<(std::ostream &s, const attack_const_ptr& attack)
45 {
46  assert(attack);
47  return attack->print(s);
48 }
49 
50 std::ostream& attack::print(std::ostream& s) const
51 {
52  s << "Attack on (" << get_target_hex() << ") preceded by ";
53  move::print(s);
54  return s;
55 }
56 
57 attack::attack(std::size_t team_index, bool hidden, unit& u, const map_location& target_hex, int weapon_choice, const pathfind::marked_route& route,
58  arrow_ptr arrow, fake_unit_ptr fake_unit)
59  : move(team_index, hidden, u, route, std::move(arrow), std::move(fake_unit)),
60  target_hex_(target_hex),
61  weapon_choice_(weapon_choice),
62  attack_movement_cost_(u.attacks()[weapon_choice_].movement_used()),
63  temp_movement_subtracted_(0),
64  attack_count_(u.attacks()[weapon_choice_].attacks_used()),
65  temp_attacks_subtracted_(0)
66 {
67  this->init();
68 }
69 
70 attack::attack(const config& cfg, bool hidden)
71  : move(cfg,hidden)
72  , target_hex_(cfg.mandatory_child("target_hex_")["x"], cfg.mandatory_child("target_hex_")["y"], wml_loc())
73  , weapon_choice_(cfg["weapon_choice_"].to_int(-1)) //default value: -1
74  , attack_movement_cost_()
75  , temp_movement_subtracted_(0)
76  , attack_count_()
77  , temp_attacks_subtracted_(0)
78 {
79  // Validate target_hex
81  throw action::ctor_err("attack: Invalid target_hex_");
82 
83  // Validate weapon_choice_
84  if(weapon_choice_ < 0 || weapon_choice_ >= static_cast<int>(get_unit()->attacks().size()))
85  throw action::ctor_err("attack: Invalid weapon_choice_");
86 
87  // Construct attack_movement_cost_
88  assert(get_unit());
89  attack_movement_cost_ = get_unit()->attacks()[weapon_choice_].movement_used();
90  attack_count_ = get_unit()->attacks()[weapon_choice_].attacks_used();
91 
92  this->init();
93 }
94 
96 {
98 }
99 
101 {
102  invalidate();
103 }
104 
106 {
107  v.visit(shared_from_this());
108 }
109 
110 /* private */
112 {
114  {
115  //invalidate dest and target hex so attack indicator is properly cleared
118  }
119 }
120 
121 void attack::execute(bool& success, bool& complete)
122 {
123  if(!valid()) {
124  success = false;
125  //Setting complete to true signifies to side_actions to delete the planned action: nothing more to do with it.
126  complete = true;
127  return;
128  }
129 
130  LOG_WB << "Executing: " << shared_from_this();
131 
132  if (route_->steps.size() >= 2)
133  {
134  bool m_success, m_complete;
135  move::execute(m_success,m_complete);
136  if(!m_success) {
137  //Move failed for some reason, so don't attack.
138  success = false;
139  complete = true;
140  return;
141  }
142  }
143 
145  complete = true;
146 
147  //check that attacking unit is still alive, if not, consider the attack a failure
149  if(!survivor.valid() || (!unit_id_.empty() && (survivor->id() != unit_id_)))
150  {
151  success = false;
152  }
153 
154  success = true;
155 }
156 
158 {
160  assert(get_unit());
161  unit& unit = *get_unit();
162  DBG_WB << unit.name() << " [" << unit.id()
163  << "] has " << unit.attacks_left() << " attacks, decreasing by " << attack_count_;
164  assert(unit.attacks_left() > 0);
165 
166  //Calculate movement to subtract
169  DBG_WB << "Attack: Changing movement points for unit " << unit.name() << " [" << unit.id()
170  << "] from " << unit.movement_left() << " to "
174 
175  //Update status of fake unit (not undone by remove_temp_modifiers)
176  //@todo this contradicts the name "temp_modifiers"
177  if (fake_unit_) { //Attacks that are not attack-moves don't have fake units
178  fake_unit_->set_movement(unit.movement_left(), true);
179  fake_unit_->set_attacks(unit.attacks_left());
180  }
181 }
182 
184 {
185  assert(get_unit());
186  unit& unit = *get_unit();
187  DBG_WB << unit.name() << " [" << unit.id()
188  << "] has " << unit.attacks_left() << " attacks, increasing by one";
190  DBG_WB << "Attack: Changing movement points for unit " << unit.name() << " [" << unit.id()
191  << "] from " << unit.movement_left() << " to "
197 }
198 
199 // Draws the attack indicator.
201 {
202  if(hex != get_dest_hex() && hex != target_hex_) {
203  return;
204  }
205 
206  //@todo: replace this by either the use of transparency + drawing_layer::attack_indicator,
207  //or a dedicated layer
209 
210  //calculate direction (valid for both hexes)
211  const std::string direction_text = map_location::write_direction(get_dest_hex().get_relative_dir(target_hex_));
212 
213  texture indicator = (hex == get_dest_hex())
214  ? image::get_texture("whiteboard/attack-indicator-src-" + direction_text + ".png", image::HEXED)
215  : image::get_texture("whiteboard/attack-indicator-dst-" + direction_text + ".png", image::HEXED);
216 
217  // hex is either the dst or target here. Whichever it is, we want to draw there.
219  layer, hex, [tex = std::move(indicator)](const rect& d) { draw::blit(tex, d); });
220 }
221 
223 {
224  move::redraw();
226 }
227 
229 {
230  // Verify that the unit that planned this attack exists
231  if(!get_unit()) {
232  return NO_UNIT;
233  }
234  // Verify that the target hex is still valid
235  if(!target_hex_.valid()) {
236  return INVALID_LOCATION;
237  }
238  // Verify that the target hex isn't empty
239  if(resources::gameboard->units().find(target_hex_) == resources::gameboard->units().end()){
240  return NO_TARGET;
241  }
242  // Verify that the attacking unit has attacks left
243  if(get_unit()->attacks_left() <= 0) {
244  return NO_ATTACK_LEFT;
245  }
246  // Verify that the attacker and target are enemies
247  if(!resources::gameboard->get_team(get_unit()->side()).is_enemy(resources::gameboard->units().find(target_hex_)->side())){
248  return NOT_AN_ENEMY;
249  }
250  //@todo: (maybe) verify that the target hex contains the same unit that before,
251  // comparing for example the unit ID
252 
253  return move::check_validity();
254 }
255 
257 {
258  config final_cfg = move::to_config();
259 
260  final_cfg["type"] = "attack";
261  final_cfg["weapon_choice_"] = weapon_choice_;
262 // final_cfg["attack_movement_cost_"] = attack_movement_cost_; //Unnecessary
263 // final_cfg["temp_movement_subtracted_"] = temp_movement_subtracted_; //Unnecessary
264 
265  config target_hex_cfg;
266  target_hex_cfg["x"]=target_hex_.wml_x();
267  target_hex_cfg["y"]=target_hex_.wml_y();
268  final_cfg.add_child("target_hex_", std::move(target_hex_cfg));
269 
270  return final_cfg;
271 }
272 
273 } // 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:172
config & add_child(config_key_type key)
Definition: config.cpp:440
bool invalidate(const map_location &loc)
Function to invalidate a specific tile for redrawing.
Definition: display.cpp:3087
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:1258
static display * get_singleton()
Returns the display object if a display object exists.
Definition: display.hpp:111
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:107
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:100
virtual void remove_temp_modifier(unit_map &unit_map)
Removes the result of this action from the specified unit map.
Definition: attack.cpp:183
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:111
virtual void redraw()
Redrawing function, called each time the action situation might have changed.
Definition: attack.cpp:222
virtual error check_validity() const
Check the validity of the action.
Definition: attack.cpp:228
virtual void accept(visitor &v)
Definition: attack.cpp:105
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:157
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:57
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:121
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:256
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:200
std::shared_ptr< attack > shared_from_this()
Definition: attack.hpp:65
virtual std::ostream & print(std::ostream &s) const
Definition: attack.cpp:50
void init()
Definition: attack.cpp:95
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:567
virtual void remove_temp_modifier(unit_map &unit_map)
Removes the result of this action from the specified unit map.
Definition: move.cpp:373
virtual unit_ptr get_unit() const
Return the unit targeted by this action.
Definition: move.cpp:289
virtual error check_validity() const
Check the validity of the action.
Definition: move.cpp:440
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:58
virtual map_location get_dest_hex() const
Definition: move.cpp:304
virtual config to_config() const
Constructs and returns a config object representing this object.
Definition: move.cpp:506
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:206
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:335
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
Definitions for the interface to Wesnoth Markup Language (WML).
Drawing functions, for drawing things on the screen.
drawing_layer
@ footsteps
Footsteps showing path from unit to mouse.
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:1000
void set_attacks(int left)
Sets the number of attacks this unit has left this turn.
Definition: unit.hpp:1021
void set_movement(int moves, bool unit_action=false)
Set this unit's remaining movement to moves.
Definition: unit.cpp:1256
int movement_left() const
Gets how far a unit can move, considering the incapacitated flag.
Definition: unit.hpp:1329
bool tiles_adjacent(const map_location &a, const map_location &b)
Function which tells if two locations are adjacent.
Definition: location.cpp:507
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:166
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:920
game_board * gameboard
Definition: resources.cpp:20
play_controller * controller
Definition: resources.cpp:21
std::size_t size(std::string_view str)
Length in characters of a UTF-8 string.
Definition: unicode.cpp:85
auto * find(Container &container, const Value &value)
Convenience wrapper for using find on a container without needing to comare to end()
Definition: general.hpp:140
Definition: display.hpp:45
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
std::ostream & operator<<(std::ostream &s, const action_ptr &action)
Definition: action.cpp:34
Encapsulates the map of the game.
Definition: location.hpp:45
static std::string write_direction(direction dir)
Definition: location.cpp:154
bool valid() const
Definition: location.hpp:110
int wml_y() const
Definition: location.hpp:184
int wml_x() const
Definition: location.hpp:183
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