[solved] emulate hexen arch melee attacks

Ask about ACS, DECORATE, ZScript, or any other scripting questions here!

Moderator: GZDoom Developers

Forum rules
Before asking on how to use a ZDoom feature, read the ZDoom wiki first. If you still don't understand how to use a feature, then ask here.

Please bear in mind that the people helping you do not automatically know how much you know. You may be asked to upload your project file to look at. Don't be afraid to ask questions about what things mean, but also please be patient with the people trying to help you. (And helpers, please be patient with the person you're trying to help!)
Post Reply
User avatar
Lagi
Posts: 683
Joined: Sat Jun 23, 2018 12:51 pm
Location: Thou shalt alter thy beliefs with new evidence

[solved] emulate hexen arch melee attacks

Post by Lagi »

Hexen melee attacks search for target in the cone of 90deg. which is very good.

Did someone write any function so i can use similar behavior with my weapons? (zscript is fine)

im too stupid to wrtie the func from here on my own:
https://github.com/coelckers/gzdoom/blo ... terfist.zs
but what excactly do you want?
TNT1 a A_meleeAsHexenAttack9326(dmg, range, pufftype*)

search arch can be hardcoded

*if i dont ask too much :D
Last edited by Lagi on Sat Dec 12, 2020 10:07 am, edited 1 time in total.
User avatar
Player701
 
 
Posts: 1710
Joined: Wed May 13, 2009 3:15 am
Graphics Processor: nVidia with Vulkan support
Contact:

Re: emulate hexen arch melee attacks

Post by Player701 »

The following code implements a generalized version of the fighter's fist attack. I've taken the original code and removed the parts specific to the fist's implementation. It seems to work fine on my end, please tell me if you have any problems with it.

Code: Select all

class HexenMeleeWeapon : Weapon
{
    private action bool TryPunch(double angle, int damage, int power, int range, class<Actor> pufftype)
    {
        Class<Actor> pufftype;
        FTranslatedLineTarget t;

        double slope = AimLineAttack (angle, 2*range, t, 0., ALF_CHECK3D);
        if (t.linetarget != null)
        {
            LineAttack (angle, 2*range, slope, damage, 'Melee', pufftype, true, t);
            if (t.linetarget != null)
            {
                // The mass threshold has been changed to CommanderKeen's value which has been used most often for 'unmovable' stuff.
                if (t.linetarget.player != null || (t.linetarget.Mass < 10000000 && (t.linetarget.bIsMonster)))
                {
                    if (!t.linetarget.bDontThrust)
                    {
                        t.linetarget.Thrust(power, t.attackAngleFromSource);
                    }
                }
                AdjustPlayerAngle(t);
                return true;
            }
        }
        return false;
    }

    action void A_HexenPunch(int damage, int range = 0, class<Actor> pufftype = 'BulletPuff', sound hitsound = "", sound misssound = "")
    {
        if (player == null)
        {
            return;
        }

        if (range == 0)
        {
            range = DEFMELEERANGE;
        }

        if (pufftype == null)
        {
            pufftype = 'BulletPuff';
        }

        for (int i = 0; i < 16; i++)
        {
            if (TryPunch(angle + i*(45./16), damage, 2, range, pufftype) || TryPunch(angle - i*(45./16), damage, 2, range, pufftype))
            { 
                // hit something            
                A_StartSound (hitsound, CHAN_WEAPON);
                return;
            }
        }

        A_StartSound (misssound, CHAN_WEAPON);
        double slope = AimLineAttack (angle, range, null, 0., ALF_CHECK3D);
        LineAttack (angle, range, slope, damage, 'Melee', pufftype, true);
    }
}
User avatar
Lagi
Posts: 683
Joined: Sat Jun 23, 2018 12:51 pm
Location: Thou shalt alter thy beliefs with new evidence

Re: emulate hexen arch melee attacks

Post by Lagi »

that was quick, thanks
User avatar
Lagi
Posts: 683
Joined: Sat Jun 23, 2018 12:51 pm
Location: Thou shalt alter thy beliefs with new evidence

