Some cleanup of attack_type usage for enable_shared_from_this safety

- Call shared_from_this() instead of taking the address
- Don't use raw pointers to attack_type
- Change some cases of attack_type objects that weren't owned by a shared_ptr
  (either owned by another object or allocated directly on the stack)

List of files that currently call attack_type constructors:
- game_events/conditional_wml.cpp
- gui/dialogs/unit_attack.cpp
- scripting/lua_unit_attacks.cpp
- units/types.cpp
- units/unit.cpp

Each of these has been individually considered and made safe for use with
enable_shared_from_this. (Most of them already were safe.)
This commit is contained in:
Celtic Minstrel 2017-04-11 17:13:45 -04:00
parent 2ca105e146
commit fcc0da5bd4
19 changed files with 108 additions and 104 deletions

View file

@ -67,7 +67,7 @@ static lg::log_domain log_config("config");
battle_context_unit_stats::battle_context_unit_stats(const unit &u,
const map_location& u_loc, int u_attack_num, bool attacking,
const unit &opp, const map_location& opp_loc,
const attack_type *opp_weapon, const unit_map& units) :
const_attack_ptr opp_weapon, const unit_map& units) :
weapon(nullptr),
attack_num(u_attack_num),
is_attacker(attacking),
@ -100,7 +100,7 @@ battle_context_unit_stats::battle_context_unit_stats(const unit &u,
{
// Get the current state of the unit.
if (attack_num >= 0) {
weapon = &u.attacks()[attack_num];
weapon = u.attacks()[attack_num].shared_from_this();
}
if(u.hitpoints() < 0) {
LOG_CF << "Unit with " << u.hitpoints() << " hitpoints found, set to 0 for damage calculations\n";
@ -204,9 +204,9 @@ battle_context_unit_stats::battle_context_unit_stats(const unit &u,
}
battle_context_unit_stats::battle_context_unit_stats(const unit_type* u_type,
const attack_type* att_weapon, bool attacking,
const_attack_ptr att_weapon, bool attacking,
const unit_type* opp_type,
const attack_type* opp_weapon,
const_attack_ptr opp_weapon,
unsigned int opp_terrain_defense,
int lawful_bonus) :
weapon(att_weapon),
@ -332,7 +332,7 @@ battle_context::battle_context(const unit_map& units,
const unit &defender = *units.find(defender_loc);
const double harm_weight = 1.0 - aggression;
if (attacker_weapon == -1 && attacker.attacks().size() == 1 && attacker.attacks()[0].attack_weight() > 0 && !(&attacker.attacks()[0])->get_special_bool("disable", true))
if (attacker_weapon == -1 && attacker.attacks().size() == 1 && attacker.attacks()[0].attack_weight() > 0 && !attacker.attacks()[0].get_special_bool("disable", true))
attacker_weapon = 0;
if (attacker_weapon == -1) {
@ -346,17 +346,17 @@ battle_context::battle_context(const unit_map& units,
// If those didn't have to generate statistics, do so now.
if (!attacker_stats_) {
const attack_type *adef = nullptr;
const attack_type *ddef = nullptr;
const_attack_ptr adef = nullptr;
const_attack_ptr ddef = nullptr;
if (attacker_weapon >= 0) {
VALIDATE(attacker_weapon < static_cast<int>(attacker.attacks().size()),
_("An invalid attacker weapon got selected."));
adef = &attacker.attacks()[attacker_weapon];
adef = attacker.attacks()[attacker_weapon].shared_from_this();
}
if (defender_weapon >= 0) {
VALIDATE(defender_weapon < static_cast<int>(defender.attacks().size()),
_("An invalid defender weapon got selected."));
ddef = &defender.attacks()[defender_weapon];
ddef = defender.attacks()[defender_weapon].shared_from_this();
}
assert(!defender_stats_ && !attacker_combatant_ && !defender_combatant_);
attacker_stats_ = new battle_context_unit_stats(attacker, attacker_loc, attacker_weapon,
@ -493,7 +493,7 @@ int battle_context::choose_attacker_weapon(const unit &attacker,
if (choices.size() == 1) {
*defender_weapon = choose_defender_weapon(attacker, defender, choices[0], units,
attacker_loc, defender_loc, prev_def);
const attack_type *def_weapon = *defender_weapon >= 0 ? &defender.attacks()[*defender_weapon] : nullptr;
const_attack_ptr def_weapon = *defender_weapon >= 0 ? defender.attacks()[*defender_weapon].shared_from_this() : nullptr;
attacker_stats_ = new battle_context_unit_stats(attacker, attacker_loc, choices[0],
true, defender, defender_loc, def_weapon, units);
if (attacker_stats_->disable) {
@ -503,7 +503,7 @@ int battle_context::choose_attacker_weapon(const unit &attacker,
}
const attack_type &att = attacker.attacks()[choices[0]];
defender_stats_ = new battle_context_unit_stats(defender, defender_loc, *defender_weapon, false,
attacker, attacker_loc, &att, units);
attacker, attacker_loc, att.shared_from_this(), units);
return choices[0];
}
@ -517,9 +517,9 @@ int battle_context::choose_attacker_weapon(const unit &attacker,
attacker_loc, defender_loc, prev_def);
// If that didn't simulate, do so now.
if (!attacker_combatant_) {
const attack_type *def = nullptr;
const_attack_ptr def = nullptr;
if (def_weapon >= 0) {
def = &defender.attacks()[def_weapon];
def = defender.attacks()[def_weapon].shared_from_this();
}
attacker_stats_ = new battle_context_unit_stats(attacker, attacker_loc, choices[i],
true, defender, defender_loc, def, units);
@ -529,7 +529,7 @@ int battle_context::choose_attacker_weapon(const unit &attacker,
continue;
}
defender_stats_ = new battle_context_unit_stats(defender, defender_loc, def_weapon, false,
attacker, attacker_loc, &att, units);
attacker, attacker_loc, att.shared_from_this(), units);
attacker_combatant_ = new combatant(*attacker_stats_);
defender_combatant_ = new combatant(*defender_stats_, prev_def);
attacker_combatant_->fight(*defender_combatant_);
@ -599,7 +599,7 @@ int battle_context::choose_defender_weapon(const unit &attacker,
return -1;
if (choices.size() == 1) {
const battle_context_unit_stats def_stats(defender, defender_loc,
choices[0], false, attacker, attacker_loc, &att, units);
choices[0], false, attacker, attacker_loc, att.shared_from_this(), units);
return (def_stats.disable) ? -1 : choices[0];
}
@ -616,7 +616,7 @@ int battle_context::choose_defender_weapon(const unit &attacker,
const attack_type &def = defender.attacks()[choices[i]];
if (def.defense_weight() >= max_weight) {
const battle_context_unit_stats def_stats(defender, defender_loc,
choices[i], false, attacker, attacker_loc, &att, units);
choices[i], false, attacker, attacker_loc, att.shared_from_this(), units);
if (def_stats.disable) continue;
max_weight = def.defense_weight();
int rating = static_cast<int>(def_stats.num_blows * def_stats.damage *
@ -632,9 +632,9 @@ int battle_context::choose_defender_weapon(const unit &attacker,
for (i = 0; i < choices.size(); ++i) {
const attack_type &def = defender.attacks()[choices[i]];
battle_context_unit_stats *att_stats = new battle_context_unit_stats(attacker, attacker_loc, attacker_weapon,
true, defender, defender_loc, &def, units);
true, defender, defender_loc, def.shared_from_this(), units);
battle_context_unit_stats *def_stats = new battle_context_unit_stats(defender, defender_loc, choices[i], false,
attacker, attacker_loc, &att, units);
attacker, attacker_loc, att.shared_from_this(), units);
if (def_stats->disable) {
delete att_stats;
delete def_stats;
@ -878,11 +878,11 @@ namespace {
// Fix pointer to weapons
const_cast<battle_context_unit_stats*>(a_stats_)->weapon =
a_.valid() && a_.weapon_ >= 0
? &a_.get_unit().attacks()[a_.weapon_] : nullptr;
? a_.get_unit().attacks()[a_.weapon_].shared_from_this() : nullptr;
const_cast<battle_context_unit_stats*>(d_stats_)->weapon =
d_.valid() && d_.weapon_ >= 0
? &d_.get_unit().attacks()[d_.weapon_] : nullptr;
? d_.get_unit().attacks()[d_.weapon_].shared_from_this() : nullptr;
return;
}

View file

@ -48,7 +48,7 @@ inline unsigned swarm_blows(unsigned min_blows, unsigned max_blows, unsigned hp,
/** Structure describing the statistics of a unit involved in the battle. */
struct battle_context_unit_stats
{
const attack_type *weapon; /**< The weapon used by the unit to attack the opponent, or nullptr if there is none. */
const_attack_ptr weapon; /**< The weapon used by the unit to attack the opponent, or nullptr if there is none. */
int attack_num; /**< Index into unit->attacks() or -1 for none. */
bool is_attacker; /**< True if the unit is the attacker. */
bool is_poisoned; /**< True if the unit is poisoned at the beginning of the battle. */
@ -85,13 +85,13 @@ struct battle_context_unit_stats
battle_context_unit_stats(const unit &u, const map_location& u_loc,
int u_attack_num, bool attacking,
const unit &opp, const map_location& opp_loc,
const attack_type *opp_weapon,
const_attack_ptr opp_weapon,
const unit_map& units);
/** Used by AI for combat analysis */
battle_context_unit_stats(const unit_type* u_type,
const attack_type* att_weapon, bool attacking,
const unit_type* opp_type, const attack_type* opp_weapon,
const_attack_ptr att_weapon, bool attacking,
const unit_type* opp_type, const_attack_ptr opp_weapon,
unsigned int opp_terrain_defense,
int lawful_bonus = 0);

View file

@ -1056,7 +1056,7 @@ struct attack_simulation {
attack_simulation(const unit_type* attacker, const unit_type* defender,
double attacker_defense, double defender_defense,
const attack_type* att_weapon, const attack_type* def_weapon,
const_attack_ptr att_weapon, const_attack_ptr def_weapon,
int average_lawful_bonus) :
attacker_type(attacker),
defender_type(defender),
@ -1133,7 +1133,7 @@ void recruitment::simulate_attack(
std::shared_ptr<attack_simulation> simulation(new attack_simulation(
attacker, defender,
attacker_defense, defender_defense,
&att_weapon, &def_weapon, average_lawful_bonus_));
att_weapon.shared_from_this(), def_weapon.shared_from_this(), average_lawful_bonus_));
if (!best_def_response || simulation->better_result(best_def_response.get(), true)) {
best_def_response = simulation;
}
@ -1144,7 +1144,7 @@ void recruitment::simulate_attack(
best_def_response.reset(new attack_simulation(
attacker, defender,
attacker_defense, defender_defense,
&att_weapon, nullptr, average_lawful_bonus_));
att_weapon.shared_from_this(), nullptr, average_lawful_bonus_));
}
if (!best_att_attack || best_def_response->better_result(best_att_attack.get(), false)) {
best_att_attack = best_def_response;

View file

@ -66,33 +66,33 @@ void location_callable::serialize_to_string(std::string& str) const
variant attack_type_callable::get_value(const std::string& key) const
{
if(key == "id" || key == "name") {
return variant(att_.id());
return variant(att_->id());
} else if(key == "description") {
return variant(att_.name());
return variant(att_->name());
} else if(key == "type") {
return variant(att_.type());
return variant(att_->type());
} else if(key == "icon") {
return variant(att_.icon());
return variant(att_->icon());
} else if(key == "range") {
return variant(att_.range());
return variant(att_->range());
} else if(key == "damage") {
return variant(att_.damage());
return variant(att_->damage());
} else if(key == "number_of_attacks" || key == "number" || key == "num_attacks" || key == "attacks") {
return variant(att_.num_attacks());
return variant(att_->num_attacks());
} else if(key == "attack_weight") {
return variant(att_.attack_weight(), variant::DECIMAL_VARIANT);
return variant(att_->attack_weight(), variant::DECIMAL_VARIANT);
} else if(key == "defense_weight") {
return variant(att_.defense_weight(), variant::DECIMAL_VARIANT);
return variant(att_->defense_weight(), variant::DECIMAL_VARIANT);
} else if(key == "accuracy") {
return variant(att_.accuracy());
return variant(att_->accuracy());
} else if(key == "parry") {
return variant(att_.parry());
return variant(att_->parry());
} else if(key == "movement_used") {
return variant(att_.movement_used());
return variant(att_->movement_used());
} else if(key == "specials" || key == "special") {
std::vector<variant> res;
for(const auto& special : att_.specials().all_children_range()) {
for(const auto& special : att_->specials().all_children_range()) {
if(!special.cfg["id"].empty()) {
res.emplace_back(special.cfg["id"].str());
}
@ -127,27 +127,27 @@ int attack_type_callable::do_compare(const formula_callable* callable) const
return formula_callable::do_compare(callable);
}
if(att_.damage() != att_callable->att_.damage()) {
return att_.damage() - att_callable->att_.damage();
if(att_->damage() != att_callable->att_->damage()) {
return att_->damage() - att_callable->att_->damage();
}
if(att_.num_attacks() != att_callable->att_.num_attacks()) {
return att_.num_attacks() - att_callable->att_.num_attacks();
if(att_->num_attacks() != att_callable->att_->num_attacks()) {
return att_->num_attacks() - att_callable->att_->num_attacks();
}
if(att_.id() != att_callable->att_.id()) {
return att_.id().compare(att_callable->att_.id());
if(att_->id() != att_callable->att_->id()) {
return att_->id().compare(att_callable->att_->id());
}
if(att_.type() != att_callable->att_.type()) {
return att_.type().compare(att_callable->att_.type());
if(att_->type() != att_callable->att_->type()) {
return att_->type().compare(att_callable->att_->type());
}
if(att_.range() != att_callable->att_.range()) {
return att_.range().compare(att_callable->att_.range());
if(att_->range() != att_callable->att_->range()) {
return att_->range().compare(att_callable->att_->range());
}
return att_.weapon_specials().compare(att_callable->att_.weapon_specials());
return att_->weapon_specials().compare(att_callable->att_->weapon_specials());
}
variant unit_callable::get_value(const std::string& key) const

View file

@ -83,7 +83,7 @@ private:
class attack_type_callable : public formula_callable
{
public:
explicit attack_type_callable(const attack_type& attack) : att_(attack)
explicit attack_type_callable(const attack_type& attack) : att_(attack.shared_from_this())
{
type_ = ATTACK_TYPE_C;
}
@ -93,10 +93,10 @@ public:
int do_compare(const formula_callable* callable) const override;
const attack_type& get_attack_type() const { return att_; }
const attack_type& get_attack_type() const { return *att_; }
private:
const attack_type att_;
const_attack_ptr att_;
};
class unit_callable : public formula_callable

View file

@ -213,8 +213,10 @@ bool matches_special_filter(const config &cfg, const vconfig& filter)
// better to not execute the event (so the problem is more obvious)
return false;
}
const attack_type attack(cfg);
return attack.matches_filter(filter.get_parsed_config());
// Though it may seem wasteful to put this on the heap, it's necessary.
// matches_filter() could potentially call a WFL formula, which would call shared_from_this().
auto attack = std::make_shared<const attack_type>(cfg);
return attack->matches_filter(filter.get_parsed_config());
}
} // end namespace game_events

View file

@ -126,7 +126,7 @@ void attack_predictions::set_data(window& window, const combatant_data& attacker
ss.str("");
// Set specials context (for safety, it should not have changed normally).
const attack_type* weapon = attacker.stats_.weapon;
const_attack_ptr weapon = attacker.stats_.weapon;
weapon->set_specials_context(attacker.unit_.get_location(), defender.unit_.get_location(), attacker.stats_.is_attacker, defender.stats_.weapon);
// Get damage modifiers.

View file

@ -109,8 +109,9 @@ void unit_attack::pre_show(window& window)
listbox& weapon_list = find_widget<listbox>(&window, "weapon_list", false);
window.keyboard_capture(&weapon_list);
const config empty;
const attack_type no_weapon(empty);
// Possible TODO: If a "blank weapon" is generally useful, add it as a static member in attack_type.
static const config empty;
static const_attack_ptr no_weapon(new attack_type(empty));
for(const auto & weapon : weapons_) {
const battle_context_unit_stats& attacker = weapon.get_attacker_stats();
@ -119,7 +120,7 @@ void unit_attack::pre_show(window& window)
const attack_type& attacker_weapon =
*attacker.weapon;
const attack_type& defender_weapon = defender.weapon ?
*defender.weapon : no_weapon;
*defender.weapon : *no_weapon;
// Don't show if the atacker's weapon has at least one active "disable" special.
if(attacker_weapon.get_special_bool("disable")) {

View file

@ -434,7 +434,7 @@ static int impl_add_animation(lua_State* L)
lua_pop(L, 1);
}
anim.add_animation(&u, which, u.get_location(), dest, v1, bars, text, color, hits, primary.get(), secondary.get(), v2);
anim.add_animation(&u, which, u.get_location(), dest, v1, bars, text, color, hits, primary, secondary, v2);
return 0;
}

View file

@ -679,7 +679,7 @@ std::string attack_type::weapon_specials(bool only_active, bool is_backstab) con
void attack_type::set_specials_context(const map_location& unit_loc,
const map_location& other_loc,
bool attacking,
const attack_type *other_attack) const
const_attack_ptr other_attack) const
{
self_loc_ = unit_loc;
other_loc_ = other_loc;
@ -808,7 +808,7 @@ namespace { // Helpers for attack_type::special_active()
static bool special_unit_matches(const unit_map::const_iterator & un_it,
const unit_map::const_iterator & u2,
const map_location & loc,
const attack_type * weapon,
const_attack_ptr weapon,
const config & filter,
const bool for_listing,
const std::string & child_tag)
@ -909,11 +909,11 @@ bool attack_type::special_active(const config& special, AFFECTS whom,
unit_map::const_iterator & def = is_attacker_ ? other : self;
const map_location & att_loc = is_attacker_ ? self_loc_ : other_loc_;
const map_location & def_loc = is_attacker_ ? other_loc_ : self_loc_;
const attack_type * att_weapon = is_attacker_ ? this : other_attack_;
const attack_type * def_weapon = is_attacker_ ? other_attack_ : this;
const_attack_ptr att_weapon = is_attacker_ ? shared_from_this() : other_attack_;
const_attack_ptr def_weapon = is_attacker_ ? other_attack_ : shared_from_this();
// Filter the units involved.
if (!special_unit_matches(self, other, self_loc_, this, special, is_for_listing_, "filter_self"))
if (!special_unit_matches(self, other, self_loc_, shared_from_this(), special, is_for_listing_, "filter_self"))
return false;
if (!special_unit_matches(other, self, other_loc_, other_attack_, special, is_for_listing_, "filter_opponent"))
return false;

View file

@ -10,7 +10,7 @@
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
*/
#include "units/animation.hpp"
@ -374,8 +374,8 @@ unit_animation::unit_animation(const config& cfg,const std::string& frame_string
}
int unit_animation::matches(const display& disp, const map_location& loc, const map_location& second_loc,
const unit* my_unit, const std::string& event, const int value, hit_type hit, const attack_type* attack,
const attack_type* second_attack, int value2) const
const unit* my_unit, const std::string& event, const int value, hit_type hit, const_attack_ptr attack,
const_attack_ptr second_attack, int value2) const
{
int result = base_score_;
@ -1301,8 +1301,8 @@ void unit_animator::add_animation(const unit* animated_unit
, const std::string& text
, const color_t text_color
, const unit_animation::hit_type hit_type
, const attack_type* attack
, const attack_type* second_attack
, const_attack_ptr attack
, const_attack_ptr second_attack
, int value2)
{
if(!animated_unit) return;
@ -1355,8 +1355,8 @@ void unit_animator::replace_anim_if_invalid(const unit* animated_unit
, const std::string& text
, const color_t text_color
, const unit_animation::hit_type hit_type
, const attack_type* attack
, const attack_type* second_attack
, const_attack_ptr attack
, const_attack_ptr second_attack
, int value2)
{
if(!animated_unit) return;

View file

@ -10,7 +10,7 @@
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
*/
#ifndef UNIT_ANIMATION_H_INCLUDED
#define UNIT_ANIMATION_H_INCLUDED
@ -21,7 +21,6 @@
#include "units/ptr.hpp"
#include "utils/make_enum.hpp"
class attack_type;
class display;
class unit;
@ -43,7 +42,7 @@ public:
static void fill_initial_animations(std::vector<unit_animation>& animations, const config& cfg);
static void add_anims(std::vector<unit_animation>& animations, const config& cfg);
int matches(const display& disp, const map_location& loc, const map_location& second_loc, const unit* my_unit, const std::string& event = "", const int value = 0, hit_type hit = hit_type::INVALID, const attack_type* attack = nullptr, const attack_type* second_attack = nullptr, int value2 = 0) const;
int matches(const display& disp, const map_location& loc, const map_location& second_loc, const unit* my_unit, const std::string& event = "", const int value = 0, hit_type hit = hit_type::INVALID, const_attack_ptr attack = nullptr, const_attack_ptr second_attack = nullptr, int value2 = 0) const;
const unit_frame& get_last_frame() const
{
@ -208,8 +207,8 @@ public:
, const color_t text_color = {0,0,0}
, const unit_animation::hit_type hit_type =
unit_animation::hit_type::INVALID
, const attack_type* attack = nullptr
, const attack_type* second_attack = nullptr
, const_attack_ptr attack = nullptr
, const_attack_ptr second_attack = nullptr
, int value2 = 0);
void replace_anim_if_invalid(const unit* animated_unit
@ -221,8 +220,8 @@ public:
, const std::string& text = ""
, const color_t text_color = {0,0,0}
, const unit_animation::hit_type hit_type = unit_animation::hit_type::INVALID
, const attack_type* attack = nullptr
, const attack_type* second_attack = nullptr
, const_attack_ptr attack = nullptr
, const_attack_ptr second_attack = nullptr
, int value2 = 0);
void start_animations();
void pause_animation();

View file

@ -23,7 +23,7 @@
const unit_animation* unit_animation_component::choose_animation(const display& disp, const map_location& loc,const std::string& event,
const map_location& second_loc,const int value,const unit_animation::hit_type hit,
const attack_type* attack, const attack_type* second_attack, int swing_num)
const_attack_ptr attack, const_attack_ptr second_attack, int swing_num)
{
// Select one of the matching animations at random
std::vector<const unit_animation*> options;

View file

@ -64,7 +64,7 @@ public:
const map_location& second_loc = map_location::null_location(),
const int damage=0,
const unit_animation::hit_type hit_type = unit_animation::hit_type::INVALID,
const attack_type* attack=nullptr,const attack_type* second_attack = nullptr,
const_attack_ptr attack=nullptr,const_attack_ptr second_attack = nullptr,
int swing_num =0);
/** Sets the animation state to standing. */

View file

@ -71,10 +71,6 @@ attack_type::attack_type(const config& cfg) :
}
}
attack_type::~attack_type()
{
}
std::string attack_type::accuracy_parry_description() const
{
if(accuracy_ == 0 && parry_ == 0) {

View file

@ -26,6 +26,8 @@
#include <boost/smart_ptr/intrusive_ptr.hpp>
#include <boost/dynamic_bitset_fwd.hpp>
#include "units/ptr.hpp" // for attack_ptr
class unit_ability_list;
//the 'attack type' is the type of attack, how many times it strikes,
@ -35,8 +37,6 @@ class attack_type : public std::enable_shared_from_this<attack_type>
public:
explicit attack_type(const config& cfg);
/** Default implementation, but defined out-of-line for efficiency reasons. */
~attack_type();
const t_string& name() const { return description_; }
const std::string& id() const { return id_; }
const std::string& type() const { return type_; }
@ -74,7 +74,7 @@ public:
std::vector<std::pair<t_string, t_string> > special_tooltips(boost::dynamic_bitset<>* active_list = nullptr) const;
std::string weapon_specials(bool only_active=false, bool is_backstab=false) const;
void set_specials_context(const map_location& unit_loc, const map_location& other_loc,
bool attacking, const attack_type *other_attack) const;
bool attacking, const_attack_ptr other_attack) const;
void set_specials_context(const map_location& loc, bool attacking = true) const;
void set_specials_context_for_listing() const;
@ -108,7 +108,7 @@ private:
// considered active.
mutable map_location self_loc_, other_loc_;
mutable bool is_attacker_;
mutable const attack_type* other_attack_;
mutable const_attack_ptr other_attack_;
mutable bool is_for_listing_ = false;
t_string description_;
@ -128,8 +128,6 @@ private:
config specials_;
};
using attack_ptr = std::shared_ptr<attack_type>;
using const_attack_ptr = std::shared_ptr<const attack_type>;
using attack_list = std::vector<attack_ptr>;
using attack_itors = boost::iterator_range<boost::indirect_iterator<attack_list::iterator>>;
using const_attack_itors = boost::iterator_range<boost::indirect_iterator<attack_list::const_iterator>>;

View file

@ -20,6 +20,7 @@
#define UNIT_PTR_H_INCLUDED
#include <boost/intrusive_ptr.hpp>
#include <memory>
class unit;
@ -29,4 +30,11 @@ void intrusive_ptr_release(const unit *);
typedef boost::intrusive_ptr<unit> unit_ptr;
typedef boost::intrusive_ptr<const unit> unit_const_ptr;
// And attacks too!
class attack_type;
using attack_ptr = std::shared_ptr<attack_type>;
using const_attack_ptr = std::shared_ptr<const attack_type>;
#endif

View file

@ -498,7 +498,7 @@ void move_unit(const std::vector<map_location>& path, unit_ptr u,
void reset_helpers(const unit *attacker,const unit *defender);
void unit_draw_weapon(const map_location& loc, unit& attacker,
const attack_type* attack,const attack_type* secondary_attack, const map_location& defender_loc,unit* defender)
const_attack_ptr attack,const_attack_ptr secondary_attack, const map_location& defender_loc,unit* defender)
{
display* disp = display::get_singleton();
if(!disp ||disp->video().update_locked() || disp->video().faked() || disp->fogged(loc) || preferences::show_combat() == false) {
@ -516,7 +516,7 @@ void unit_draw_weapon(const map_location& loc, unit& attacker,
void unit_sheath_weapon(const map_location& primary_loc, unit* primary_unit,
const attack_type* primary_attack,const attack_type* secondary_attack, const map_location& secondary_loc,unit* secondary_unit)
const_attack_ptr primary_attack,const_attack_ptr secondary_attack, const map_location& secondary_loc,unit* secondary_unit)
{
display* disp = display::get_singleton();
if(!disp ||disp->video().update_locked() || disp->video().faked() || disp->fogged(primary_loc) || preferences::show_combat() == false) {
@ -546,7 +546,7 @@ void unit_sheath_weapon(const map_location& primary_loc, unit* primary_unit,
void unit_die(const map_location& loc, unit& loser,
const attack_type* attack,const attack_type* secondary_attack, const map_location& winner_loc,unit* winner)
const_attack_ptr attack,const_attack_ptr secondary_attack, const map_location& winner_loc,unit* winner)
{
display* disp = display::get_singleton();
if(!disp ||disp->video().update_locked() || disp->video().faked() || disp->fogged(loc) || preferences::show_combat() == false) {
@ -571,7 +571,7 @@ void unit_die(const map_location& loc, unit& loser,
void unit_attack(display * disp, game_board & board,
const map_location& a, const map_location& b, int damage,
const attack_type& attack, const attack_type* secondary_attack,
const attack_type& attack, const_attack_ptr secondary_attack,
int swing,const std::string& hit_text,int drain_amount,const std::string& att_text, const std::vector<std::string>* extra_hit_sounds)
{
if(!disp ||disp->video().update_locked() || disp->video().faked() ||
@ -618,12 +618,12 @@ void unit_attack(display * disp, game_board & board,
animator.add_animation(&attacker, "attack", att->get_location(),
def->get_location(), damage, true, text_2,
(drain_amount >= 0) ? color_t(0,255,0) : color_t(255,0,0),
hit_type, &attack, secondary_attack, swing);
hit_type, attack.shared_from_this(), secondary_attack, swing);
// note that we take an anim from the real unit, we'll use it later
const unit_animation *defender_anim = def->anim_comp().choose_animation(*disp,
def->get_location(), "defend", att->get_location(), damage,
hit_type, &attack, secondary_attack, swing);
hit_type, attack.shared_from_this(), secondary_attack, swing);
animator.add_animation(&defender, defender_anim, def->get_location(),
true, text , {255,0,0});
@ -635,7 +635,7 @@ void unit_attack(display * disp, game_board & board,
leader->set_facing(ability.second.get_relative_dir(a));
animator.add_animation(&*leader, "leading", ability.second,
att->get_location(), damage, true, "", {0,0,0},
hit_type, &attack, secondary_attack, swing);
hit_type, attack.shared_from_this(), secondary_attack, swing);
}
for (const unit_ability & ability : helpers) {
if(ability.second == a) continue;
@ -645,7 +645,7 @@ void unit_attack(display * disp, game_board & board,
helper->set_facing(ability.second.get_relative_dir(b));
animator.add_animation(&*helper, "resistance", ability.second,
def->get_location(), damage, true, "", {0,0,0},
hit_type, &attack, secondary_attack, swing);
hit_type, attack.shared_from_this(), secondary_attack, swing);
}

View file

@ -89,13 +89,13 @@ void move_unit(const std::vector<map_location>& path, unit_ptr u,
* Play a pre-fight animation
* First unit is the attacker, second unit the defender
*/
void unit_draw_weapon( const map_location& loc, unit& u, const attack_type* attack=nullptr, const attack_type*secondary_attack=nullptr,const map_location& defender_loc = map_location::null_location(), unit * defender=nullptr);
void unit_draw_weapon( const map_location& loc, unit& u, const_attack_ptr attack=nullptr, const_attack_ptr secondary_attack=nullptr,const map_location& defender_loc = map_location::null_location(), unit * defender=nullptr);
/**
* Play a post-fight animation
* Both unit can be set to null, only valid units will play their animation
*/
void unit_sheath_weapon( const map_location& loc, unit* u=nullptr, const attack_type* attack=nullptr, const attack_type*secondary_attack=nullptr,const map_location& defender_loc = map_location::null_location(), unit * defender=nullptr);
void unit_sheath_weapon( const map_location& loc, unit* u=nullptr, const_attack_ptr attack=nullptr, const_attack_ptr secondary_attack=nullptr,const map_location& defender_loc = map_location::null_location(), unit * defender=nullptr);
/**
* Show a unit fading out.
@ -103,7 +103,7 @@ void unit_sheath_weapon( const map_location& loc, unit* u=nullptr, const attack_
* Note: this only shows the effect, it doesn't actually kill the unit.
*/
void unit_die( const map_location& loc, unit& u,
const attack_type* attack=nullptr, const attack_type* secondary_attack=nullptr,
const_attack_ptr attack=nullptr, const_attack_ptr secondary_attack=nullptr,
const map_location& winner_loc=map_location::null_location(),
unit* winner=nullptr);
@ -119,7 +119,7 @@ void unit_sheath_weapon( const map_location& loc, unit* u=nullptr, const attack_
*/
void unit_attack(display * disp, game_board & board, //TODO: Would be nice if this could be purely a display function and defer damage dealing to its caller
const map_location& a, const map_location& b, int damage,
const attack_type& attack, const attack_type* secondary_attack,
const attack_type& attack, const_attack_ptr secondary_attack,
int swing, const std::string& hit_text, int drain_amount, const std::string& att_text, const std::vector<std::string>* extra_hit_sounds=nullptr);