Page 1 of 1

Monsters shooting at corpses

Posted: Tue Nov 10, 2020 9:25 pm
by rileymartin
I reported this a while back but it does not appear to have changed:

Monsters with volley attacks, such as the Mancubus or Cyberdemon, will aim down to shoot at the floor, where the monster corpse is, if their first shot killed the enemy - even if they're on the same elevation. This happens in (Strict) compatibility and is not vanilla behaviour. The monster is supposed to keep shooting straight over the corpse where the dead enemy's hitbox used to be and not correct their aim downwards mid-volley like that.

Re: Monsters shooting at corpses

Posted: Fri Jan 15, 2021 9:37 pm
by rileymartin


Here is a rough video demonstration showing the difference. After the 18 second mark, you can see the GZ Cyber fire shots at the ground after killing Barons. Meanwhile, in the second half, the PR+ Cyber always shoots parallel to the ground after a kill.

Re: Monsters shooting at corpses

Posted: Wed May 19, 2021 11:42 am
by Graf Zahl
This is a typical vanilla accuracy issue. The missile shooting function never checks the height of either shooter or target, it only checks their z position. Needless to say, if this gets changed back to this sloppy math it'd wreak havoc with all kinds of mods. ZDoom once changed this to aim at the target's center so that it works with smaller and larger targets than what the original code assumed would be valid.

It's just particularly noticable with corpses because they get reduced to a height of 16.

Re: Monsters shooting at corpses

Posted: Mon May 24, 2021 5:20 am
by Warden
This was bothering me now that you've pointed it out. Here's a Zscript fix for the Cyberdemon and Mancubus if you want to mod it yourself.

Code: Select all

class VNCyberdemon : Cyberdemon replaces Cyberdemon
{
    states {
    Missile:
    // restore vanilla Z aiming behavior for the Cyberdemon
		CYBR E 6 A_FaceTarget;
		CYBR F 12 A_VNCyberAttack;
		CYBR E 12 A_FaceTarget;
		CYBR F 12 A_VNCyberAttack;
		CYBR E 12 A_FaceTarget;
		CYBR F 12 A_VNCyberAttack;
		goto See;
    }
    
    void A_VNCyberAttack()
    {
        if (!target) return;
        A_FaceTarget();
        let missile = SpawnMissile(target, "Rocket");
        if (missile) {
            missile.Vel.Z = (target.Pos.Z - Pos.Z) / DistanceBySpeed(target, missile.speed);
        }
    }
}

class VNFatso : Fatso replaces Fatso
{
    states {
    Missile:
    // restore vanilla Z aiming behavior for the Mancubus
		FATT G 20 A_FatRaise;
		FATT H 10 BRIGHT A_VNFatAttack1;
		FATT IG 5 A_FaceTarget;
		FATT H 10 BRIGHT A_VNFatAttack2;
		FATT IG 5 A_FaceTarget;
		FATT H 10 BRIGHT A_VNFatAttack3;
		FATT IG 5 A_FaceTarget;
		goto See;
    }
    
    void A_VNFatAttack1()
    {
        if (!target) return;
        A_FaceTarget ();
        // Change direction  to ...
        Angle += FATSPREAD;
        let missile = SpawnMissile(target, "FatShot");
        if (missile) {
            missile.Vel.Z = (target.Pos.Z - Pos.Z) / DistanceBySpeed(target, missile.speed);
        }
        missile = SpawnMissile(target, "FatShot");
        if (missile) {
            missile.Angle += FATSPREAD;
            missile.VelFromAngle();
            missile.Vel.Z = (target.Pos.Z - Pos.Z) / DistanceBySpeed(target, missile.speed);
        }
    }    
    
    void A_VNFatAttack2()
    {
        if (!target) return;
        A_FaceTarget ();
        // Now here choose opposite deviation.
        Angle -= FATSPREAD;
        let missile = SpawnMissile(target, "FatShot");
        if (missile) {
            missile.Vel.Z = (target.Pos.Z - Pos.Z) / DistanceBySpeed(target, missile.speed);
        }
        missile = SpawnMissile(target, "FatShot");
        if (missile) {
            missile.Angle -= FATSPREAD;
            missile.VelFromAngle();
            missile.Vel.Z = (target.Pos.Z - Pos.Z) / DistanceBySpeed(target, missile.speed);
        }
    }    
    
    void A_VNFatAttack3()
    {
        if (!target) return;
        A_FaceTarget ();
        let missile = SpawnMissile(target, "FatShot");
        if (missile) {
            missile.Angle -= FATSPREAD/2;
            missile.VelFromAngle();
            missile.Vel.Z = (target.Pos.Z - Pos.Z) / DistanceBySpeed(target, missile.speed);
        }
        missile = SpawnMissile(target, "FatShot");
        if (missile) {
            missile.Angle += FATSPREAD/2;
            missile.VelFromAngle();
            missile.Vel.Z = (target.Pos.Z - Pos.Z) / DistanceBySpeed(target, missile.speed);
        }
    }
}