Re: emulate hexen arch melee attacks

Post by Lagi »

works good, very as it should 8-)

is there a way to use the function A_hexenPunch without inheriting from HexenMeleeWeapon ?

edit: suggest change default puff to staffpuff (heretic) of punchpuff *hexen
pufftype = 'BulletPuff';

======================================

create ZSCRIPT.zs in your mod file:

Code: Select all

class HexenMeleeWeapon  : Weapon
{
 


    private action bool TryPunch(double angle, int damage, int power, int range, class<Actor> pufftype)
    {
        Class<Actor> pufftype;
        FTranslatedLineTarget t;

        double slope = AimLineAttack (angle, 2*range, t, 0., ALF_CHECK3D);
        if (t.linetarget != null)
        {
            LineAttack (angle, 2*range, slope, damage, 'Melee', pufftype, true, t);
            if (t.linetarget != null)
            {
                // The mass threshold has been changed to CommanderKeen's value which has been used most often for 'unmovable' stuff.
                if (t.linetarget.player != null || (t.linetarget.Mass < 10000000 && (t.linetarget.bIsMonster)))
                {
                    if (!t.linetarget.bDontThrust)
                    {
                        t.linetarget.Thrust(power, t.attackAngleFromSource);
                    }
                }
                AdjustPlayerAngle(t);
                return true;
            }
        }
        return false;
    }

    action void A_HexenPunch(int damage, int range = 0, class<Actor> pufftype = 'BulletPuff', sound hitsound = "", sound misssound = "")
    {
        if (player == null)
        {
            return;
        }

        if (range == 0)
        {
            range = DEFMELEERANGE;
        }

        if (pufftype == null)
        {
            pufftype = 'BulletPuff';
        }

        for (int i = 0; i < 16; i++)
        {
            if (TryPunch(angle + i*(45./16), damage, 2, range, pufftype) || TryPunch(angle - i*(45./16), damage, 2, range, pufftype))
            {
                // hit something           
                A_StartSound (hitsound, CHAN_WEAPON);
                return;
            }
        }

        A_StartSound (misssound, CHAN_WEAPON);
        double slope = AimLineAttack (angle, range, null, 0., ALF_CHECK3D);
        LineAttack (angle, range, slope, damage, 'Melee', pufftype, true);
    }
}
use A_hexenPunch in decorate weapon, but it need to inherit from HexenMeleeWeapon (yes, copy paste of wiki is necessary)

DECORATE:

Code: Select all

ACTOR Mace2 :HexenMeleeWeapon
{
  Weapon.SelectionOrder 1400
  Weapon.AmmoUse 1
  Weapon.AmmoGive1 50
  Weapon.YAdjust 15
  Weapon.AmmoType "MaceAmmo"
  Weapon.SisterWeapon "MacePowered"
  Inventory.PickupMessage "$TXT_WPNMACE"
  Tag "$TAG_MACE"

   
  States
  {
  Spawn:
    WMCE A -1
    Stop
  Ready:
    MACE A 1 A_WeaponReady
    Loop
  Deselect:
    MACE A 1 A_Lower
    Loop
  Select:
    MACE A 1 A_Raise
    Loop
  Fire:
   TNT1 A 0  A_JumpIfInventory("Backhand", 1, "BackSWING")
    MACE H 2    
	MACE I 2 
    MACE J 2 A_HEXENPUNCH(RANDOM(20,60))  //<<<<<<===================================================================HERE
    MACE KL 2
     
	TNT1 A 5 A_GiveInventory("Backhand", 1)
	TNT1 A 7 A_WeaponReady
	TNT1 A 1 A_TakeInventory("Backhand", 1)
	
	MACE A 1 Offset(0, 60)
    MACE A 1 Offset(0, 52)
    MACE A 1 Offset(0, 44)
    MACE A 1 Offset(0, 36)
    MACE A 1
	Goto ready


BackSWING:
		MACE M 2  Offset(0,8)     
		MACE N 2 A_PlaySound("WHOP")		
		MACE O 2 A_Custompunch(random(45, 85), 1, CPF_NORANDOMPUFFZ, "STAFFPuff", 110)
		MACE PQ 2
		
		TNT1 A 9 A_TakeInventory("Backhand", 1)
		TNT1 A 7 A_WeaponReady
		MACE A 1 Offset(0, 60) 
		MACE A 1 Offset(0, 52)
		MACE A 1 Offset(0, 44)
		MACE A 1 Offset(0, 36)
		MACE A 1

		Goto Ready
  }
}
User avatar
Player701
 
 
Posts: 1710
Joined: Wed May 13, 2009 3:15 am
Graphics Processor: nVidia with Vulkan support
Contact:

