diff --git a/src/actions/attack.cpp b/src/actions/attack.cpp index 2494772c3382..a4f7ad4da96f 100644 --- a/src/actions/attack.cpp +++ b/src/actions/attack.cpp @@ -1291,6 +1291,8 @@ void attack::unit_killed(unit_info& attacker, std::string undead_variation = defender.get_unit().undead_variation(); + unit::dying_unit_loc = defender.loc_; + fire_event("attack_end"); refresh_bc(); @@ -1315,6 +1317,7 @@ void attack::unit_killed(unit_info& attacker, // WML has invalidated the dying unit, abort. if(!defender.valid() || defender.get_unit().hitpoints() > 0) { + unit::dying_unit_loc = map_location::null_location(); return; } @@ -1339,6 +1342,8 @@ void attack::unit_killed(unit_info& attacker, resources::game_events->pump().fire("die", death_loc, attacker_loc, dat); refresh_bc(); + unit::dying_unit_loc = map_location::null_location(); + if(!defender.valid() || defender.get_unit().hitpoints() > 0) { // WML has invalidated the dying unit, abort return; diff --git a/src/units/unit.cpp b/src/units/unit.cpp index bc39fe7c19dc..48d59efbe041 100644 --- a/src/units/unit.cpp +++ b/src/units/unit.cpp @@ -207,6 +207,8 @@ namespace } } // end anon namespace +map_location unit::dying_unit_loc; + /** * Intrusive Pointer interface * @@ -630,7 +632,9 @@ void unit::init(const config& cfg, bool use_traits, const vconfig* vcfg) } if(const config::attribute_value* v = cfg.get("hitpoints")) { - VALIDATE(*v > 0, _("Unit with negative HP found")); + if(loc_ != dying_unit_loc) { + VALIDATE(*v > 0, _("Unit with negative HP found")); + } hit_points_ = *v; } else { hit_points_ = max_hit_points_; diff --git a/src/units/unit.hpp b/src/units/unit.hpp index 8a918c79b1b5..8d8276299d9f 100644 --- a/src/units/unit.hpp +++ b/src/units/unit.hpp @@ -1598,6 +1598,15 @@ class unit void set_appearance_changed(bool value) { appearance_changed_ = value; } bool appearance_changed() const { return appearance_changed_; } + /** + * The location of the dying unit for the duration of last_breath and die events. + * Null location when neither of those events is running. + * This exists in order to detect at unit creation time whether the WML/Lua code is unstoring a unit + * that was already dead (e.g. as a result of [modify_unit], which is implemented with unstoring + * under the hood). That's the only situation where creating a unit with negative HP is allowed. + */ + static map_location dying_unit_loc; + protected: mutable long ref_count_; // used by intrusive_ptr