Creating a custom weapon state sequence

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!)
milkFiend
Posts: 27
Joined: Tue Nov 21, 2023 10:30 pm
Preferred Pronouns: No Preference
Operating System Version (Optional): Windows 11
Graphics Processor: Intel (Modern GZDoom)

Creating a custom weapon state sequence

Post by milkFiend »

To be more specific, I'm trying to add a "Throw:" state sequence to a weapon to play the corresponding animation and go through the state logic.
Ideally, this state would be triggered via keypress, similar to other player controls like "+attack" (although I'm not sure the '+' is needed here, as the state will play once and remove the weapon).
Would I have to add an event handler for this? Would I still be able to make the key bind customizable to the player?

Apologies if this is documented more elsewhere, I've been doing my best to look for resources.
User avatar
Player701
 
 
Posts: 1693
Joined: Wed May 13, 2009 3:15 am
Graphics Processor: nVidia with Vulkan support

Re: Creating a custom weapon state sequence

Post by Player701 »

A_WeaponReady supports up to four custom state sequences activated by the corresponding keys in the controls menu called "Weapon state 1" to "Weapon state 4" respectively. You can find them in "Options" -> "Customize controls" -> "Weapons". The only limitation here is that your states can only be called User1, User2 etc., but nothing prevents you from adding multiple state labels if necessary:

Code: Select all

class MyWeapon : Weapon
{
    ...

    States
    {
        ...
        Ready:
           WEAP A 1 A_WeaponReady(WRF_ALLOWUSER1);
            Loop;           
        User1:
        Throw:
            ...
    }
}
If you want to avoid using generic state labels and controls, you can also do it via an event that sets the weapon state manually. Note that this event will forcibly switch the current state from Ready to Throw regardless of any flags passed to A_WeaponReady, which in this case you don't even need to call. It also checks that the relevant states actually exist so it won't crash.

Code: Select all

version "4.13"

class ThrowEventHandler : EventHandler
{
    override void NetworkProcess(ConsoleEvent e)
    {
        if (e.Name ~== "throw")
        {
            let player = players[e.Player];

            let weap = player.ReadyWeapon;
            let psp = player.GetPSprite(PSP_WEAPON);

            if (weap != null && psp != null && psp.CurState != null)
            {
                let readyState = weap.FindState("Ready");
                let throwState = weap.FindState("Throw");

                if (readyState != null && throwState != null && psp.CurState.InStateSequence(readyState))
                {
                    player.SetPSprite(PSP_WEAPON, throwState);
                }
            }
        }
    }
}
milkFiend
Posts: 27
Joined: Tue Nov 21, 2023 10:30 pm
Preferred Pronouns: No Preference
Operating System Version (Optional): Windows 11
Graphics Processor: Intel (Modern GZDoom)

Re: Creating a custom weapon state sequence

Post by milkFiend »

Player701 wrote: Tue Nov 26, 2024 2:57 am A_WeaponReady supports up to four custom state sequences activated by the corresponding keys in the controls menu called "Weapon state 1" to "Weapon state 4" respectively. You can find them in "Options" -> "Customize controls" -> "Weapons". The only limitation here is that your states can only be called User1, User2 etc., but nothing prevents you from adding multiple state labels if necessary:

Code: Select all

class MyWeapon : Weapon
{
    ...

    States
    {
        ...
        Ready:
           WEAP A 1 A_WeaponReady(WRF_ALLOWUSER1);
            Loop;           
        User1:
        Throw:
            ...
    }
}
If you want to avoid using generic state labels and controls, you can also do it via an event that sets the weapon state manually. Note that this event will forcibly switch the current state from Ready to Throw regardless of any flags passed to A_WeaponReady, which in this case you don't even need to call. It also checks that the relevant states actually exist so it won't crash.

Code: Select all

version "4.13"

class ThrowEventHandler : EventHandler
{
    override void NetworkProcess(ConsoleEvent e)
    {
        if (e.Name ~== "throw")
        {
            let player = players[e.Player];

            let weap = player.ReadyWeapon;
            let psp = player.GetPSprite(PSP_WEAPON);

            if (weap != null && psp != null && psp.CurState != null)
            {
                let readyState = weap.FindState("Ready");
                let throwState = weap.FindState("Throw");

                if (readyState != null && throwState != null && psp.CurState.InStateSequence(readyState))
                {
                    player.SetPSprite(PSP_WEAPON, throwState);
                }
            }
        }
    }
}
damn, I tried using "user1" earlier and didn't even realize that I left out the "WRF_ALLOWUSER1" flag lol so I'll likely use that for now until I understand event handlers better
but thank you! :D now I can see those beautiful animations

Return to “Scripting”