Re: [solved] emulate hexen arch melee attacks

Post by Player701 »

If you're using DECORATE, inheritance is likely the only option. With ZScript, you can use mixins. Simply add the keyword "mixin" to HexenMeleeWeapon so that it reads "mixin class HexenMeleeWeapon", and then in your actual weapon code, add this line:

Code: Select all

mixin HexenMeleeWeapon;
Then you will be able to call A_HexenPunch from your weapon code. Note that HexenMeleeWeapon is no longer a class, so you cannot inherit from it anymore.

Another ZScript-only solution is to implement the attack as a static method. You will then be able to call it from anywhere regardless of inheritance. However, this requires modifying the code so that the actor who initiates the attack is passed as an argument:

Code: Select all

class HexenMelee
{
    private static bool TryPunch(Actor originator, double angle, int damage, int power, int range, class<Actor> pufftype)
    {
        Class<Actor> pufftype;
        FTranslatedLineTarget t;

        double slope = originator.AimLineAttack (angle, 2*range, t, 0., ALF_CHECK3D);
        if (t.linetarget != null)
        {
            originator.LineAttack (angle, 2*range, slope, damage, 'Melee', pufftype, true, t);
            if (t.linetarget != null)
            {
                // The mass threshold has been changed to CommanderKeen's value which has been used most often for 'unmovable' stuff.
                if (t.linetarget.player != null || (t.linetarget.Mass < 10000000 && (t.linetarget.bIsMonster)))
                {
                    if (!t.linetarget.bDontThrust)
                    {
                        t.linetarget.Thrust(power, t.attackAngleFromSource);
                    }
                }
                originator.AdjustPlayerAngle(t);
                return true;
            }
        }
        return false;
    }

    static void A_HexenPunch(Actor originator, int damage, int range = 0, class<Actor> pufftype = 'StaffPuff', sound hitsound = "", sound misssound = "")
    {
        if (originator == null)
        {
            return;
        }

        if (range == 0)
        {
            range = DEFMELEERANGE;
        }

        if (pufftype == null)
        {
            pufftype = 'StaffPuff';
        }
        
        double ang = originator.Angle;

        for (int i = 0; i < 16; i++)
        {
            if (TryPunch(originator, ang + i*(45./16), damage, 2, range, pufftype) || TryPunch(originator, ang - i*(45./16), damage, 2, range, pufftype))
            {
                // hit something           
                originator.A_StartSound (hitsound, CHAN_WEAPON);
                return;
            }
        }

        originator.A_StartSound (misssound, CHAN_WEAPON);
        double slope = originator.AimLineAttack (ang, range, null, 0., ALF_CHECK3D);
        originator.LineAttack (ang, range, slope, damage, 'Melee', pufftype, true);
    }
}
To call this attack from your weapon code, use the following code:

Code: Select all

MACE J 2 { HexenMelee.A_HexenPunch(self, random(20, 60)); }
User avatar
neoworm
Posts: 1748
Joined: Fri Sep 23, 2005 9:17 am
Location: Czech Republic

Re: [solved] emulate hexen arch melee attacks

Post by neoworm »

