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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -62,12 +62,13 @@ class Knight : Actor
void A_KnightAttack ()
{
if (!target) return;
let targ = target;
if (!targ) return;
if (CheckMeleeRange ())
{
int damage = random[KnightAttack](1, 8) * 3;
int newdam = target.DamageMobj (self, self, damage, 'Melee');
target.TraceBleed (newdam > 0 ? newdam : damage, self);
int newdam = targ.DamageMobj (self, self, damage, 'Melee');
targ.TraceBleed (newdam > 0 ? newdam : damage, self);
A_PlaySound ("hknight/melee", CHAN_BODY);
return;
}
@ -75,11 +76,11 @@ class Knight : Actor
A_PlaySound (AttackSound, CHAN_BODY);
if (self.bShadow || random[KnightAttack]() < 40)
{ // Red axe
SpawnMissileZ (pos.Z + 36, target, "RedAxe");
SpawnMissileZ (pos.Z + 36, targ, "RedAxe");
}
else
{ // 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 ()
{
A_GhostOff();
if (!target) return;
let targ = target;
if (!targ) return;
A_PlaySound (AttackSound, CHAN_WEAPON);
if (CheckMeleeRange())
{
int damage = random[WizAtk3](1, 8) * 4;
int newdam = target.DamageMobj (self, self, damage, 'Melee');
target.TraceBleed (newdam > 0 ? newdam : damage, self);
int newdam = targ.DamageMobj (self, self, damage, 'Melee');
targ.TraceBleed (newdam > 0 ? newdam : damage, self);
return;
}
Actor mo = SpawnMissile (target, "WizardFX1");
Actor mo = SpawnMissile (targ, "WizardFX1");
if (mo != null)
{
SpawnMissileAngle("WizardFX1", mo.Angle - 45. / 8, mo.Vel.Z);

View file

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

View file

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

View file

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

View file

@ -178,25 +178,26 @@ class ThrustFloor : Actor
BlockThingsIterator it = BlockThingsIterator.Create(self);
while (it.Next())
{
let targ = it.thing;
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;
// 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;
}
if (!it.thing.bShootable)
if (!targ.bShootable)
continue;
if (it.thing == self)
if (targ == self)
continue; // don't clip against self
int newdam = it.thing.DamageMobj (self, self, 10001, 'Crush');
it.thing.TraceBleed (newdam > 0 ? newdam : 10001, null);
int newdam = targ.DamageMobj (self, self, 10001, 'Crush');
targ.TraceBleed (newdam > 0 ? newdam : 10001, null);
args[1] = 1; // Mark thrust thing as bloody
}
}

View file

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

View file

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