A_HeadAttack (and similar) [Solved]
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!)
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!)
A_HeadAttack (and similar) [Solved]
I am converting the (awesome) Enhanced Cacodemon (by Tormentor and SandyPaper) to ZScript (for myself), and I wanted to modify her to include a Melee state, which she surprisingly lacks. I thought I would just copy and paste the original Cacodemon's melee state to her to keep them similar, but she lacks an actual melee state, and instead has an Extend Class to include a A_HeadAttack (as well as both the Imp and Baron with their own respective Extend Class). However, when I tested it, I received an error about "Class actor cannot be found in the current translation unit." So I thought it would be better to simply use A_CustomMeleeAttack instead.
My question is this: Is there any real difference between the "Extend Class" type melee attack, and a Melee state with A_CustomMeleeAttack, and what is it if there is? I would like to understand more about it, even if I just go with the easier option. Does the original monster's extend class not work on custom, or is it because it's double defined, perhaps? Jus' anything on the subject would be helpful and greatly appreciated.
My question is this: Is there any real difference between the "Extend Class" type melee attack, and a Melee state with A_CustomMeleeAttack, and what is it if there is? I would like to understand more about it, even if I just go with the easier option. Does the original monster's extend class not work on custom, or is it because it's double defined, perhaps? Jus' anything on the subject would be helpful and greatly appreciated.
Last edited by Misery on Sat Dec 19, 2020 6:55 am, edited 1 time in total.
- Arctangent
- Posts: 1235
- Joined: Thu Nov 06, 2014 1:53 pm
- Contact:
Re: A_HeadAttack (and similar)
A_HeadAttack is accessible to all actors by default to begin with. That's why the Cacodemon definition extends the function to Actor to begin with, instead of just defining it for itself - it's effectively just a way to organize things by having functions related to a particular actor be defined with that actor, instead of including 'em with the standard Actor definition.
And, yes, the attacks of the imp, cacodemon, and hell nobles are completely different from attacks that are just melee attacks, because they're used for both melee and projectile attacks. The way they work is that they check if the attacker's target is in melee range, and if so, deals melee damage to it. Otherwise, they launch a projectile. That's why the cacodemon is able to use a melee attack despite not having a Melee state - it's actually completely unable to initiate a melee attack by normal means ( you can see this by how most monsters with a melee attack will use it continuously while in range, but a cacodemon will wander around for a bit before trying to bite again ) but since it uses a "combo" attack instead of a dedicated projectile attack like the cyberdemon or revenant, you can still end up taking melee damage from it.
And, yes, the attacks of the imp, cacodemon, and hell nobles are completely different from attacks that are just melee attacks, because they're used for both melee and projectile attacks. The way they work is that they check if the attacker's target is in melee range, and if so, deals melee damage to it. Otherwise, they launch a projectile. That's why the cacodemon is able to use a melee attack despite not having a Melee state - it's actually completely unable to initiate a melee attack by normal means ( you can see this by how most monsters with a melee attack will use it continuously while in range, but a cacodemon will wander around for a bit before trying to bite again ) but since it uses a "combo" attack instead of a dedicated projectile attack like the cyberdemon or revenant, you can still end up taking melee damage from it.
Re: A_HeadAttack (and similar)
So I need only use it like any other function? And how do I include a MeleeSound? Do I place it in it's Default block? I know the Cacodemon used to use the Imp's melee sound, but it lacks it now.Arctangent wrote:A_HeadAttack is accessible to all actors by default to begin with.
Code: Select all
Melee:
ENCD BC 8 A_FaceTarget();
ENCD A 8 Bright A_HeadAttack();
Goto See;
- Player701
-
- Posts: 1710
- Joined: Wed May 13, 2009 3:15 am
- Graphics Processor: nVidia with Vulkan support
- Contact:
Re: A_HeadAttack (and similar)
It looks like A_HeadAttack uses AttackSound instead of MeleeSound in melee range. This may or may not be a bug. And yes, you define sounds in the Default block like every other actor property.
- Arctangent
- Posts: 1235
- Joined: Thu Nov 06, 2014 1:53 pm
- Contact:
Re: A_HeadAttack (and similar)
If there's a bug, it's that the function can make a sound at all. Cacodemons are the one enemy type that don't make a sound at melee range, so the fact that you can define one for it using AttackSound is wholly a ZDoom extension. Or an oversight.
Re: A_HeadAttack (and similar)
Using MeleeSound in the Default block for the Cacodemon didn't work, but it did work when I replaced AttackSound with "imp/melee" in the A_HeadAttack block. But using the whole thing for the Enhanced Cacodemon may not work the same, because she throws three projectiles, and not just one. So I need to create my own Extend Class attack for it, like an A_EnhancedHeadAttack. But it says Spawn Missile instead of an A_ function, so I don't know how that one works.
- Player701
-
- Posts: 1710
- Joined: Wed May 13, 2009 3:15 am
- Graphics Processor: nVidia with Vulkan support
- Contact:
Re: A_HeadAttack (and similar)
Well, cacodemon does not have an AttackSound defined by default, so without any mods it works just like it's supposed to be.Arctangent wrote:If there's a bug, it's that the function can make a sound at all. Cacodemons are the one enemy type that don't make a sound at melee range, so the fact that you can define one for it using AttackSound is wholly a ZDoom extension. Or an oversight.
Also see the wiki article for A_HeadAttack:
It seems to me that if there is a bug, it's that it uses AttackSound and not MeleeSound.ZDoom Wiki wrote:The behavior of this function can be replicated by the use of A_CustomComboAttack in the following manner:
Note that the cacodemon doesn't come with a melee sound. Hence, the sound omission from the line above, though it can be added very easily if provided.Code: Select all
A_CustomComboAttack("CacodemonBall", 32, 10 * random(1, 6))
Re: A_HeadAttack (and similar)
I fixed the issue with the MeleeSound. I simply replaced AttackSound with "imp/melee" which it originally did a long time ago.Player701 wrote:ZDoom Wiki wrote:The behavior of this function can be replicated by the use of A_CustomComboAttack in the following manner:
Note that the cacodemon doesn't come with a melee sound. Hence, the sound omission from the line above, though it can be added very easily if provided.Code: Select all
A_CustomComboAttack("CacodemonBall", 32, 10 * random(1, 6))
As for A_CustomMeleeAttack, it does not replicate the behavior. I tried. The Enhanced Cacodemon stayed in melee range and repeatedly attack, while the Cacodemon only melee attacked once, then floated away like normal. That's the behavior I am trying to replicate.
So I think what I need is one of two things. Either I keep A_HeadAttack and keep its SpawnMissile, and simply redefine a new CacodemonBall, and use that. Or I can use SpawnMissileAngleZ for the A_EnhancedHeadAttack, but I don't understand it's parameters (double z, class<Actor> type, double angle, double vz), 'cause I don't understand why it says "double". I tried looking up an example, but I haven't found one.
- Player701
-
- Posts: 1710
- Joined: Wed May 13, 2009 3:15 am
- Graphics Processor: nVidia with Vulkan support
- Contact:
Re: A_HeadAttack (and similar)
This is because the vanilla cacodemon does not have a Melee state defined. For the same reason, it will not attack you immediately when you enter melee range, unlike other monsters that do have proper melee attacks (like the imp). If you put your combo attack in the Missile state and remove the Melee state entirely, it should work like the original cacodemon.Misery wrote:Player701 wrote:The Enhanced Cacodemon stayed in melee range and repeatedly attack, while the Cacodemon only melee attacked once, then floated away like normal. That's the behavior I am trying to replicate.
Re: A_HeadAttack (and similar)
Player701 wrote:If you put your combo attack in the Missile state and remove the Melee state entirely, it should work like the original cacodemon.
Code: Select all
Missile:
ENCD BC 5 A_FaceTarget();
ENCD B 5 Bright
{
if (CheckMeleeRange())
{
A_CustomMeleeAttack (4 * Random (3, 12), "imp/melee");
}
else
{
A_SpawnProjectile ("CacodemonBall", 24, 0, 8, 1);
A_SpawnProjectile ("CacodemonBall", 24, 0, 0, 1);
A_SpawnProjectile ("CacodemonBall", 24, 0, -8, 1);
}
}
Goto See;
- Player701
-
- Posts: 1710
- Joined: Wed May 13, 2009 3:15 am
- Graphics Processor: nVidia with Vulkan support
- Contact:
Re: A_HeadAttack (and similar)
Not quite. You should only launch cacodemon balls when the target is NOT in melee range. Something like this, I think:
Code: Select all
class MyCacodemon : Cacodemon
{
States
{
Missile:
HEAD BC 5 A_FaceTarget;
HEAD D 5 Bright A_MyCacodemonAttack;
Goto See;
}
void A_MyCacodemonAttack()
{
if (Target == null)
{
return;
}
if (CheckMeleeRange())
{
A_CustomMeleeAttack (4 * Random (3, 12), "imp/melee");
}
else
{
A_SpawnProjectile ("CacodemonBall", 24, 0, 8, 1);
A_SpawnProjectile ("CacodemonBall", 24, 0, 0, 1);
A_SpawnProjectile ("CacodemonBall", 24, 0, -8, 1);
}
}
}
Re: A_HeadAttack (and similar)
Oh, I see. I can't define it within the Actor state. So I have to define a new attack, and use it. Pretty much what I was trying to do with A_HeadAttack, but it didn't work. Wasn't a virtual function, or somethin'. This is hard, but totally fun.
Edit: Yes, fantastic. It totally works. Thanks a bunch.
Edit: Yes, fantastic. It totally works. Thanks a bunch.
Last edited by Misery on Sat Dec 19, 2020 6:55 am, edited 1 time in total.
- Player701
-
- Posts: 1710
- Joined: Wed May 13, 2009 3:15 am
- Graphics Processor: nVidia with Vulkan support
- Contact:
Re: A_HeadAttack (and similar)
You can. I've written my example code that way to separate the actual ZScript code from the states block. This approach also allows you to reuse the attack anywhere else in your class (and subclasses) without copy-pasting the code each time. But it doesn't mean you have to define a separate function for your attack if you don't want to.Misery wrote:Oh, I see. I can't define it within the Actor state.
Code: Select all
class MyCacodemon : Cacodemon
{
States
{
Missile:
HEAD BC 5 A_FaceTarget;
HEAD D 5 Bright
{
if (!Target)
{
return;
}
if (CheckMeleeRange())
{
A_CustomMeleeAttack (4 * Random (3, 12), "imp/melee");
}
else
{
A_SpawnProjectile ("CacodemonBall", 24, 0, 8, 1);
A_SpawnProjectile ("CacodemonBall", 24, 0, 0, 1);
A_SpawnProjectile ("CacodemonBall", 24, 0, -8, 1);
}
}
Goto See;
}
}
Re: A_HeadAttack (and similar)
Well, either way it works great. Just like a regular Cacodemon. I spawn 'em both to test it. Thanks.