The Battle for Wesnoth  1.17.0-dev
attack.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/attack.hpp"
21 
22 #include "whiteboard/visitor.hpp"
23 #include "whiteboard/utility.hpp"
24 
25 #include "arrow.hpp"
26 #include "config.hpp"
27 #include "fake_unit_ptr.hpp"
28 #include "game_board.hpp"
29 #include "play_controller.hpp"
30 #include "resources.hpp"
31 #include "units/unit.hpp"
32 #include "units/map.hpp"
33 
34 namespace wb
35 {
36 
37 std::ostream &operator<<(std::ostream &s, attack_ptr attack)
38 {
39  assert(attack);
40  return attack->print(s);
41 }
42 
43 std::ostream &operator<<(std::ostream &s, attack_const_ptr attack)
44 {
45  assert(attack);
46  return attack->print(s);
47 }
48 
49 std::ostream& attack::print(std::ostream& s) const
50 {
51  s << "Attack on (" << get_target_hex() << ") preceded by ";
52  move::print(s);
53  return s;
54 }
55 
56 attack::attack(std::size_t team_index, bool hidden, unit& u, const map_location& target_hex, int weapon_choice, const pathfind::marked_route& route,
57  arrow_ptr arrow, fake_unit_ptr fake_unit)
58  : move(team_index, hidden, u, route, arrow, std::move(fake_unit)),
59  target_hex_(target_hex),
60  weapon_choice_(weapon_choice),
61  attack_movement_cost_(u.attacks()[weapon_choice_].movement_used()),
63 {
64  this->init();
65 }
66 
67 attack::attack(const config& cfg, bool hidden)
68  : move(cfg,hidden)
69  , target_hex_(cfg.child("target_hex_")["x"],cfg.child("target_hex_")["y"], wml_loc())
70  , weapon_choice_(cfg["weapon_choice_"].to_int(-1)) //default value: -1
73 {
74  // Validate target_hex
76  throw action::ctor_err("attack: Invalid target_hex_");
77 
78  // Validate weapon_choice_
79  if(weapon_choice_ < 0 || weapon_choice_ >= static_cast<int>(get_unit()->attacks().size()))
80  throw action::ctor_err("attack: Invalid weapon_choice_");
81 
82  // Construct attack_movement_cost_
83  assert(get_unit());
84  attack_movement_cost_ = get_unit()->attacks()[weapon_choice_].movement_used();
85 
86  this->init();
87 }
88 
90 {
92 }
93 
95 {
96  invalidate();
97 }
98 
100 {
101  v.visit(shared_from_this());
102 }
103 
104 /* private */
106 {
108  {
109  //invalidate dest and target hex so attack indicator is properly cleared
112  }
113 }
114 
115 void attack::execute(bool& success, bool& complete)
116 {
117  if(!valid()) {
118  success = false;
119  //Setting complete to true signifies to side_actions to delete the planned action: nothing more to do with it.
120  complete = true;
121  return;
122  }
123 
124  LOG_WB << "Executing: " << shared_from_this() << "\n";
125 
126  if (route_->steps.size() >= 2)
127  {
128  bool m_success, m_complete;
129  move::execute(m_success,m_complete);
130  if(!m_success) {
131  //Move failed for some reason, so don't attack.
132  success = false;
133  complete = true;
134  return;
135  }
136  }
137 
139  complete = true;
140 
141  //check that attacking unit is still alive, if not, consider the attack a failure
143  if(!survivor.valid() || (!unit_id_.empty() && (survivor->id() != unit_id_)))
144  {
145  success = false;
146  }
147 
148  success = true;
149 }
150 
152 {
153  move::apply_temp_modifier(unit_map);
154  assert(get_unit());
155  unit& unit = *get_unit();
156  DBG_WB << unit.name() << " [" << unit.id()
157  << "] has " << unit.attacks_left() << " attacks, decreasing by one" << "\n";
158  assert(unit.attacks_left() > 0);
159  unit.set_attacks(unit.attacks_left() - 1);
160 
161  //Calculate movement to subtract
163  DBG_WB << "Attack: Changing movement points for unit " << unit.name() << " [" << unit.id()
164  << "] from " << unit.movement_left() << " to "
165  << unit.movement_left() - temp_movement_subtracted_ << ".\n";
167 
168  //Update status of fake unit (not undone by remove_temp_modifiers)
169  //@todo this contradicts the name "temp_modifiers"
170  if (fake_unit_) { //Attacks that are not attack-moves don't have fake units
171  fake_unit_->set_movement(unit.movement_left(), true);
172  fake_unit_->set_attacks(unit.attacks_left());
173  }
174 }
175 
177 {
178  assert(get_unit());
179  unit& unit = *get_unit();
180  DBG_WB << unit.name() << " [" << unit.id()
181  << "] has " << unit.attacks_left() << " attacks, increasing by one" << "\n";
182  unit.set_attacks(unit.attacks_left() + 1);
183  DBG_WB << "Attack: Changing movement points for unit " << unit.name() << " [" << unit.id()
184  << "] from " << unit.movement_left() << " to "
185  << unit.movement_left() + temp_movement_subtracted_ << ".\n";
188  move::remove_temp_modifier(unit_map);
189 }
190 
192 {
193  if (hex == get_dest_hex() || hex == target_hex_) //draw attack indicator
194  {
195  //@todo: replace this by either the use of transparency + LAYER_ATTACK_INDICATOR,
196  //or a dedicated layer
198 
199  //calculate direction (valid for both hexes)
200  std::string direction_text = map_location::write_direction(
201  get_dest_hex().get_relative_dir(target_hex_));
202 
203  if (hex == get_dest_hex()) //add symbol to attacker hex
204  {
207 
209  image::get_image("whiteboard/attack-indicator-src-" + direction_text + ".png", image::SCALED_TO_HEX));
210  }
211  else if (hex == target_hex_) //add symbol to defender hex
212  {
215 
217  image::get_image("whiteboard/attack-indicator-dst-" + direction_text + ".png", image::SCALED_TO_HEX));
218  }
219  }
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
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
map_location target_hex_
the target of the attack
Definition: attack.hpp:80
play_controller * controller
Definition: resources.cpp:22
surface get_image(const image::locator &i_locator, TYPE type)
Caches and returns an image.
Definition: picture.cpp:816
std::string unit_id_
Definition: move.hpp:111
int attacks_left() const
Gets the remaining number of attacks this unit can perform this turn.
Definition: unit.hpp:983
void set_movement(int moves, bool unit_action=false)
Set this unit&#39;s remaining movement to moves.
Definition: unit.cpp:1176
virtual void apply_temp_modifier(unit_map &unit_map)
Applies temporarily the result of this action to the specified unit map.
Definition: attack.cpp:151
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:115
Arrows destined to be drawn on the map.
unit_iterator end()
Definition: map.hpp:429
static display * get_singleton()
Returns the display object if a display object exists.
Definition: display.hpp:92
virtual const unit_map & units() const override
Definition: game_board.hpp:112
bool invalidate(const map_location &loc)
Function to invalidate a specific tile for redrawing.
Definition: display.cpp:3026
int weapon_choice_
Definition: attack.hpp:82
This class represents a single unit of a specific type.
Definition: unit.hpp:121
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:56
int attack_movement_cost_
Definition: attack.hpp:83
virtual void redraw()
Redrawing function, called each time the action situation might have changed.
Definition: attack.cpp:222
std::shared_ptr< attack > attack_ptr
Definition: typedefs.hpp:70
virtual std::ostream & print(std::ostream &s) const
Definition: move.cpp:59
int wml_x() const
Definition: location.hpp:153
virtual void visit(move_ptr move)=0
STL namespace.
int temp_movement_subtracted_
Definition: attack.hpp:84
std::shared_ptr< attack const > attack_const_ptr
Definition: typedefs.hpp:71
virtual void remove_temp_modifier(unit_map &unit_map)
Removes the result of this action from the specified unit map.
Definition: move.cpp:374
std::shared_ptr< attack > shared_from_this()
Definition: attack.hpp:65
drawing_layer
The layers to render something on.
Definition: display.hpp:824
Definitions for the interface to Wesnoth Markup Language (WML).
virtual error check_validity() const
Check the validity of the action.
Definition: attack.cpp:228
std::size_t team_index() const
Returns the index of the team that owns this action.
Definition: action.hpp:84
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:207
virtual ~attack()
Definition: attack.cpp:94
bool valid()
Returns whether this action is valid or not.
Definition: action.hpp:135
virtual void accept(visitor &v)
Definition: attack.cpp:99
std::size_t size(const std::string &str)
Length in characters of a UTF-8 string.
Definition: unicode.cpp:87
const std::string & id() const
Gets this unit&#39;s id.
Definition: unit.hpp:371
Arrows destined to be drawn on the map.
Definition: arrow.hpp:30
virtual map_location get_dest_hex() const
Definition: move.cpp:305
error
Possible errors.
Definition: action.hpp:106
fake_unit_ptr fake_unit_
Definition: move.hpp:118
int wml_y() const
Definition: location.hpp:154
bool valid() const
Definition: location.hpp:89
game_board * gameboard
Definition: resources.cpp:21
virtual error check_validity() const
Check the validity of the action.
Definition: move.cpp:441
const t_string & name() const
Gets this unit&#39;s translatable display name.
Definition: unit.hpp:394
virtual unit_ptr get_unit() const
Return the unit targeted by this action.
Definition: move.cpp:290
Structure which holds a single route and marks for special events.
Definition: pathfind.hpp:141
virtual void apply_temp_modifier(unit_map &unit_map)
Applies temporarily the result of this action to the specified unit map.
Definition: move.cpp:336
void redraw()
Redrawing function, called each time the action situation might have changed.
Definition: move.cpp:568
virtual config to_config() const
Constructs and returns a config object representing this object.
Definition: attack.cpp:256
Encapsulates the map of the game.
Definition: location.hpp:38
unit_iterator find(std::size_t id)
Definition: map.cpp:310
virtual void remove_temp_modifier(unit_map &unit_map)
Removes the result of this action from the specified unit map.
Definition: attack.cpp:176
bool tiles_adjacent(const map_location &a, const map_location &b)
Function which tells if two locations are adjacent.
Definition: location.cpp:503
virtual config to_config() const
Constructs and returns a config object representing this object.
Definition: move.cpp:507
void set_attacks(int left)
Sets the number of attacks this unit has left this turn.
Definition: unit.hpp:1004
void attack_enemy(const map_location &attacker_loc, const map_location &defender_loc, int choice)
static map_location::DIRECTION s
int get_location_y(const map_location &loc) const
Definition: display.cpp:755
const map_location & get_target_hex() const
Definition: attack.hpp:59
#define LOG_WB
Definition: typedefs.hpp:27
config & add_child(config_key_type key)
Definition: config.cpp:514
std::shared_ptr< arrow > arrow_ptr
Definition: typedefs.hpp:60
void drawing_buffer_add(const drawing_layer layer, const map_location &loc, int x, int y, const surface &surf, const SDL_Rect &clip=SDL_Rect())
Add an item to the drawing buffer.
Definition: display.cpp:1209
int get_location_x(const map_location &loc) const
Functions to get the on-screen positions of hexes.
Definition: display.cpp:750
Image rescaled to fit into a hexagonal tile according to the zoom settings.
Definition: picture.hpp:238
events::mouse_handler & get_mouse_handler_base() override
Get a reference to a mouse handler member a derived class uses.
bool hidden() const
Definition: action.hpp:64
#define DBG_WB
Definition: typedefs.hpp:28
Container associating units to locations.
Definition: map.hpp:98
std::ostream & operator<<(std::ostream &s, action_ptr action)
Definition: action.cpp:34
virtual std::ostream & print(std::ostream &s) const
Definition: attack.cpp:49
visitor is an abstract interface : action.accept(visitor) calls visitor.visit(action) ...
std::unique_ptr< pathfind::marked_route > route_
Definition: move.hpp:112
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:61
bool valid() const
Definition: map.hpp:274
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:191
void invalidate()
invalidates the move-destination and attack-target hexes
Definition: attack.cpp:105
static std::string write_direction(DIRECTION dir)
Definition: location.cpp:141
Holds a temporary unit that can be drawn on the map without being placed in the unit_map.
int movement_left() const
Gets how far a unit can move, considering the incapacitated flag.
Definition: unit.hpp:1271
A planned move, represented on the map by an arrow and a ghosted unit in the destination hex...
Definition: move.hpp:35
Definition: display.hpp:49
Footsteps showing path from unit to mouse.
Definition: display.hpp:831
void init()
Definition: attack.cpp:89
Abstract base class for all the visitors (cf GoF Visitor Design Pattern) the whiteboard uses...
Definition: visitor.hpp:32