use shared_ptr for unit_ptr (#4985)

use shared_ptr for unit_ptr

This make the code a bit simpler, furthermore it
allows us to use weak_ptr to unit should we ever
need that.

Furthermore this adds a class shared_reference that wraps shared_ptr but can never be nullptr.
This commit is contained in:
gfgtdf 2020-08-07 14:30:40 +02:00 committed by GitHub
parent f33330de19
commit 6d73033445
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
23 changed files with 288 additions and 187 deletions

View file

@ -124,7 +124,7 @@ namespace
if (animate && !CVideo::get_singleton().update_locked()) {
unit_animator animator;
bool with_bars = true;
animator.add_animation(&*u, "levelout", u->get_location(), map_location(), 0, with_bars);
animator.add_animation(u.get_shared_ptr(), "levelout", u->get_location(), map_location(), 0, with_bars);
animator.start_animations();
animator.wait_for_end();
}
@ -144,7 +144,7 @@ namespace
if (animate && u != resources::gameboard->units().end() && !CVideo::get_singleton().update_locked()) {
unit_animator animator;
animator.add_animation(&*u, "levelin", u->get_location(), map_location(), 0, true);
animator.add_animation(u.get_shared_ptr(), "levelin", u->get_location(), map_location(), 0, true);
animator.start_animations();
animator.wait_for_end();
animator.set_all_standing();

View file

@ -72,19 +72,19 @@ static lg::log_domain log_config("config");
// BATTLE CONTEXT UNIT STATS
// ==================================================================================
battle_context_unit_stats::battle_context_unit_stats(const unit& u,
battle_context_unit_stats::battle_context_unit_stats(nonempty_unit_const_ptr up,
const map_location& u_loc,
int u_attack_num,
bool attacking,
const unit& opp,
nonempty_unit_const_ptr oppp,
const map_location& opp_loc,
const_attack_ptr opp_weapon,
const unit_map& units)
: weapon(nullptr)
, attack_num(u_attack_num)
, is_attacker(attacking)
, is_poisoned(u.get_state(unit::STATE_POISONED))
, is_slowed(u.get_state(unit::STATE_SLOWED))
, is_poisoned(up->get_state(unit::STATE_POISONED))
, is_slowed(up->get_state(unit::STATE_SLOWED))
, slows(false)
, drains(false)
, petrifies(false)
@ -94,12 +94,12 @@ battle_context_unit_stats::battle_context_unit_stats(const unit& u,
, swarm(false)
, firststrike(false)
, disable(false)
, experience(u.experience())
, max_experience(u.max_experience())
, level(u.level())
, experience(up->experience())
, max_experience(up->max_experience())
, level(up->level())
, rounds(1)
, hp(0)
, max_hp(u.max_hitpoints())
, max_hp(up->max_hitpoints())
, chance_to_hit(0)
, damage(0)
, slow_damage(0)
@ -110,6 +110,8 @@ battle_context_unit_stats::battle_context_unit_stats(const unit& u,
, swarm_max(0)
, plague_type()
{
const unit& u = *up;
const unit& opp = *oppp;
// Get the current state of the unit.
if(attack_num >= 0) {
weapon = u.attacks()[attack_num].shared_from_this();
@ -132,11 +134,11 @@ battle_context_unit_stats::battle_context_unit_stats(const unit& u,
}
// Get the weapon characteristics as appropriate.
auto ctx = weapon->specials_context(&u, &opp, u_loc, opp_loc, attacking, opp_weapon);
auto ctx = weapon->specials_context(up, oppp, u_loc, opp_loc, attacking, opp_weapon);
boost::optional<decltype(ctx)> opp_ctx;
if(opp_weapon) {
opp_ctx.emplace(opp_weapon->specials_context(&opp, &u, opp_loc, u_loc, !attacking, weapon));
opp_ctx.emplace(opp_weapon->specials_context(oppp, up, opp_loc, u_loc, !attacking, weapon));
}
slows = weapon->bool_ability("slow");
@ -365,10 +367,10 @@ battle_context_unit_stats::battle_context_unit_stats(const unit_type* u_type,
// ==================================================================================
battle_context::battle_context(
const unit& attacker,
nonempty_unit_const_ptr attacker,
const map_location& a_loc,
int a_wep_index,
const unit& defender,
nonempty_unit_const_ptr defender,
const map_location& d_loc,
int d_wep_index,
const unit_map& units)
@ -380,8 +382,8 @@ battle_context::battle_context(
size_t a_wep_uindex = static_cast<size_t>(a_wep_index);
size_t d_wep_uindex = static_cast<size_t>(d_wep_index);
const_attack_ptr a_wep(a_wep_uindex < attacker.attacks().size() ? attacker.attacks()[a_wep_index].shared_from_this() : nullptr);
const_attack_ptr d_wep(d_wep_uindex < defender.attacks().size() ? defender.attacks()[d_wep_index].shared_from_this() : nullptr);
const_attack_ptr a_wep(a_wep_uindex < attacker->attacks().size() ? attacker->attacks()[a_wep_index].shared_from_this() : nullptr);
const_attack_ptr d_wep(d_wep_uindex < defender->attacks().size() ? defender->attacks()[d_wep_index].shared_from_this() : nullptr);
attacker_stats_.reset(new battle_context_unit_stats(attacker, a_loc, a_wep_index, true , defender, d_loc, d_wep, units));
defender_stats_.reset(new battle_context_unit_stats(defender, d_loc, d_wep_index, false, attacker, a_loc, a_wep, units));
@ -407,30 +409,37 @@ battle_context::battle_context(const unit_map& units,
int defender_weapon,
double aggression,
const combatant* prev_def,
const unit* attacker_ptr,
const unit* defender_ptr)
unit_const_ptr attacker,
unit_const_ptr defender)
: attacker_stats_(nullptr)
, defender_stats_(nullptr)
, attacker_combatant_(nullptr)
, defender_combatant_(nullptr)
{
//TODO: maybe check before dereferencing units.find(attacker_loc),units.find(defender_loc) ?
const unit& attacker = attacker_ptr ? *attacker_ptr : *units.find(attacker_loc);
const unit& defender = defender_ptr ? *defender_ptr : *units.find(defender_loc);
if(!attacker) {
attacker = units.find(attacker_loc).get_shared_ptr();
}
if(!defender) {
defender = units.find(defender_loc).get_shared_ptr();
}
nonempty_unit_const_ptr n_attacker { attacker };
nonempty_unit_const_ptr n_defender { defender };
const double harm_weight = 1.0 - aggression;
if(attacker_weapon == -1) {
*this = choose_attacker_weapon(
attacker, defender, units, attacker_loc, defender_loc, harm_weight, prev_def
n_attacker, n_defender, units, attacker_loc, defender_loc, harm_weight, prev_def
);
}
else if(defender_weapon == -1) {
*this = choose_defender_weapon(
attacker, defender, attacker_weapon, units, attacker_loc, defender_loc, prev_def
n_attacker, n_defender, attacker_weapon, units, attacker_loc, defender_loc, prev_def
);
}
else {
*this = battle_context(attacker, attacker_loc, attacker_weapon, defender, defender_loc, defender_weapon, units);
*this = battle_context(n_attacker, attacker_loc, attacker_weapon, n_defender, defender_loc, defender_weapon, units);
}
assert(attacker_stats_);
@ -529,8 +538,8 @@ bool battle_context::better_combat(const combatant& us_a,
return them_a.average_hp() < them_b.average_hp();
}
battle_context battle_context::choose_attacker_weapon(const unit& attacker,
const unit& defender,
battle_context battle_context::choose_attacker_weapon(nonempty_unit_const_ptr attacker,
nonempty_unit_const_ptr defender,
const unit_map& units,
const map_location& attacker_loc,
const map_location& defender_loc,
@ -541,8 +550,8 @@ battle_context battle_context::choose_attacker_weapon(const unit& attacker,
std::vector<battle_context> choices;
// What options does attacker have?
for(size_t i = 0; i < attacker.attacks().size(); ++i) {
const attack_type& att = attacker.attacks()[i];
for(size_t i = 0; i < attacker->attacks().size(); ++i) {
const attack_type& att = attacker->attacks()[i];
if(att.attack_weight() <= 0) {
continue;
@ -583,8 +592,8 @@ battle_context battle_context::choose_attacker_weapon(const unit& attacker,
}
/** @todo FIXME: Hand previous defender unit in here. */
battle_context battle_context::choose_defender_weapon(const unit& attacker,
const unit& defender,
battle_context battle_context::choose_defender_weapon(nonempty_unit_const_ptr attacker,
nonempty_unit_const_ptr defender,
unsigned attacker_weapon,
const unit_map& units,
const map_location& attacker_loc,
@ -592,15 +601,15 @@ battle_context battle_context::choose_defender_weapon(const unit& attacker,
const combatant* prev_def)
{
log_scope2(log_attack, "choose_defender_weapon");
VALIDATE(attacker_weapon < attacker.attacks().size(), _("An invalid attacker weapon got selected."));
VALIDATE(attacker_weapon < attacker->attacks().size(), _("An invalid attacker weapon got selected."));
const attack_type& att = attacker.attacks()[attacker_weapon];
const attack_type& att = attacker->attacks()[attacker_weapon];
auto no_weapon = [&]() { return battle_context(attacker, attacker_loc, attacker_weapon, defender, defender_loc, -1, units); };
std::vector<battle_context> choices;
// What options does defender have?
for(size_t i = 0; i < defender.attacks().size(); ++i) {
const attack_type& def = defender.attacks()[i];
for(size_t i = 0; i < defender->attacks().size(); ++i) {
const attack_type& def = defender->attacks()[i];
if(def.range() != att.range() || def.defense_weight() <= 0) {
//no need to calculate the battle_context here.
continue;
@ -636,7 +645,7 @@ battle_context battle_context::choose_defender_weapon(const unit& attacker,
double max_weight = 0.0;
for(const auto& choice : choices) {
const attack_type& def = defender.attacks()[choice.defender_stats_->attack_num];
const attack_type& def = defender->attacks()[choice.defender_stats_->attack_num];
if(def.defense_weight() >= max_weight) {
const battle_context_unit_stats& def_stats = *choice.defender_stats_;
@ -655,7 +664,7 @@ battle_context battle_context::choose_defender_weapon(const unit& attacker,
battle_context* best_choice = nullptr;
// Multiple options: simulate them, save best.
for(auto& choice : choices) {
const attack_type& def = defender.attacks()[choice.defender_stats_->attack_num];
const attack_type& def = defender->attacks()[choice.defender_stats_->attack_num];
choice.simulate(prev_def);
@ -744,6 +753,7 @@ private:
unit_info(const map_location& loc, int weapon, unit_map& units);
unit& get_unit();
unit_ptr get_unit_ptr();
bool valid();
std::string dump();
@ -807,6 +817,15 @@ unit& attack::unit_info::get_unit()
return *i;
}
unit_ptr attack::unit_info::get_unit_ptr()
{
unit_map::iterator i = units_.find(loc_);
if(i.valid() && i->underlying_id() == id_) {
return i.get_shared_ptr();
}
return unit_ptr();
}
bool attack::unit_info::valid()
{
unit_map::iterator i = units_.find(loc_);
@ -1261,7 +1280,7 @@ void attack::unit_killed(unit_info& attacker,
attacker_stats->weapon,
defender_stats->weapon,
attacker.loc_,
&attacker.get_unit()
attacker.get_unit_ptr()
);
}
@ -1400,7 +1419,7 @@ void attack::perform()
<< (defender_strikes_first ? " defender first-strike" : "") << "\n";
// Play the pre-fight animation
unit_display::unit_draw_weapon(a_.loc_, a_.get_unit(), a_stats_->weapon, d_stats_->weapon, d_.loc_, &d_.get_unit());
unit_display::unit_draw_weapon(a_.loc_, a_.get_unit(), a_stats_->weapon, d_stats_->weapon, d_.loc_, d_.get_unit_ptr());
for(;;) {
DBG_NG << "start of attack loop...\n";
@ -1464,8 +1483,8 @@ void attack::perform()
u.set_experience(u.experience() + d_.xp_);
}
unit_display::unit_sheath_weapon(a_.loc_, a_.valid() ? &a_.get_unit() : nullptr, a_stats_->weapon, d_stats_->weapon,
d_.loc_, d_.valid() ? &d_.get_unit() : nullptr);
unit_display::unit_sheath_weapon(a_.loc_, a_.get_unit_ptr(), a_stats_->weapon, d_stats_->weapon,
d_.loc_, d_.get_unit_ptr());
if(update_display_) {
game_display::get_singleton()->invalidate_unit();

View file

@ -24,6 +24,7 @@
#include "ai/lua/aspect_advancements.hpp"
#include "attack_prediction.hpp"
#include "units/alignment.hpp"
#include "units/ptr.hpp"
#include <vector>
@ -82,11 +83,11 @@ struct battle_context_unit_stats
std::string plague_type; /**< The plague type used by the attack, if any. */
battle_context_unit_stats(const unit& u,
battle_context_unit_stats(nonempty_unit_const_ptr u,
const map_location& u_loc,
int u_attack_num,
bool attacking,
const unit& opp,
nonempty_unit_const_ptr opp,
const map_location& opp_loc,
const_attack_ptr opp_weapon,
const unit_map& units);
@ -185,8 +186,8 @@ public:
int defender_weapon = -1,
double aggression = 0.0,
const combatant* prev_def = nullptr,
const unit* attacker_ptr = nullptr,
const unit* defender_ptr = nullptr);
unit_const_ptr attacker_ptr = unit_const_ptr(),
unit_const_ptr defender_ptr = unit_const_ptr());
/** Used by the AI which caches battle_context_unit_stats */
battle_context(const battle_context_unit_stats& att, const battle_context_unit_stats& def);
@ -225,24 +226,24 @@ public:
void simulate(const combatant* prev_def);
private:
battle_context(
const unit& attacker,
nonempty_unit_const_ptr attacker,
const map_location& attacker_loc,
int attacker_weapon,
const unit& defender,
nonempty_unit_const_ptr defender,
const map_location& defender_loc,
int defender_weapon,
const unit_map& units);
static battle_context choose_attacker_weapon(const unit& attacker,
const unit& defender,
static battle_context choose_attacker_weapon(nonempty_unit_const_ptr attacker,
nonempty_unit_const_ptr defender,
const unit_map& units,
const map_location& attacker_loc,
const map_location& defender_loc,
double harm_weight,
const combatant* prev_def);
static battle_context choose_defender_weapon(const unit& attacker,
const unit& defender,
static battle_context choose_defender_weapon(nonempty_unit_const_ptr attacker,
nonempty_unit_const_ptr defender,
unsigned attacker_weapon,
const unit_map& units,
const map_location& attacker_loc,

View file

@ -162,7 +162,7 @@ attack_callable::attack_callable(const map_location& move_from,
const map_location& src, const map_location& dst, int weapon)
: move_from_(move_from), src_(src), dst_(dst),
bc_(resources::gameboard->units(), src, dst, weapon, -1, 1.0, nullptr,
&*resources::gameboard->units().find(move_from))
resources::gameboard->units().find(move_from).get_shared_ptr())
{
type_ = ATTACK_C;
}

View file

@ -617,7 +617,7 @@ DEFINE_WFL_FUNCTION(calculate_outcome, 3, 4)
}
battle_context bc(units, args()[1]->evaluate(variables, add_debug_info(fdb, 1, "calculate_outcome:attacker_attack_location")).convert_to<location_callable>()->loc(),
defender_location, weapon, -1, 1.0, nullptr, &*units.find(attacker_location));
defender_location, weapon, -1, 1.0, nullptr, units.find(attacker_location).get_shared_ptr());
std::vector<double> hp_dist = bc.get_attacker_combatant().hp_dist;
std::vector<double>::iterator it = hp_dist.begin();
int i = 0;

View file

@ -61,6 +61,16 @@ const unit * display_context::get_visible_unit(const map_location & loc, const t
return &*u;
}
unit_const_ptr display_context::get_visible_unit_shared_ptr(const map_location & loc, const team &current_team, bool see_all) const
{
if (!map().on_board(loc)) return nullptr;
const unit_map::const_iterator u = units().find(loc);
if (!u.valid() || !u->is_visible_to_team(current_team, see_all)) {
return unit_const_ptr();
}
return u.get_shared_ptr();
}
/**
* Will return true iff the unit @a u has any possible moves
* it can do (including attacking etc).

View file

@ -23,6 +23,7 @@
#include <string>
#include <vector>
#include "units/ptr.hpp"
class team;
class gamemap;
@ -60,6 +61,7 @@ public:
// Needed for reports
const unit * get_visible_unit(const map_location &loc, const team &current_team, bool see_all = false) const;
unit_const_ptr get_visible_unit_shared_ptr(const map_location &loc, const team &current_team, bool see_all = false) const;
// From actions:: namespace

View file

@ -48,7 +48,7 @@ const unsigned int attack_predictions::graph_width = 270;
const unsigned int attack_predictions::graph_height = 170;
const unsigned int attack_predictions::graph_max_rows = 10;
attack_predictions::attack_predictions(battle_context& bc, const unit& attacker, const unit& defender)
attack_predictions::attack_predictions(battle_context& bc, unit_const_ptr attacker, unit_const_ptr defender)
: attacker_data_(attacker, bc.get_attacker_combatant(), bc.get_attacker_stats())
, defender_data_(defender, bc.get_defender_combatant(), bc.get_defender_stats())
{
@ -127,11 +127,11 @@ void attack_predictions::set_data(window& window, const combatant_data& attacker
// Set specials context (for safety, it should not have changed normally).
const_attack_ptr weapon = attacker.stats_.weapon, opp_weapon = defender.stats_.weapon;
auto ctx = weapon->specials_context(&attacker.unit_, &defender.unit_, attacker.unit_.get_location(), defender.unit_.get_location(), attacker.stats_.is_attacker, opp_weapon);
auto ctx = weapon->specials_context(attacker.unit_, defender.unit_, attacker.unit_->get_location(), defender.unit_->get_location(), attacker.stats_.is_attacker, opp_weapon);
boost::optional<decltype(ctx)> opp_ctx;
if(opp_weapon) {
opp_ctx.emplace(opp_weapon->specials_context(&defender.unit_, &attacker.unit_, defender.unit_.get_location(), attacker.unit_.get_location(), defender.stats_.is_attacker, weapon));
opp_ctx.emplace(opp_weapon->specials_context(defender.unit_, attacker.unit_, defender.unit_->get_location(), attacker.unit_->get_location(), defender.stats_.is_attacker, weapon));
}
// Get damage modifiers.
@ -187,7 +187,7 @@ void attack_predictions::set_data(window& window, const combatant_data& attacker
ss.str("");
// Resistance modifier.
const int resistance_modifier = defender.unit_.damage_from(*weapon, !attacker.stats_.is_attacker, defender.unit_.get_location(), opp_weapon);
const int resistance_modifier = defender.unit_->damage_from(*weapon, !attacker.stats_.is_attacker, defender.unit_->get_location(), opp_weapon);
if(resistance_modifier != 100) {
if(attacker.stats_.is_attacker) {
if(resistance_modifier < 100) {
@ -218,7 +218,7 @@ void attack_predictions::set_data(window& window, const combatant_data& attacker
// TODO: color format the modifiers
// Time of day modifier.
const unit& u = attacker.unit_;
const unit& u = *attacker.unit_;
const int tod_modifier = combat_modifier(resources::gameboard->units(), resources::gameboard->map(),
u.get_location(), u.alignment(), u.is_fearless());
@ -230,7 +230,7 @@ void attack_predictions::set_data(window& window, const combatant_data& attacker
}
// Leadership bonus.
const int leadership_bonus = under_leadership(attacker.unit_, attacker.unit_.get_location(), weapon, opp_weapon);
const int leadership_bonus = under_leadership(*attacker.unit_, attacker.unit_->get_location(), weapon, opp_weapon);
if(leadership_bonus != 0) {
set_label_helper("leadership_modifier", utils::signed_percent(leadership_bonus));

View file

@ -16,7 +16,7 @@
#include "actions/attack.hpp"
#include "gui/dialogs/modal_dialog.hpp"
#include "units/map.hpp"
#include "units/ptr.hpp"
class battle_context;
@ -36,7 +36,7 @@ using hp_probability_vector = std::vector<hp_probability_t>;
class attack_predictions : public modal_dialog
{
public:
attack_predictions(battle_context& bc, const unit& attacker, const unit& defender);
attack_predictions(battle_context& bc, unit_const_ptr attacker, unit_const_ptr defender);
DEFINE_SIMPLE_DISPLAY_WRAPPER(attack_predictions)
@ -49,7 +49,7 @@ private:
struct combatant_data
{
combatant_data(const unit& unit, const combatant& combatant, const battle_context_unit_stats& stats)
combatant_data(unit_const_ptr unit, const combatant& combatant, const battle_context_unit_stats& stats)
: stats_(stats)
, combatant_(combatant)
, unit_(unit)
@ -57,7 +57,8 @@ private:
const battle_context_unit_stats& stats_;
const combatant& combatant_;
const unit& unit_;
/// never null
unit_const_ptr unit_;
};
void set_data(window& window, const combatant_data& attacker, const combatant_data& defender);

View file

@ -84,7 +84,7 @@ unit_attack::unit_attack(const unit_map::iterator& attacker_itor,
void unit_attack::damage_calc_callback(window& window)
{
const std::size_t index = find_widget<listbox>(&window, "weapon_list", false).get_selected_row();
attack_predictions::display(weapons_[index], *attacker_itor_, *defender_itor_);
attack_predictions::display(weapons_[index], attacker_itor_.get_shared_ptr(), defender_itor_.get_shared_ptr());
}
void unit_attack::pre_show(window& window)

View file

@ -141,6 +141,13 @@ static const unit *get_selected_unit(reports::context & rc)
rc.screen().show_everything());
}
static unit_const_ptr get_selected_unit_ptr(reports::context & rc)
{
return rc.dc().get_visible_unit_shared_ptr(rc.screen().selected_hex(),
rc.teams()[rc.screen().viewing_team()],
rc.screen().show_everything());
}
static config gray_inactive(reports::context & rc, const std::string &str, const std::string& tooltip = "")
{
if ( rc.screen().viewing_side() == rc.screen().playing_side() )
@ -741,7 +748,7 @@ static int attack_info(reports::context & rc, const attack_type &at, config &res
};
{
auto ctx = at.specials_context(unit_const_ptr(&u), hex, u.side() == rc.screen().playing_side());
auto ctx = at.specials_context(u.shared_from_this(), hex, u.side() == rc.screen().playing_side());
int base_damage = at.damage();
int specials_damage = at.modified_damage(false);
int damage_multiplier = 100;
@ -923,7 +930,7 @@ static int attack_info(reports::context & rc, const attack_type &at, config &res
//If we have a second unit, do the 2-unit specials_context
bool attacking = (u.side() == rc.screen().playing_side());
auto ctx = (sec_u == nullptr) ? at.specials_context_for_listing(attacking) :
at.specials_context(unit_const_ptr(&u), unit_const_ptr(sec_u), hex, sec_u->get_location(), attacking, sec_u_weapon);
at.specials_context(u.shared_from_this(), sec_u->shared_from_this(), hex, sec_u->get_location(), attacking, sec_u_weapon);
boost::dynamic_bitset<> active;
const std::vector<std::pair<t_string, t_string>> &specials = at.special_tooltips(&active);
@ -978,12 +985,12 @@ static std::string format_hp(unsigned hp)
return res.str();
}
static config unit_weapons(reports::context & rc, const unit *attacker, const map_location &attacker_pos, const unit *defender, bool show_attacker)
static config unit_weapons(reports::context & rc, unit_const_ptr attacker, const map_location &attacker_pos, const unit *defender, bool show_attacker)
{
if (!attacker || !defender) return config();
const unit* u = show_attacker ? attacker : defender;
const unit* sec_u = !show_attacker ? attacker : defender;
const unit* u = show_attacker ? attacker.get() : defender;
const unit* sec_u = !show_attacker ? attacker.get() : defender;
const map_location unit_loc = show_attacker ? attacker_pos : defender->get_location();
std::ostringstream str, tooltip;
@ -1140,11 +1147,11 @@ REPORT_GENERATOR(unit_weapons, rc)
}
REPORT_GENERATOR(highlighted_unit_weapons, rc)
{
const unit *u = get_selected_unit(rc);
unit_const_ptr u = get_selected_unit_ptr(rc);
const unit *sec_u = get_visible_unit(rc);
if (!u) return report_unit_weapons(rc);
if (!sec_u || u == sec_u) return unit_weapons(rc, sec_u, rc.screen().mouseover_hex());
if (!sec_u || u.get() == sec_u) return unit_weapons(rc, sec_u, rc.screen().mouseover_hex());
map_location highlighted_hex = rc.screen().displayed_unit_hex();
map_location attack_loc;
@ -1154,15 +1161,16 @@ REPORT_GENERATOR(highlighted_unit_weapons, rc)
if (!attack_loc.valid())
return unit_weapons(rc, sec_u, rc.screen().mouseover_hex());
//TODO: shouldn't this pass sec_u as secodn parameter ?
return unit_weapons(rc, u, attack_loc, sec_u, false);
}
REPORT_GENERATOR(selected_unit_weapons, rc)
{
const unit *u = get_selected_unit(rc);
unit_const_ptr u = get_selected_unit_ptr(rc);
const unit *sec_u = get_visible_unit(rc);
if (!u) return config();
if (!sec_u || u == sec_u) return unit_weapons(rc, u, u->get_location());
if (!sec_u || u.get() == sec_u) return unit_weapons(rc, u.get(), u->get_location());
map_location highlighted_hex = rc.screen().displayed_unit_hex();
map_location attack_loc;
@ -1170,7 +1178,7 @@ REPORT_GENERATOR(selected_unit_weapons, rc)
attack_loc = rc.mhb()->current_unit_attacks_from(highlighted_hex);
if (!attack_loc.valid())
return unit_weapons(rc, u, u->get_location());
return unit_weapons(rc, u.get(), u->get_location());
return unit_weapons(rc, u, attack_loc, sec_u, true);
}

View file

@ -341,7 +341,8 @@ static int impl_animator_collect(lua_State* L) {
static int impl_add_animation(lua_State* L)
{
unit_animator& anim = *static_cast<unit_animator*>(luaL_checkudata(L, 1, animatorKey));
unit& u = luaW_checkunit(L, 2);
unit_ptr up = luaW_checkunit_ptr(L, 2, false);
unit& u = *up;
std::string which = luaL_checkstring(L, 3);
using hit_type = unit_animation::hit_type;
@ -435,7 +436,7 @@ static int impl_add_animation(lua_State* L)
return luaW_type_error(L, 5, "table of options");
}
anim.add_animation(&u, which, u.get_location(), dest, v1, bars, text, color, hits, primary, secondary, v2);
anim.add_animation(up, which, u.get_location(), dest, v1, bars, text, color, hits, primary, secondary, v2);
return 0;
}
@ -2660,7 +2661,7 @@ int game_lua_kernel::intf_simulate_combat(lua_State *L)
}
battle_context context(units(), att->get_location(),
def->get_location(), att_w, def_w, 0.0, nullptr, att.get(), def.get());
def->get_location(), att_w, def_w, 0.0, nullptr, att, def);
luaW_pushsimdata(L, context.get_attacker_combatant());
luaW_pushsimdata(L, context.get_defender_combatant());
@ -3960,7 +3961,7 @@ int game_lua_kernel::intf_teleport(lua_State *L)
units().move(src_loc, vacant_dst);
unit::clear_status_caches();
u = &*units().find(vacant_dst);
u = units().find(vacant_dst).get_shared_ptr();
u->anim_comp().set_standing();
if ( clear_shroud ) {

View file

@ -903,7 +903,7 @@ attack_type::specials_context_t::specials_context_t(const attack_type& weapon, u
: parent(weapon.shared_from_this())
{
weapon.self_ = self;
weapon.other_ = nullptr;
weapon.other_ = unit_ptr();
weapon.self_loc_ = loc;
weapon.other_loc_ = map_location::null_location();
weapon.is_attacker_ = attacking;
@ -922,8 +922,8 @@ attack_type::specials_context_t::specials_context_t(const attack_type& weapon, c
: parent(weapon.shared_from_this())
{
UNUSED(self_type);
weapon.self_ = nullptr;
weapon.other_ = nullptr;
weapon.self_ = unit_ptr();
weapon.other_ = unit_ptr();
weapon.self_loc_ = loc;
weapon.other_loc_ = map_location::null_location();
weapon.is_attacker_ = attacking;
@ -941,8 +941,8 @@ attack_type::specials_context_t::specials_context_t(const attack_type& weapon, b
attack_type::specials_context_t::~specials_context_t()
{
if(was_moved) return;
parent->self_ = nullptr;
parent->other_ = nullptr;
parent->self_ = unit_ptr();
parent->other_ = unit_ptr();
parent->self_loc_ = map_location::null_location();
parent->other_loc_ = map_location::null_location();
parent->is_attacker_ = false;
@ -1217,13 +1217,13 @@ bool attack_type::special_active_impl(const_attack_ptr self_attack, const_attack
if(self == nullptr) {
unit_map::const_iterator it = units.find(self_loc);
if(it.valid()) {
self = it.get_shared_ptr().get();
self = it.get_shared_ptr();
}
}
if(other == nullptr) {
unit_map::const_iterator it = units.find(other_loc);
if(it.valid()) {
other = it.get_shared_ptr().get();
other = it.get_shared_ptr();
}
}

View file

@ -375,7 +375,7 @@ 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_ptr attack,
unit_const_ptr 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_;
@ -1291,7 +1291,7 @@ void unit_animation::particle::start_animation(int start_time)
last_frame_begin_time_ = get_begin_time() -1;
}
void unit_animator::add_animation(const unit* animated_unit
void unit_animator::add_animation(unit_const_ptr animated_unit
, const std::string& event
, const map_location &src
, const map_location &dst
@ -1309,12 +1309,12 @@ void unit_animator::add_animation(const unit* animated_unit
display* disp = display::get_singleton();
anim_elem tmp;
tmp.my_unit = unit_const_ptr(animated_unit);
tmp.my_unit = std::move(animated_unit);
tmp.text = text;
tmp.text_color = text_color;
tmp.src = src;
tmp.with_bars= with_bars;
tmp.animation = animated_unit->anim_comp().choose_animation(*disp, src, event, dst, value, hit_type, attack, second_attack, value2);
tmp.animation = tmp.my_unit->anim_comp().choose_animation(*disp, src, event, dst, value, hit_type, attack, second_attack, value2);
if(!tmp.animation) return;
@ -1322,7 +1322,7 @@ void unit_animator::add_animation(const unit* animated_unit
animated_units_.push_back(std::move(tmp));
}
void unit_animator::add_animation(const unit* animated_unit
void unit_animator::add_animation(unit_const_ptr animated_unit
, const unit_animation* anim
, const map_location &src
, bool with_bars
@ -1332,7 +1332,7 @@ void unit_animator::add_animation(const unit* animated_unit
if(!animated_unit) return;
anim_elem tmp;
tmp.my_unit = unit_const_ptr(animated_unit);
tmp.my_unit = std::move(animated_unit);
tmp.text = text;
tmp.text_color = text_color;
tmp.src = src;
@ -1345,7 +1345,7 @@ void unit_animator::add_animation(const unit* animated_unit
animated_units_.push_back(std::move(tmp));
}
void unit_animator::replace_anim_if_invalid(const unit* animated_unit
void unit_animator::replace_anim_if_invalid(unit_const_ptr animated_unit
, const std::string& event
, const map_location &src
, const map_location & dst
@ -1367,7 +1367,7 @@ void unit_animator::replace_anim_if_invalid(const unit* animated_unit
*disp, src, dst, animated_unit, event, value, hit_type, attack, second_attack, value2) > unit_animation::MATCH_FAIL)
{
anim_elem tmp;
tmp.my_unit = unit_const_ptr(animated_unit);
tmp.my_unit = animated_unit;
tmp.text = text;
tmp.text_color = text_color;
tmp.src = src;

View file

@ -43,7 +43,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_ptr attack = nullptr, const_attack_ptr second_attack = nullptr, int value2 = 0) const;
int matches(const display& disp, const map_location& loc, const map_location& second_loc, unit_const_ptr 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
{
@ -201,14 +201,14 @@ public:
start_time_(INT_MIN)
{}
void add_animation(const unit* animated_unit
void add_animation(unit_const_ptr animated_unit
, const unit_animation* animation
, const map_location& src = map_location::null_location()
, bool with_bars = false
, const std::string& text = ""
, const color_t text_color = {0,0,0});
void add_animation(const unit* animated_unit
void add_animation(unit_const_ptr animated_unit
, const std::string& event
, const map_location& src = map_location::null_location()
, const map_location& dst = map_location::null_location()
@ -222,7 +222,7 @@ public:
, const_attack_ptr second_attack = nullptr
, int value2 = 0);
void replace_anim_if_invalid(const unit* animated_unit
void replace_anim_if_invalid(unit_const_ptr animated_unit
, const std::string& event
, const map_location& src = map_location::null_location()
, const map_location& dst = map_location::null_location()
@ -257,7 +257,7 @@ private:
struct anim_elem
{
anim_elem()
: my_unit(0)
: my_unit()
, animation(0)
, text()
, text_color()

View file

@ -32,7 +32,7 @@ const unit_animation* unit_animation_component::choose_animation(const display&
std::vector<const unit_animation*> options;
int max_val = unit_animation::MATCH_FAIL;
for(const unit_animation& anim : animations_) {
int matching = anim.matches(disp,loc,second_loc,&u_,event,value,hit,attack,second_attack,swing_num);
int matching = anim.matches(disp,loc,second_loc,u_.shared_from_this(),event,value,hit,attack,second_attack,swing_num);
if(matching > unit_animation::MATCH_FAIL && matching == max_val) {
options.push_back(&anim);
} else if(matching > max_val) {

View file

@ -145,7 +145,7 @@ public:
typedef std::forward_iterator_tag iterator_category;
typedef int difference_type;
typedef typename iter_types::value_type value_type;
typedef boost::intrusive_ptr<value_type> pointer;
typedef std::shared_ptr<value_type> pointer;
typedef value_type& reference;
typedef typename iter_types::container_type container_type;
typedef typename iter_types::iterator_type iterator_type;
@ -388,14 +388,14 @@ public:
unit_ptr find_unit_ptr(const T& val)
{
auto res = find(val);
return res != end() ? res.get_shared_ptr() : unit_ptr();
return res != end() ? unit_ptr(res.get_shared_ptr()) : unit_ptr();
}
template<typename T>
unit_const_ptr find_unit_ptr(const T& val) const
{
auto res = find(val);
return res != end() ? res.get_shared_ptr() : unit_ptr();
return res != end() ? unit_const_ptr(res.get_shared_ptr()) : unit_const_ptr();
}
unit_iterator find_leader(int side);

View file

@ -20,14 +20,13 @@
#include <boost/intrusive_ptr.hpp>
#include <memory>
#include "utils/shared_reference.hpp"
class unit;
void intrusive_ptr_add_ref(const unit *);
void intrusive_ptr_release(const unit *);
typedef boost::intrusive_ptr<unit> unit_ptr;
typedef boost::intrusive_ptr<const unit> unit_const_ptr;
typedef utils::shared_reference<unit> nonempty_unit_ptr;
typedef utils::shared_reference<const unit> nonempty_unit_const_ptr;
typedef std::shared_ptr<unit> unit_ptr;
typedef std::shared_ptr<const unit> unit_const_ptr;
// And attacks too!

View file

@ -90,7 +90,7 @@ void teleport_unit_between(const map_location& a, const map_location& b, unit& t
else
disp.scroll_to_tile(a, game_display::ONSCREEN, true, false);
unit_animator animator;
animator.add_animation(&temp_unit,"pre_teleport",a);
animator.add_animation(temp_unit.shared_from_this(),"pre_teleport",a);
animator.start_animations();
animator.wait_for_end();
}
@ -104,7 +104,7 @@ void teleport_unit_between(const map_location& a, const map_location& b, unit& t
else
disp.scroll_to_tile(b, game_display::ONSCREEN, true, false);
unit_animator animator;
animator.add_animation(&temp_unit,"post_teleport",b);
animator.add_animation(temp_unit.shared_from_this(),"post_teleport",b);
animator.start_animations();
animator.wait_for_end();
}
@ -145,7 +145,7 @@ int move_unit_between(const map_location& a,
temp_unit->set_location(a);
disp.invalidate(a);
temp_unit->set_facing(a.get_relative_dir(b));
animator.replace_anim_if_invalid(temp_unit.get(),"movement",a,b,step_num,
animator.replace_anim_if_invalid(temp_unit,"movement",a,b,step_num,
false,"",{0,0,0},unit_animation::hit_type::INVALID,nullptr,nullptr,step_left);
animator.start_animations();
animator.pause_animation();
@ -293,7 +293,7 @@ void unit_mover::start(unit_ptr u)
}
// extra immobile movement animation for take-off
animator_.add_animation(temp_unit_ptr_.get(), "pre_movement", path_[0], path_[1]);
animator_.add_animation(temp_unit_ptr_.get_unit_ptr(), "pre_movement", path_[0], path_[1]);
animator_.start_animations();
animator_.wait_for_end();
animator_.clear();
@ -462,7 +462,7 @@ void unit_mover::finish(unit_ptr u, map_location::DIRECTION dir)
temp_unit_ptr_->set_facing(final_dir);
// Animation
animator_.add_animation(temp_unit_ptr_.get(), "post_movement", end_loc);
animator_.add_animation(temp_unit_ptr_.get_unit_ptr(), "post_movement", end_loc);
animator_.start_animations();
animator_.wait_for_end();
animator_.clear();
@ -522,7 +522,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_ptr attack,const_attack_ptr secondary_attack, const map_location& defender_loc,unit* defender)
const_attack_ptr attack,const_attack_ptr secondary_attack, const map_location& defender_loc, unit_ptr defender)
{
display* disp = display::get_singleton();
if(do_not_show_anims(disp) || disp->fogged(loc) || !preferences::show_combat()) {
@ -531,16 +531,18 @@ void unit_draw_weapon(const map_location& loc, unit& attacker,
unit_animator animator;
attacker.set_facing(loc.get_relative_dir(defender_loc));
defender->set_facing(defender_loc.get_relative_dir(loc));
animator.add_animation(&attacker,"draw_weapon",loc,defender_loc,0,true,"",{0,0,0},unit_animation::hit_type::HIT,attack,secondary_attack,0);
animator.add_animation(defender,"draw_weapon",defender_loc,loc,0,true,"",{0,0,0},unit_animation::hit_type::MISS,secondary_attack,attack,0);
animator.add_animation(attacker.shared_from_this(),"draw_weapon",loc,defender_loc,0,true,"",{0,0,0},unit_animation::hit_type::HIT,attack,secondary_attack,0);
if(defender) {
animator.add_animation(defender,"draw_weapon",defender_loc,loc,0,true,"",{0,0,0},unit_animation::hit_type::MISS,secondary_attack,attack,0);
}
animator.start_animations();
animator.wait_for_end();
}
void unit_sheath_weapon(const map_location& primary_loc, unit* primary_unit,
const_attack_ptr primary_attack,const_attack_ptr secondary_attack, const map_location& secondary_loc,unit* secondary_unit)
void unit_sheath_weapon(const map_location& primary_loc, unit_ptr primary_unit,
const_attack_ptr primary_attack,const_attack_ptr secondary_attack, const map_location& secondary_loc,unit_ptr secondary_unit)
{
display* disp = display::get_singleton();
if(do_not_show_anims(disp) || disp->fogged(primary_loc) || !preferences::show_combat()) {
@ -564,13 +566,13 @@ void unit_sheath_weapon(const map_location& primary_loc, unit* primary_unit,
if(secondary_unit) {
secondary_unit->anim_comp().set_standing();
}
reset_helpers(primary_unit,secondary_unit);
reset_helpers(&*primary_unit,&*secondary_unit);
}
void unit_die(const map_location& loc, unit& loser,
const_attack_ptr attack,const_attack_ptr secondary_attack, const map_location& winner_loc,unit* winner)
const_attack_ptr attack,const_attack_ptr secondary_attack, const map_location& winner_loc, unit_ptr winner)
{
display* disp = display::get_singleton();
if(do_not_show_anims(disp) || disp->fogged(loc) || !preferences::show_combat()) {
@ -578,14 +580,16 @@ void unit_die(const map_location& loc, unit& loser,
}
unit_animator animator;
// hide the hp/xp bars of the loser (useless and prevent bars around an erased unit)
animator.add_animation(&loser,"death",loc,winner_loc,0,false,"",{0,0,0},unit_animation::hit_type::KILL,attack,secondary_attack,0);
animator.add_animation(loser.shared_from_this(),"death",loc,winner_loc,0,false,"",{0,0,0},unit_animation::hit_type::KILL,attack,secondary_attack,0);
// but show the bars of the winner (avoid blinking and show its xp gain)
animator.add_animation(winner,"victory",winner_loc,loc,0,true,"",{0,0,0},
if(winner) {
animator.add_animation(winner,"victory",winner_loc,loc,0,true,"",{0,0,0},
unit_animation::hit_type::KILL,secondary_attack,attack,0);
}
animator.start_animations();
animator.wait_for_end();
reset_helpers(winner, &loser);
reset_helpers(&*winner, &loser);
if(events::mouse_handler* mousehandler = events::mouse_handler::get_singleton()) {
mousehandler->invalidate_reachmap();
@ -636,7 +640,7 @@ void unit_attack(display * disp, game_board & board,
unit_animator animator;
animator.add_animation(&attacker, "attack", att->get_location(), def->get_location(), damage, true, text_2,
animator.add_animation(attacker.shared_from_this(), "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.shared_from_this(),
secondary_attack, swing);
@ -644,7 +648,7 @@ void unit_attack(display * disp, game_board & board,
const unit_animation* defender_anim = def->anim_comp().choose_animation(*disp, def->get_location(), "defend",
att->get_location(), damage, hit_type, attack.shared_from_this(), secondary_attack, swing);
animator.add_animation(&defender, defender_anim, def->get_location(), true, text, {255, 0, 0});
animator.add_animation(defender.shared_from_this(), defender_anim, def->get_location(), true, text, {255, 0, 0});
for(const unit_ability& ability : attacker.get_abilities_weapons("leadership", attack.shared_from_this(), secondary_attack)) {
if(ability.teacher_loc == a) {
@ -658,7 +662,7 @@ void unit_attack(display * disp, game_board & board,
unit_map::const_iterator leader = board.units().find(ability.teacher_loc);
assert(leader.valid());
leader->set_facing(ability.teacher_loc.get_relative_dir(a));
animator.add_animation(&*leader, "leading", ability.teacher_loc,
animator.add_animation(leader.get_shared_ptr(), "leading", ability.teacher_loc,
att->get_location(), damage, true, "", {0,0,0},
hit_type, attack.shared_from_this(), secondary_attack, swing);
}
@ -675,7 +679,7 @@ void unit_attack(display * disp, game_board & board,
unit_map::const_iterator helper = board.units().find(ability.teacher_loc);
assert(helper.valid());
helper->set_facing(ability.teacher_loc.get_relative_dir(b));
animator.add_animation(&*helper, "resistance", ability.teacher_loc,
animator.add_animation(helper.get_shared_ptr(), "resistance", ability.teacher_loc,
def->get_location(), damage, true, "", {0,0,0},
hit_type, attack.shared_from_this(), secondary_attack, swing);
}
@ -765,13 +769,13 @@ void unit_recruited(const map_location& loc,const map_location& leader_loc)
if (leader != disp->get_units().end()) {
leader->set_facing(leader_loc.get_relative_dir(loc));
if (leader_visible) {
animator.add_animation(&*leader, "recruiting", leader_loc, loc, 0, true);
animator.add_animation(leader.get_shared_ptr(), "recruiting", leader_loc, loc, 0, true);
}
}
disp->draw();
}
animator.add_animation(&*u, "recruited", loc, leader_loc);
animator.add_animation(u.get_shared_ptr(), "recruited", loc, leader_loc);
animator.start_animations();
animator.wait_for_end();
animator.set_all_standing();
@ -798,22 +802,22 @@ void unit_healing(unit &healed, const std::vector<unit *> &healers, int healing,
for (unit *h : healers) {
h->set_facing(h->get_location().get_relative_dir(healed_loc));
animator.add_animation(h, "healing", h->get_location(),
animator.add_animation(h->shared_from_this(), "healing", h->get_location(),
healed_loc, healing);
}
if (healing < 0) {
animator.add_animation(&healed, "poisoned", healed_loc,
animator.add_animation(healed.shared_from_this(), "poisoned", healed_loc,
map_location::null_location(), -healing, false,
number_and_text(-healing, extra_text),
{255,0,0});
} else if ( healing > 0 ) {
animator.add_animation(&healed, "healed", healed_loc,
animator.add_animation(healed.shared_from_this(), "healed", healed_loc,
map_location::null_location(), healing, false,
number_and_text(healing, extra_text),
{0,255,0});
} else {
animator.add_animation(&healed, "healed", healed_loc,
animator.add_animation(healed.shared_from_this(), "healed", healed_loc,
map_location::null_location(), 0, false,
extra_text, {0,255,0});
}

View file

@ -86,13 +86,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_ptr attack=nullptr, const_attack_ptr 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_ptr defender=unit_ptr());
/**
* 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_ptr attack=nullptr, const_attack_ptr secondary_attack=nullptr,const map_location& defender_loc = map_location::null_location(), unit * defender=nullptr);
void unit_sheath_weapon( const map_location& loc, unit_ptr u=unit_ptr(), const_attack_ptr attack=nullptr, const_attack_ptr secondary_attack=nullptr,const map_location& defender_loc = map_location::null_location(), unit_ptr defender=unit_ptr());
/**
* Show a unit fading out.
@ -102,7 +102,7 @@ void unit_sheath_weapon( const map_location& loc, unit* u=nullptr, const_attack_
void unit_die( const map_location& loc, unit& u,
const_attack_ptr attack=nullptr, const_attack_ptr secondary_attack=nullptr,
const map_location& winner_loc=map_location::null_location(),
unit* winner=nullptr);
unit_ptr winner = unit_ptr());
/**

View file

@ -208,37 +208,6 @@ namespace
}
} // end anon namespace
/**
* Intrusive Pointer interface
*
**/
void intrusive_ptr_add_ref(const unit* u)
{
assert(u->ref_count_ >= 0);
// the next code line is to notice possible wrongly initialized units.
// The 100000 is picked rather randomly. If you are in the situation
// that you can actually have more then 100000 intrusive_ptr to one unit
// or if you are sure that the refcounting system works
// then feel free to remove the next line
assert(u->ref_count_ < 100000);
if(u->ref_count_ == 0) {
LOG_UT << "Freshly constructed" << std::endl;
}
++(u->ref_count_);
}
void intrusive_ptr_release(const unit* u)
{
assert(u->ref_count_ >= 1);
assert(u->ref_count_ < 100000); //See comment in intrusive_ptr_add_ref
if(--(u->ref_count_) == 0)
{
DBG_UT << "Deleting a unit: id = " << u->id() << ", uid = " << u->underlying_id() << std::endl;
delete u;
}
}
/**
* Converts a string ID to a unit_type.
* Throws a game_error exception if the string does not correspond to a type.
@ -297,7 +266,7 @@ struct ptr_vector_pushback
// Copy constructor
unit::unit(const unit& o)
: ref_count_(0)
: std::enable_shared_from_this<unit>()
, loc_(o.loc_)
, advances_to_(o.advances_to_)
, type_(o.type_)
@ -377,8 +346,8 @@ unit::unit(const unit& o)
}
}
unit::unit()
: ref_count_(0)
unit::unit(unit_ctor_t)
: std::enable_shared_from_this<unit>()
, loc_()
, advances_to_()
, type_(nullptr)

View file

@ -126,7 +126,7 @@ private:
/**
* This class represents a *single* unit of a specific type.
*/
class unit
class unit : public std::enable_shared_from_this<unit>
{
public:
/**
@ -145,7 +145,13 @@ private:
// Copy constructor
unit(const unit& u);
unit();
struct unit_ctor_t {};
public:
//private default ctor, butusing constructor to allow calling make_shared<unit> in create().
unit(unit_ctor_t);
unit() = delete;
private:
enum UNIT_ATTRIBUTE
{
UA_MAX_HP,
@ -184,7 +190,7 @@ public:
/** Initializes a unit from a config */
static unit_ptr create(const config& cfg, bool use_traits = false, const vconfig* vcfg = nullptr)
{
unit_ptr res(new unit());
unit_ptr res = std::make_shared<unit>(unit_ctor_t());
res->init(cfg, use_traits, vcfg);
return res;
}
@ -196,20 +202,21 @@ public:
*/
static unit_ptr create(const unit_type& t, int side, bool real_unit, unit_race::GENDER gender = unit_race::NUM_GENDERS, const std::string& variation = "")
{
unit_ptr res(new unit());
unit_ptr res = std::make_shared<unit>(unit_ctor_t());
res->init(t, side, real_unit, gender, variation);
return res;
}
unit_ptr clone() const
{
return unit_ptr(new unit(*this));
return unit_ptr(std::shared_ptr<unit>(new unit(*this)));
}
unit_ptr shared_from_this()
{
return unit_ptr(this);
}
//unit_ptr shared_from_this()
//{
// return unit_ptr(this);
//}
virtual ~unit();
@ -1772,21 +1779,11 @@ public:
*/
unit& mark_clone(bool is_temporary);
/** @} */
long ref_count() const
{
return ref_count_;
}
friend void intrusive_ptr_add_ref(const unit*);
friend void intrusive_ptr_release(const unit*);
void set_appearance_changed(bool value) { appearance_changed_ = value; }
bool appearance_changed() const { return appearance_changed_; }
protected:
mutable long ref_count_; // used by intrusive_ptr
private:
map_location loc_;

View file

@ -0,0 +1,90 @@
/*
Copyright (C) 2020 the Battle for Wesnoth Project https://www.wesnoth.org/
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
#pragma once
#include "global.hpp"
#include <memory>
namespace utils {
template <typename T>
class shared_reference
{
std::shared_ptr<T> m_ptr;
public:
template<typename Y>
shared_reference(const shared_reference<Y>& p)
: m_ptr(p.m_ptr)
{ }
template<typename Y>
shared_reference(shared_reference<Y>&& p)
: m_ptr(std::move(p.m_ptr))
{ }
template<typename Y>
explicit shared_reference(const std::shared_ptr<Y>& p)
: m_ptr(p)
{
if(!p) {
throw std::invalid_argument("invalid shared_reference");
}
}
template<typename Y>
explicit shared_reference(std::shared_ptr<Y>&& p)
: m_ptr(p)
{
if(!p) {
throw std::invalid_argument("invalid shared_reference");
}
}
template<typename Y>
shared_reference& operator=(shared_reference<Y>&& p)
{
m_ptr = std::move(p.m_ptr);
return *this;
}
template<typename Y>
shared_reference& operator=(const shared_reference<Y>& p)
{
m_ptr = p.m_ptr;
return *this;
}
~shared_reference() = default;
operator std::shared_ptr<T>()
{ return m_ptr; }
T* operator->() { return m_ptr.get(); }
const T* operator->() const { return m_ptr.get(); }
T& operator*() { return *m_ptr.get(); }
const T& operator*() const { return *m_ptr.get(); }
template <typename XT, typename...XTypes>
friend shared_reference<XT> make_shared_reference(XTypes&&...args);
};
template <typename T, typename...Types>
shared_reference<T> make_shared_reference(Types&&...args)
{
return shared_reference<T>(std::make_shared<T>(std::forward<Types>(args)...));
}
} // namespace utils