I was already using generalized HeXen style melee attack before. Based on Cleric's mace instead of fighter's fist. I wanted to make variants that scan from center, from left and from right and a cleave variant that damages all enemies in the cone. But I didn't know that I could use Mixins to add these calls into other classes without inheritance. Time to rewrite the code. It will also be useful for adding my improved shields to other monsters without the need to redefine the whole creature with different parents just to inherit the right code.
User avatar
Lagi
Posts: 683
Joined: Sat Jun 23, 2018 12:51 pm
Location: Thou shalt alter thy beliefs with new evidence

Re: [solved] emulate hexen arch melee attacks

Post by Lagi »

can you give link to your improved centaur shield?
User avatar
neoworm
Posts: 1748
Joined: Fri Sep 23, 2005 9:17 am
Location: Czech Republic

Re: [solved] emulate hexen arch melee attacks

Post by neoworm »

Not done yet. The core is already working, but I still didn't create all the exceptions and have some problems with sounds. The code is still pretty messy too. If I have some time to work on it during weekend I will do some kind of release and ask people around to help me with reviewing it.
User avatar
Woolie Wool
Posts: 1713
Joined: Mon Dec 15, 2003 3:36 pm
Preferred Pronouns: He/Him
Operating System Version (Optional): Arch Linux, Windows 11
Graphics Processor: nVidia with Vulkan support
Contact:

Re: [solved] emulate hexen arch melee attacks

Post by Woolie Wool »

Player701 wrote:If you're using DECORATE, inheritance is likely the only option. With ZScript, you can use mixins. Simply add the keyword "mixin" to HexenMeleeWeapon so that it reads "mixin class HexenMeleeWeapon", and then in your actual weapon code, add this line:

Code: Select all

mixin HexenMeleeWeapon;
Then you will be able to call A_HexenPunch from your weapon code. Note that HexenMeleeWeapon is no longer a class, so you cannot inherit from it anymore.
This sounds awesome, but could you do a version of HexenMeleeWeapon that A_HexenPunch has the equivalent of CPF_USEAMMO, lifesteal, and lifestealmax?

Note I am working towards doing this myself, and I've already added useammo as a bool (and passed power from the base TryPunch function to A_HexenPunch as a parameter so I can customize that), but I'd like to see someone else do it so I can check my own work against someone who actually knows ZScript because I am totally new to ZScript or really any scripting more complex than DECORATE.
User avatar
Player701
 
 
Posts: 1710
Joined: Wed May 13, 2009 3:15 am
Graphics Processor: nVidia with Vulkan support
Contact:

Re: [solved] emulate hexen arch melee attacks

Post by Player701 »

Try this out:

Code: Select all

mixin class HexenMeleeWeapon
{
    private action bool TryPunch(double angle, int damage, int power, int range, class<Actor> pufftype, bool useammo, double lifesteal, int lifestealmax)
    {
        Class<Actor> pufftype;
        FTranslatedLineTarget t;

        double slope = AimLineAttack (angle, 2*range, t, 0., ALF_CHECK3D);
        if (t.linetarget != null)
        {
            // deplete ammo
            let weap = player.ReadyWeapon;

            if (useammo && weap != null && stateinfo != null && stateinfo.mStateType == STATE_Psprite)
            {
                if (!weap.DepleteAmmo(weap.bAltFire, true))
                {
                    // out of ammo
                    return true;
                }
            }

            Actor puff;
            int actualdamage;

            [puff, actualdamage] = LineAttack (angle, 2*range, slope, damage, 'Melee', pufftype, true, t);

            if (t.linetarget != null)
            {
                if (lifesteal > 0 && !t.linetarget.bDontDrain)
                {
                    GiveBody (int(actualdamage * lifesteal), lifestealmax);
                }

                // The mass threshold has been changed to CommanderKeen's value which has been used most often for 'unmovable' stuff.
                if (t.linetarget.player != null || (t.linetarget.Mass < 10000000 && (t.linetarget.bIsMonster)))
                {
                    if (!t.linetarget.bDontThrust)
                    {
                        t.linetarget.Thrust(power, t.attackAngleFromSource);
                    }
                }
                AdjustPlayerAngle(t);
                return true;
            }
        }
        return false;
    }

    action void A_HexenPunch(int damage, int range = 0, class<Actor> pufftype = 'BulletPuff', sound hitsound = "", sound misssound = "", bool useammo = false, double lifesteal = 0, int lifestealmax = 0)
    {
        if (player == null)
        {
            return;
        }

        if (range == 0)
        {
            range = DEFMELEERANGE;
        }

        if (pufftype == null)
        {
            pufftype = 'BulletPuff';
        }

        for (int i = 0; i < 16; i++)
        {
            if (TryPunch(angle + i*(45./16), damage, 2, range, pufftype, useammo, lifesteal, lifestealmax) || TryPunch(angle - i*(45./16), damage, 2, range, pufftype, useammo, lifesteal, lifestealmax))
            {
                // hit something           
                A_StartSound (hitsound, CHAN_WEAPON);
                return;
            }
        }

        A_StartSound (misssound, CHAN_WEAPON);
        double slope = AimLineAttack (angle, range, null, 0., ALF_CHECK3D);
        LineAttack (angle, range, slope, damage, 'Melee', pufftype, true);
    }
}
User avatar
Woolie Wool
Posts: 1713
Joined: Mon Dec 15, 2003 3:36 pm
Preferred Pronouns: He/Him
Operating System Version (Optional): Arch Linux, Windows 11
Graphics Processor: nVidia with Vulkan support
Contact:

