- fixed: All melee functions calling TraceBleed after DamageMobj must first copy the target member to a local variable.

DamageMobj can destroy the damaged actor if the death state sequence has zero duration. But Actor.target is a garbage collected member variable, i.e. it will be null, once the actor it points to gets destroyed.
This was originally done correctly in the C++ code but during the scriptification all those 'AActor *target = self->target' lines were removed because they looked redundant, but were not.
This commit is contained in:
Christoph Oelckers 2017-06-06 09:12:23 +02:00
parent c698f10257
commit a210aaea3e
16 changed files with 99 additions and 80 deletions

View file

@ -904,22 +904,23 @@ class Actor : Thinker native
private void DoAttack (bool domelee, bool domissile, int MeleeDamage, Sound MeleeSound, Class<Actor> MissileType,double MissileHeight) private void DoAttack (bool domelee, bool domissile, int MeleeDamage, Sound MeleeSound, Class<Actor> MissileType,double MissileHeight)
{ {
if (target == NULL) return; let targ = target;
if (targ == NULL) return;
A_FaceTarget (); A_FaceTarget ();
if (domelee && MeleeDamage>0 && CheckMeleeRange ()) if (domelee && MeleeDamage>0 && CheckMeleeRange ())
{ {
int damage = random[CustomMelee](1, 8) * MeleeDamage; int damage = random[CustomMelee](1, 8) * MeleeDamage;
if (MeleeSound) A_PlaySound (MeleeSound, CHAN_WEAPON); if (MeleeSound) A_PlaySound (MeleeSound, CHAN_WEAPON);
int newdam = target.DamageMobj (self, self, damage, 'Melee'); int newdam = targ.DamageMobj (self, self, damage, 'Melee');
target.TraceBleed (newdam > 0 ? newdam : damage, self); targ.TraceBleed (newdam > 0 ? newdam : damage, self);
} }
else if (domissile && MissileType != NULL) else if (domissile && MissileType != NULL)
{ {
// This seemingly senseless code is needed for proper aiming. // This seemingly senseless code is needed for proper aiming.
double add = MissileHeight + GetBobOffset() - 32; double add = MissileHeight + GetBobOffset() - 32;
AddZ(add); AddZ(add);
Actor missile = SpawnMissileXYZ (Pos + (0, 0, 32), target, MissileType, false); Actor missile = SpawnMissileXYZ (Pos + (0, 0, 32), targ, MissileType, false);
AddZ(-add); AddZ(-add);
if (missile) if (missile)
@ -927,7 +928,7 @@ class Actor : Thinker native
// automatic handling of seeker missiles // automatic handling of seeker missiles
if (missile.bSeekerMissile) if (missile.bSeekerMissile)
{ {
missile.tracer = target; missile.tracer = targ;
} }
missile.CheckMissileSpawn(radius); missile.CheckMissileSpawn(radius);
} }

View file

@ -149,14 +149,15 @@ extend class Actor
{ {
void A_BruisAttack() void A_BruisAttack()
{ {
if (target) let targ = target;
if (targ)
{ {
if (CheckMeleeRange()) if (CheckMeleeRange())
{ {
int damage = random[pr_bruisattack](1, 8) * 10; int damage = random[pr_bruisattack](1, 8) * 10;
A_PlaySound ("baron/melee", CHAN_WEAPON); A_PlaySound ("baron/melee", CHAN_WEAPON);
int newdam = target.DamageMobj (self, self, damage, "Melee"); int newdam = target.DamageMobj (self, self, damage, "Melee");
target.TraceBleed (newdam > 0 ? newdam : damage, self); targ.TraceBleed (newdam > 0 ? newdam : damage, self);
} }
else else
{ {

View file

@ -99,19 +99,20 @@ extend class Actor
{ {
void A_HeadAttack() void A_HeadAttack()
{ {
if (target) let targ = target;
if (targ)
{ {
if (CheckMeleeRange()) if (CheckMeleeRange())
{ {
int damage = random[pr_headattack](1, 6) * 10; int damage = random[pr_headattack](1, 6) * 10;
A_PlaySound (AttackSound, CHAN_WEAPON); A_PlaySound (AttackSound, CHAN_WEAPON);
int newdam = target.DamageMobj (self, self, damage, "Melee"); int newdam = target.DamageMobj (self, self, damage, "Melee");
target.TraceBleed (newdam > 0 ? newdam : damage, self); targ.TraceBleed (newdam > 0 ? newdam : damage, self);
} }
else else
{ {
// launch a missile // launch a missile
SpawnMissile (target, "CacodemonBall"); SpawnMissile (targ, "CacodemonBall");
} }
} }
} }

View file

@ -85,11 +85,12 @@ extend class Actor
{ {
void A_SargAttack() void A_SargAttack()
{ {
if (target && CheckMeleeRange()) let targ = target;
if (targ && CheckMeleeRange())
{ {
int damage = random[pr_sargattack](1, 10) * 4; int damage = random[pr_sargattack](1, 10) * 4;
int newdam = target.DamageMobj (self, self, damage, "Melee"); int newdam = targ.DamageMobj (self, self, damage, "Melee");
target.TraceBleed (newdam > 0 ? newdam : damage, self); targ.TraceBleed (newdam > 0 ? newdam : damage, self);
} }
} }
} }

View file

@ -104,19 +104,20 @@ extend class Actor
{ {
void A_TroopAttack() void A_TroopAttack()
{ {
if (target) let targ = target;
if (targ)
{ {
if (CheckMeleeRange()) if (CheckMeleeRange())
{ {
int damage = random[pr_troopattack](1, 8) * 3; int damage = random[pr_troopattack](1, 8) * 3;
A_PlaySound ("imp/melee", CHAN_WEAPON); A_PlaySound ("imp/melee", CHAN_WEAPON);
int newdam = target.DamageMobj (self, self, damage, "Melee"); int newdam = targ.DamageMobj (self, self, damage, "Melee");
target.TraceBleed (newdam > 0 ? newdam : damage, self); targ.TraceBleed (newdam > 0 ? newdam : damage, self);
} }
else else
{ {
// launch a missile // launch a missile
SpawnMissile (target, "DoomImpBall"); SpawnMissile (targ, "DoomImpBall");
} }
} }
} }

View file

@ -154,15 +154,16 @@ extend class Actor
void A_SkelFist() void A_SkelFist()
{ {
if (target == null) return; let targ = target;
if (targ == null) return;
A_FaceTarget(); A_FaceTarget();
if (CheckMeleeRange ()) if (CheckMeleeRange ())
{ {
int damage = random[SkelFist](1, 10) * 6; int damage = random[SkelFist](1, 10) * 6;
A_PlaySound("skeleton/melee", CHAN_WEAPON); A_PlaySound("skeleton/melee", CHAN_WEAPON);
int newdam = target.DamageMobj (self, self, damage, 'Melee'); int newdam = targ.DamageMobj (self, self, damage, 'Melee');
target.TraceBleed (newdam > 0 ? newdam : damage, self); targ.TraceBleed (newdam > 0 ? newdam : damage, self);
} }
} }

View file

@ -115,7 +115,8 @@ class Sorcerer1 : Actor
void A_Srcr1Attack () void A_Srcr1Attack ()
{ {
if (!target) let targ = target;
if (!targ)
{ {
return; return;
} }
@ -123,18 +124,18 @@ class Sorcerer1 : Actor
if (CheckMeleeRange ()) if (CheckMeleeRange ())
{ {
int damage = random[Srcr1Attack](1,8) * 8; int damage = random[Srcr1Attack](1,8) * 8;
int newdam = target.DamageMobj (self, self, damage, 'Melee'); int newdam = targ.DamageMobj (self, self, damage, 'Melee');
target.TraceBleed (newdam > 0 ? newdam : damage, self); targ.TraceBleed (newdam > 0 ? newdam : damage, self);
return; return;
} }
if (health > (SpawnHealth()/3)*2) if (health > (SpawnHealth()/3)*2)
{ // Spit one fireball { // Spit one fireball
SpawnMissileZ (pos.z + 48, target, "SorcererFX1"); SpawnMissileZ (pos.z + 48, targ, "SorcererFX1");
} }
else else
{ // Spit three fireballs { // Spit three fireballs
Actor mo = SpawnMissileZ (pos.z + 48, target, "SorcererFX1"); Actor mo = SpawnMissileZ (pos.z + 48, targ, "SorcererFX1");
if (mo != null) if (mo != null)
{ {
double ang = mo.angle; double ang = mo.angle;
@ -343,7 +344,8 @@ class Sorcerer2 : Actor
void A_Srcr2Attack () void A_Srcr2Attack ()
{ {
if (!target) let targ = target;
if (!targ)
{ {
return; return;
} }
@ -351,8 +353,8 @@ class Sorcerer2 : Actor
if (CheckMeleeRange()) if (CheckMeleeRange())
{ {
int damage = random[Srcr2Atk](1, 8) * 20; int damage = random[Srcr2Atk](1, 8) * 20;
int newdam = target.DamageMobj (self, self, damage, 'Melee'); int newdam = targ.DamageMobj (self, self, damage, 'Melee');
target.TraceBleed (newdam > 0 ? newdam : damage, self); targ.TraceBleed (newdam > 0 ? newdam : damage, self);
return; return;
} }
int chance = health < SpawnHealth()/2 ? 96 : 48; int chance = health < SpawnHealth()/2 ? 96 : 48;
@ -364,7 +366,7 @@ class Sorcerer2 : Actor
} }
else else
{ // Blue bolt { // Blue bolt
SpawnMissile (target, "Sorcerer2FX1"); SpawnMissile (targ, "Sorcerer2FX1");
} }
} }

View file

@ -70,7 +70,8 @@ class Ironlich : Actor
// Whirlwind (close 40% : far 20%) // Whirlwind (close 40% : far 20%)
// Distance threshold = 8 cells // Distance threshold = 8 cells
if (target == null) let targ = target;
if (targ == null)
{ {
return; return;
} }
@ -78,20 +79,20 @@ class Ironlich : Actor
if (CheckMeleeRange ()) if (CheckMeleeRange ())
{ {
int damage = random[LichAttack](1, 8) * 6; int damage = random[LichAttack](1, 8) * 6;
int newdam = target.DamageMobj (self, self, damage, 'Melee'); int newdam = targ.DamageMobj (self, self, damage, 'Melee');
target.TraceBleed (newdam > 0 ? newdam : damage, self); targ.TraceBleed (newdam > 0 ? newdam : damage, self);
return; return;
} }
int dist = Distance2D(target) > 8 * 64; int dist = Distance2D(targ) > 8 * 64;
int randAttack = random[LichAttack](); int randAttack = random[LichAttack]();
if (randAttack < atkResolve1[dist]) if (randAttack < atkResolve1[dist])
{ // Ice ball { // Ice ball
SpawnMissile (target, "HeadFX1"); SpawnMissile (targ, "HeadFX1");
A_PlaySound ("ironlich/attack2", CHAN_BODY); A_PlaySound ("ironlich/attack2", CHAN_BODY);
} }
else if (randAttack < atkResolve2[dist]) else if (randAttack < atkResolve2[dist])
{ // Fire column { // Fire column
Actor baseFire = SpawnMissile (target, "HeadFX3"); Actor baseFire = SpawnMissile (targ, "HeadFX3");
if (baseFire != null) if (baseFire != null)
{ {
baseFire.SetStateLabel("NoGrow"); baseFire.SetStateLabel("NoGrow");
@ -116,11 +117,11 @@ class Ironlich : Actor
} }
else else
{ // Whirlwind { // Whirlwind
Actor mo = SpawnMissile (target, "Whirlwind"); Actor mo = SpawnMissile (targ, "Whirlwind");
if (mo != null) if (mo != null)
{ {
mo.AddZ(-32); mo.AddZ(-32);
mo.tracer = target; mo.tracer = targ;
mo.health = 20*TICRATE; // Duration mo.health = 20*TICRATE; // Duration
A_PlaySound ("ironlich/attack3", CHAN_BODY); A_PlaySound ("ironlich/attack3", CHAN_BODY);
} }

View file

@ -62,12 +62,13 @@ class Knight : Actor
void A_KnightAttack () void A_KnightAttack ()
{ {
if (!target) return; let targ = target;
if (!targ) return;
if (CheckMeleeRange ()) if (CheckMeleeRange ())
{ {
int damage = random[KnightAttack](1, 8) * 3; int damage = random[KnightAttack](1, 8) * 3;
int newdam = target.DamageMobj (self, self, damage, 'Melee'); int newdam = targ.DamageMobj (self, self, damage, 'Melee');
target.TraceBleed (newdam > 0 ? newdam : damage, self); targ.TraceBleed (newdam > 0 ? newdam : damage, self);
A_PlaySound ("hknight/melee", CHAN_BODY); A_PlaySound ("hknight/melee", CHAN_BODY);
return; return;
} }
@ -75,11 +76,11 @@ class Knight : Actor
A_PlaySound (AttackSound, CHAN_BODY); A_PlaySound (AttackSound, CHAN_BODY);
if (self.bShadow || random[KnightAttack]() < 40) if (self.bShadow || random[KnightAttack]() < 40)
{ // Red axe { // Red axe
SpawnMissileZ (pos.Z + 36, target, "RedAxe"); SpawnMissileZ (pos.Z + 36, targ, "RedAxe");
} }
else else
{ // Green axe { // Green axe
SpawnMissileZ (pos.Z + 36, target, "KnightAxe"); SpawnMissileZ (pos.Z + 36, targ, "KnightAxe");
} }
} }
} }

View file

@ -112,16 +112,17 @@ class Wizard : Actor
void A_WizAtk3 () void A_WizAtk3 ()
{ {
A_GhostOff(); A_GhostOff();
if (!target) return; let targ = target;
if (!targ) return;
A_PlaySound (AttackSound, CHAN_WEAPON); A_PlaySound (AttackSound, CHAN_WEAPON);
if (CheckMeleeRange()) if (CheckMeleeRange())
{ {
int damage = random[WizAtk3](1, 8) * 4; int damage = random[WizAtk3](1, 8) * 4;
int newdam = target.DamageMobj (self, self, damage, 'Melee'); int newdam = targ.DamageMobj (self, self, damage, 'Melee');
target.TraceBleed (newdam > 0 ? newdam : damage, self); targ.TraceBleed (newdam > 0 ? newdam : damage, self);
return; return;
} }
Actor mo = SpawnMissile (target, "WizardFX1"); Actor mo = SpawnMissile (targ, "WizardFX1");
if (mo != null) if (mo != null)
{ {
SpawnMissileAngle("WizardFX1", mo.Angle - 45. / 8, mo.Vel.Z); SpawnMissileAngle("WizardFX1", mo.Angle - 45. / 8, mo.Vel.Z);

View file

@ -82,7 +82,8 @@ class Bishop : Actor
void A_BishopAttack() void A_BishopAttack()
{ {
if (!target) let targ = target;
if (!targ)
{ {
return; return;
} }
@ -90,8 +91,8 @@ class Bishop : Actor
if (CheckMeleeRange()) if (CheckMeleeRange())
{ {
int damage = random[BishopAttack](1, 8) * 4; int damage = random[BishopAttack](1, 8) * 4;
int newdam = target.DamageMobj (self, self, damage, 'Melee'); int newdam = targ.DamageMobj (self, self, damage, 'Melee');
target.TraceBleed (newdam > 0 ? newdam : damage, self); targ.TraceBleed (newdam > 0 ? newdam : damage, self);
return; return;
} }
missilecount = (random[BishopAttack]() & 3) + 5; missilecount = (random[BishopAttack]() & 3) + 5;

View file

@ -109,8 +109,8 @@ class Dragon : Actor
if (CheckMeleeRange ()) if (CheckMeleeRange ())
{ {
int damage = random[DragonSeek](1, 8) * 10; int damage = random[DragonSeek](1, 8) * 10;
int newdam = target.DamageMobj (self, self, damage, 'Melee'); int newdam = targ.DamageMobj (self, self, damage, 'Melee');
target.TraceBleed (newdam > 0 ? newdam : damage, self); targ.TraceBleed (newdam > 0 ? newdam : damage, self);
A_PlaySound (AttackSound, CHAN_WEAPON); A_PlaySound (AttackSound, CHAN_WEAPON);
} }
else if (random[DragonSeek]() < 128 && CheckMissileRange()) else if (random[DragonSeek]() < 128 && CheckMissileRange())
@ -210,7 +210,8 @@ class Dragon : Actor
double ang; double ang;
DragonSeek (4., 8.); DragonSeek (4., 8.);
if (target) let targ = target;
if (targ)
{ {
if(!target.bShootable) if(!target.bShootable)
{ // target died { // target died
@ -221,8 +222,8 @@ class Dragon : Actor
if (ang <22.5 && CheckMeleeRange()) if (ang <22.5 && CheckMeleeRange())
{ {
int damage = random[DragonFlight](1, 8) * 8; int damage = random[DragonFlight](1, 8) * 8;
int newdam = target.DamageMobj (self, self, damage, 'Melee'); int newdam = targ.DamageMobj (self, self, damage, 'Melee');
target.TraceBleed (newdam > 0 ? newdam : damage, self); targ.TraceBleed (newdam > 0 ? newdam : damage, self);
A_PlaySound (AttackSound, CHAN_WEAPON); A_PlaySound (AttackSound, CHAN_WEAPON);
} }
else if (ang <= 20) else if (ang <= 20)

View file

@ -240,15 +240,16 @@ class Serpent : Actor
void A_SerpentMeleeAttack() void A_SerpentMeleeAttack()
{ {
if (!target) let targ = target;
if (!targ)
{ {
return; return;
} }
if (CheckMeleeRange ()) if (CheckMeleeRange ())
{ {
int damage = random[SerpentAttack](1, 8) * 5; int damage = random[SerpentAttack](1, 8) * 5;
int newdam = target.DamageMobj (self, self, damage, 'Melee'); int newdam = targ.DamageMobj (self, self, damage, 'Melee');
target.TraceBleed (newdam > 0 ? newdam : damage, self); targ.TraceBleed (newdam > 0 ? newdam : damage, self);
A_PlaySound ("SerpentMeleeHit", CHAN_BODY); A_PlaySound ("SerpentMeleeHit", CHAN_BODY);
} }
if (random[SerpentAttack]() < 96) if (random[SerpentAttack]() < 96)

View file

@ -178,25 +178,26 @@ class ThrustFloor : Actor
BlockThingsIterator it = BlockThingsIterator.Create(self); BlockThingsIterator it = BlockThingsIterator.Create(self);
while (it.Next()) while (it.Next())
{ {
let targ = it.thing;
double blockdist = radius + it.thing.radius; double blockdist = radius + it.thing.radius;
if (abs(it.thing.pos.x - it.Position.X) >= blockdist || abs(it.thing.pos.y - it.Position.Y) >= blockdist) if (abs(targ.pos.x - it.Position.X) >= blockdist || abs(targ.pos.y - it.Position.Y) >= blockdist)
continue; continue;
// Q: Make this z-aware for everything? It never was before. // Q: Make this z-aware for everything? It never was before.
if (it.thing.pos.z + it.thing.height < pos.z || it.thing.pos.z > pos.z + height) if (targ.pos.z + targ.height < pos.z || targ.pos.z > pos.z + height)
{ {
if (CurSector.PortalGroup != it.thing.CurSector.PortalGroup) if (CurSector.PortalGroup != targ.CurSector.PortalGroup)
continue; continue;
} }
if (!it.thing.bShootable) if (!targ.bShootable)
continue; continue;
if (it.thing == self) if (targ == self)
continue; // don't clip against self continue; // don't clip against self
int newdam = it.thing.DamageMobj (self, self, 10001, 'Crush'); int newdam = targ.DamageMobj (self, self, 10001, 'Crush');
it.thing.TraceBleed (newdam > 0 ? newdam : 10001, null); targ.TraceBleed (newdam > 0 ? newdam : 10001, null);
args[1] = 1; // Mark thrust thing as bloody args[1] = 1; // Mark thrust thing as bloody
} }
} }

View file

@ -165,18 +165,19 @@ class Minotaur : Actor
void A_MinotaurAtk1() void A_MinotaurAtk1()
{ {
if (!target) let targ = target;
if (!targ)
{ {
return; return;
} }
A_PlaySound ("minotaur/melee", CHAN_WEAPON); A_PlaySound ("minotaur/melee", CHAN_WEAPON);
if (CheckMeleeRange()) if (CheckMeleeRange())
{ {
PlayerInfo player = targ.player;
int damage = random[MinotaurAtk1](1, 8) * 4; int damage = random[MinotaurAtk1](1, 8) * 4;
int newdam = target.DamageMobj (self, self, damage, 'Melee'); int newdam = targ.DamageMobj (self, self, damage, 'Melee');
target.TraceBleed (newdam > 0 ? newdam : damage, self); targ.TraceBleed (newdam > 0 ? newdam : damage, self);
PlayerInfo player = target.player; if (player != null && player.mo == targ)
if (player != null && player.mo == target)
{ // Squish the player { // Squish the player
player.deltaviewheight = -16; player.deltaviewheight = -16;
} }
@ -284,7 +285,8 @@ class Minotaur : Actor
{ {
bool friendly = bSummonedMonster; bool friendly = bSummonedMonster;
if (target == null) let targ = target;
if (targ == null)
{ {
return; return;
} }
@ -292,13 +294,13 @@ class Minotaur : Actor
if (CheckMeleeRange()) if (CheckMeleeRange())
{ {
int damage = random[MinotaurAtk2](1, 8) * (friendly ? 3 : 5); int damage = random[MinotaurAtk2](1, 8) * (friendly ? 3 : 5);
int newdam = target.DamageMobj (self, self, damage, 'Melee'); int newdam = targ.DamageMobj (self, self, damage, 'Melee');
target.TraceBleed (newdam > 0 ? newdam : damage, self); targ.TraceBleed (newdam > 0 ? newdam : damage, self);
return; return;
} }
double z = pos.z + 40; double z = pos.z + 40;
Class<Actor> fx = "MinotaurFX1"; Class<Actor> fx = "MinotaurFX1";
Actor mo = SpawnMissileZ (z, target, fx); Actor mo = SpawnMissileZ (z, targ, fx);
if (mo != null) if (mo != null)
{ {
// S_Sound (mo, CHAN_WEAPON, "minotaur/attack2", 1, ATTN_NORM); // S_Sound (mo, CHAN_WEAPON, "minotaur/attack2", 1, ATTN_NORM);
@ -323,18 +325,19 @@ class Minotaur : Actor
{ {
bool friendly = bSummonedMonster; bool friendly = bSummonedMonster;
if (!target) let targ = target;
if (!targ)
{ {
return; return;
} }
A_PlaySound ("minotaur/attack3", CHAN_VOICE); A_PlaySound ("minotaur/attack3", CHAN_VOICE);
if (CheckMeleeRange()) if (CheckMeleeRange())
{ {
PlayerInfo player = targ.player;
int damage = random[MinotaurAtk3](1, 8) * (friendly ? 3 : 5); int damage = random[MinotaurAtk3](1, 8) * (friendly ? 3 : 5);
int newdam = target.DamageMobj (self, self, damage, 'Melee'); int newdam = targ.DamageMobj (self, self, damage, 'Melee');
target.TraceBleed (newdam > 0 ? newdam : damage, self); targ.TraceBleed (newdam > 0 ? newdam : damage, self);
PlayerInfo player = target.player; if (player != null && player.mo == targ)
if (player != null && player.mo == target)
{ // Squish the player { // Squish the player
player.deltaviewheight = -16; player.deltaviewheight = -16;
} }

View file

@ -117,10 +117,11 @@ class Stalker : Actor
A_FaceTarget (); A_FaceTarget ();
if (CheckMeleeRange ()) if (CheckMeleeRange ())
{ {
let targ = target;
int damage = (random[Stalker]() & 7) * 2 + 2; int damage = (random[Stalker]() & 7) * 2 + 2;
int newdam = target.DamageMobj (self, self, damage, 'Melee'); int newdam = targ.DamageMobj (self, self, damage, 'Melee');
target.TraceBleed (newdam > 0 ? newdam : damage, self); targ.TraceBleed (newdam > 0 ? newdam : damage, self);
} }
} }
} }