Re: [solved] emulate hexen arch melee attacks

Post by Woolie Wool »

It's got everything I need except that its attacks don't respect +PUFFONACTORS like the existing melee attacks, which is a problem e.g. for Timon's Axe.
User avatar
Player701
 
 
Posts: 1710
Joined: Wed May 13, 2009 3:15 am
Graphics Processor: nVidia with Vulkan support
Contact:

Re: [solved] emulate hexen arch melee attacks

Post by Player701 »

Ouch. There's a typo in that code. Remove this line from TryPunch (right after the opening brace):

Code: Select all

Class<Actor> pufftype;
(Too bad the ZScript compiler doesn't report cases of uninitialized variable usage... perhaps I should try to implement it myself?)
User avatar
Woolie Wool
Posts: 1713
Joined: Mon Dec 15, 2003 3:36 pm
Preferred Pronouns: He/Him
Operating System Version (Optional): Arch Linux, Windows 11
Graphics Processor: nVidia with Vulkan support
Contact:

Re: [solved] emulate hexen arch melee attacks

Post by Woolie Wool »

Perfect! Thank you! :D
User avatar
Lagi
Posts: 683
Joined: Sat Jun 23, 2018 12:51 pm
Location: Thou shalt alter thy beliefs with new evidence

Re: [solved] emulate hexen arch melee attacks

Post by Lagi »

i think there is bug with attack range here:

Code: Select all

        double slope = AimLineAttack (angle, 2*range, t, 0., ALF_CHECK3D);
        if (t.linetarget != null)
        {
            LineAttack (angle, 2*range, slope, damage, 'Melee', pufftype, true, t);
            if (t.linetarget != null)
all weapons using hexenpunch are reach much further. So i remove this 2*range, and all seems to be more intact.

Code: Select all

        double slope = AimLineAttack (angle, range, t, 0., ALF_CHECK3D);
        if (t.linetarget != null)
        {
            LineAttack (angle, range, slope, damage, 'Melee', pufftype, true, t);
            if (t.linetarget != null)
User avatar
Player701
 
 
Posts: 1710
Joined: Wed May 13, 2009 3:15 am
Graphics Processor: nVidia with Vulkan support
Contact:

Re: [solved] emulate hexen arch melee attacks

Post by Player701 »

The default range for Hexen fist attack when it hits an object is 2*DEFMELEERANGE, and just DEFMELEERANGE otherwise. That code was taken directly from gzdoom.pk3 (I only replaced the DEFMELEERANGE constant with an argument), but you're of course free to adjust the values to your own liking. :)
Post Reply

Return to “Scripting”