Welcome back.
So we have some eye movement.
We have our ranged attackers coming in, not so close.
And our melee attackers coming in a little closer.
And we see based on our red debug spheres, that they are trying to attack.
Our attack behavior tree task is being executed, but all it does is show that red sphere.
So we want some actual gameplay abilities for our enemies to attack.
So we're going to begin with the melee attack.
The melee attack is a little bit less complex than the ranged attackers attack.
So we'll start with that.
And in order to do that, I'd like to make a gameplay ability specifically for melee attacks.
So we're going to create a new C plus plus class for that.
I'm going to go to C plus plus classes or a public ability system abilities.
And our melee gameplay ability is going to cause damage.
Of course.
So it's going to be based on aura damage, gameplay ability.
So even though this is based on aura damage gameplay ability, which in turn is based on aura gameplay
ability, don't think of these as abilities specific to aura character.
These are base classes for the project Aura.
Remember the project itself is called Aura in my case.
So our enemies will be using this ability that we create.
Now.
It's going to be a damage gameplay ability, so it has a damage scalable float that we can use.
So we're going to create a C plus plus class based on aura damage gameplay ability.
It's going to go straight into abilities and we're going to call this aura melee ability.
So this will be the melee attack.
In fact, we can call this melee attack.
You could even call it melee spell, but it's not really magic.
So melee attack It is.
Let's create the class.
Let's close the editor.
And now we have an aura melee attack class.
I'm going to close all tabs, open up aura, melee attack.
And here it is.
Here's the CPP file.
Now I'd like a gameplay tag associated with attacking.
That's just going to make things a lot easier in the gas system as you can give these specific abilities,
the attack tag and do all kinds of things with that information.
You can even activate abilities by tag as we've seen.
So I'm going to add a new gameplay tag to our native tags.
That's an aura gameplay tags.
And what I'd like to do is have an abilities sub tag or parent tag.
So we're going to have F gameplay tag abilities underscore attack.
So we'll just have abilities attack.
If we need to distinguish between different kinds of attacks, we can have abilities, attack, melee
abilities, attack, ranged abilities, attack spell and so on.
For now, we're just going to have the attack tag and I'm going to go ahead and define this in the CPP
file or a gameplay tags dot CPP.
Let's go ahead and do that.
So just down here at the bottom, I'm going to copy the effects with the comment and everything.
We're going to paste it and I'm just going to have abilities here.
And the first one will be abilities attack.
So the name will be abilities dot attack and the F string will be attack ability tag.
So we have a new gameplay tag called Abilities Attack.
Great.
And we also have an aura melee attack.
Also.
Great.
Now we're going to need a way for our enemies to be granted the melee ability.
Well, not all of them, right?
Some of the enemies are going to need melee abilities.
Some of them are going to need ranged attacks and others still might need spells.
So it depends on the class.
But we have a class for the character default info, default abilities and such.
That's going to be in the ability system data.
And we have this data asset called character class info.
Here's where we decide what each character class is supposed to start with.
Now we have this character class default info struct and we have a team map mapping the character class
to that struct.
So whatever's in this struct, we can set those default properties for each class individually.
And then of course each character class type has common class defaults.
That's the common abilities, vital and secondary attributes and so on.
But if we want each character class to have its own unique set of either abilities or gameplay effects
that would go into character class default info and we can set those individually per character class.
So what I'd like here is a set of abilities that each character class should start the game with by
default, and this should be an array of gameplay abilities as they may need more than one.
So we're going to have a t array of t sub class of gameplay abilities, just like common abilities here.
I'm going to go ahead and just copy that t array declaration and paste it up here and character class
default info.
And this is going to be in the category of class defaults rather than common class defaults and it's
going to be edit defaults only.
It's a t array of t sub class of gameplay abilities.
It's called common abilities and it's up to us to fill in those common abilities for each given class.
Now that doesn't mean they're going to be just granted this set of abilities by default.
That's something that we have to do ourselves and we could do that.
We can easily see an example of how it's done by seeing how the common abilities are granted.
So where are we granting those common abilities anyway?
Let's take a look at our blueprint function library.
Where did we put that?
Well, it's Aura ability system library, and we have our give startup abilities here, which takes
in a world context object, an ability system component.
Let's go to the CPP file and see that give startup abilities function and here it is.
So give startup abilities is going to get the character class info data asset and that exists on the
game mode.
So it's getting it from the game mode using get character class info and then it's looping through each
class and common abilities.
So this is handling the common startup abilities, right?
But it'd be nice if this function just automatically handles giving those class specific abilities as
well.
Now how would it manage to do that?
It would have to know what the character class is for a given character.
So if we could change this function to take in the enum for the character class, then it could look
up that character class in the map and get those class specific gameplay abilities and give those as
well.
So I think that's what I'd like this function to do.
I'd like it to be smart enough to do that.
So we're going to have to give this give startup abilities a input for the enum.
So going back into the header file for our Ability System library, we're going to need to add that
enum and that enum is defined in character class info dot h.
Which means.
We're going to need to make sure that that is an include here, which it is in our ability system library
header file, so we can use that enum.
In fact, we're using it here in initialize default attributes.
We're going to do that here now and give startup abilities.
Let's go ahead and just add that as an input parameter.
We'll make it the last one.
So if we're going to add it to the function declaration, we must add it to the function definition
in the CPP file right here.
Now before we go and implement the functionality here, we need to change everywhere we're calling this
function.
We need to make sure to pass in that enum value.
So the easiest way to find out where we need to change our code is to compile our code because we'll
get some nice compiler errors telling us exactly where we're calling this function and not passing in
enough inputs.
Right here we're seeing it's in Ora enemy CPP.
Line 82 says this function does not take two arguments.
We can double click on that and go straight to the violation.
So here we're calling give startup abilities, right?
And our Ora enemy has its own character class enum, doesn't it?
If we go to the header file for Ora Enemy and search for character class, here we have character class.
So we have access to that right here in the enemy class.
I'm going to close the header file and we're just going to pass that in for the third input parameter
character class.
And that's going to satisfy give startup abilities.
If I compile once again, then that should get rid of that compiler error.
So that handles any errors that we created.
By adding that input to give startup abilities, we see that we're only calling this once in Beginplay
for the Ora enemy.
We're not using this for our player controlled character.
For that, we're using the abilities that we've set on the character blueprint itself.
But for this, for enemies, we're going to get those abilities from character class info, the data
asset.
So now we need to make sure to give those abilities here and give startup abilities in Ora Ability System
Library.
So how are we going to do that?
Well, we have character, class info and character class info has the t map mapping from the E character
class to a specific struct that contains those default abilities for the specific class.
Right?
So what we're going to do is access character class info.
And we have a function that can give us the class default info for a given character class type.
So if we call get class default info, we can pass in that character class.
Now this is going to return us that f character class default info struct.
So let's store that in a local variable, but I'm going to make it a const reference.
So f character class default info const reference.
I'm going to call this default info.
Now give startup abilities as we know could have a null pointer for get character class info as this
is only valid on the server.
So I'm going to say if character class info is a null pointer, we're going to return early and now
that we have the default info, we know that there's an array of gameplay abilities in here, so we're
going to loop through that.
We're going to loop through, we're going to say first auto ability class in default info dot and it
looks like I call this common abilities.
Did I call it common abilities?
Let's go to character class info into that struct and yes, I called it common abilities.
This is not actually common abilities, right?
This is abilities specific to the given class.
So really I think this should be called either just abilities or start up abilities.
I'm going to call it startup abilities.
And go back to our ability system Blueprint Library.
And we should now see start up abilities.
Now I know that Ability class is a subclass of gameplay ability, so I'm going to go ahead and change
it from auto to this.
And now we have our ability class.
We just need to give the startup ability.
Now here's the thing.
We can create an ability spec at level one, just like we did before, but these are going to be things
like attack abilities and so on.
So it's possible that we might want to start these enemies off with abilities of different levels.
And if that's the case, we are going to want to know what the level is for our enemy.
So just something to think about.
We may want to access the player level from our character and we know that our character, our enemy
itself does implement an interface.
We know that it also implements the combat interface.
That's thanks to the base character class inheriting from combat interface as well.
I Combat interface.
Okay.
Closing Aura Character Base Closing Aura Enemy.
Let's go really quick to combat interface.
And we can see that we have a jet player level so we can easily get the player level if we can get the
actual character.
Okay.
Closing combat interface back to Aura Ability System Library, CP.
So how do we get that character associated with a given ability system component?
Well, we have the ASC so we can get the ASC and we know that we can get the Avatar actor.
So get Avatar, here's the Avatar actor And if we cast this to the combat interface, then we can get
its level.
So we're going to cast it to a combat interface.
Now the header was automatically included, so make sure you include the header if you're not using
writers, auto include.
So we're going to cast an eye combat interface.
We're going to store that in an eye combat interface pointer called Combat interface.
Now that we have the combat interface, we're going to say if combat interface, then we know combat
interface get player level, we can call get player level.
And we know that we now have the level for the character.
Now if we create an ability spec, we can set it to that level.
So I'm going to copy this line where we're making our ability spec, I'm going to make an ability spec,
but instead of just hard coding one, I'm now going to pass in player level.
Now, I'm not really concerned with the level for the common abilities as these are things that will
not really change based on level, at least by my design.
These are things like hit, react and death.
When we make that one, these are going to be the same for all levels.
We're not going to level up those abilities.
If you plan on changing the levels and changing behavior based on level, you may wish to pass something
in other than one here.
But for my start up abilities per class, I'm going to pass in the character's level just so those specific
abilities, which will be things like attacks, can potentially get stronger if we're spawning in an
enemy at a higher level.
Okay, so now that we have the ability spec, the last thing to do here is to give the ability that's
using this line here, ask, give ability.
And now our enemy should be given all abilities in its array of start up abilities.
Now, Ryder's going to tell us that the combat interface can be moved inside the if statement if we
want.
So just an option.
If you want to do that, you could cut it and paste it here.
That's up to you.
But now we have our start up abilities given to our enemies.
Now what's the easiest way to test out that this is working?
Well, that would be to try to activate the ability, right?
As we know, give startup abilities is being called already.
So why don't we compile and launch the editor and see if we can really quickly test this out to make
sure that our enemies are getting some start up abilities.
Okay.
So back in the editor, I know that I have a new Cplusplus class called Aura Melee Attack.
I'd like to make a blueprint based on this ability specifically for my goblin.
So I'm going to go to blueprints, I'm going to go to Ability System and I'm just going to go into gameplay
abilities and make an ability right here next to these other two.
So I'm going to choose New Blueprint class and choose Aura.
Melee.
Attack.
We're going to make a blueprint based on that.
And this is going to be a underscore.
And this can be goblin spear attack.
So opening goblin spear attack.
Here we have our goblin spear attack.
Now, here's the thing.
We know that we can activate abilities by tag, right?
That's how we're activating our hit react.
If we go to hit React, it has a tag in its ability tags effects.
Hit react.
If it has a tag in its ability tags, it can be activated by tag.
We're going to add our newly created attack tag to our ability tags.
So opening the dropdown, we're going to go to Abilities Attack and make sure that we have the attack
tag.
Now that we have that, we know that we can activate this ability by tag.
Okay, that's good.
We also want our goblin, or at least our warrior class to be given this goblin spear attack.
In fact, I don't think I want this to be specific to the Goblin.
I want it to be specific to the warrior class.
So what I'm going to do is actually call this G a underscore.
We'll just call it melee attack.
So this will be something we can call for anything that wants to use a melee attack.
Now, let's add this to the character class defaults.
That's going to be in blueprints, ability system data.
And we have character class info.
And notice that our map now has an additional array in each of these structs.
For the warrior, we have startup abilities and we're going to add one to it and we're going to select
from the dropdown our new Gar melee attack.
So only the Warriors are going to get this melee attack.
So now that our Goblin Spear should be granted this ability, we now need to try to activate it and
see if it actually gets activated.
And one way we can do that is from our behavior tree task.
So if we go to blueprints I tasks BT attack instead of drawing a debug sphere here, we don't want to
do that anymore.
Instead, we're going to try to activate the ability with the attack tag.
How do we do that?
Well, we need to get the ability system component.
We know that we get the controlled pawn here.
So from the controlled pawn we can call get ability system component as this is the blueprint library
function ability system, blueprint library.
So if we have this ability system component, we can try to activate an ability by tag, we can say
activate.
Abilities by tag.
It's actually try activate abilities by tag.
This requires a gameplay tag container.
So what we can do is make a gameplay tag container by dragging off of gameplay tag container and we
have to make one from an array.
So we're going to choose make gameplay tag container from array and we can make an array from a gameplay
tag.
I'd like to make this gameplay tag an actual member variable on BT attack.
So we're going to make a variable.
We're going to call this attack tag.
We're going to change it to gameplay tag.
We're going to compile and give this a default value and it's going to be abilities attack.
And then we're going to take that attack tag, get it, and we're going to hook it in here.
That's going to give us an automatic make array that will make us a gameplay tag container from that
array.
And we can pass that into try activate abilities by tag.
And in fact, we don't have to make this from an array we can drag off of attack tag and make gameplay
tag container from tag.
This skips that intermediate step of the array.
This is a little bit cleaner and we can hook up that gameplay tag container.
So here our behavior tree task is now going to attempt to activate abilities by tag.
And this is great because we can have all sorts of different gameplay abilities on our enemies and if
they have that attack tag, then it doesn't matter what gameplay ability it is as long as it has the
attack tag.
So we're going to try activate abilities by tag in our task now and we can just check to make sure this
is working in our melee attack by simply drawing a debug sphere at the location of the enemy.
So I'm going to draw debug sphere here.
I'm going to make it a red debug sphere.
I'm going to give it a radius of 40 and the center will be at the Avatar actor that owns this melee
attack ability.
How do we get that?
Well, we can type get avatar and we have get Avatar actor from actor info.
All we need to do is get its actor location.
So get actor location from it and hook that into the center of our debug sphere.
I'm going to give it a duration of 0.5 seconds really quick and we're going to activate the ability,
draw the debug sphere and deactivate or end the ability immediately.
Perfect.
And we can even go to our class defaults and we can set our instancing policy to instance per actor.
That way we don't instance this once each execution, but only once and then reuse the same ability.
Okay, so if all is well, we should see the same behavior.
We're still just drawing a debug sphere.
Let's make the debug sphere a different color just so we can see that this is no longer the debug sphere
drawn from our behavior tree task attack.
That's not happening anymore.
Now our behavior tree task is activating an ability by tag.
And our melee attack is drawing the debug sphere.
So saving all.
Let's see what happens.
If we press play, we should only see something happen.
Now, if it's our melee.
And look at that.
Our melee character is attacking.
And we know that this is because of a gameplay ability.
Now, it's not just from the behavior tree task.
So the behavior tree is actually activating a gameplay ability in the gas system.
So we've made the link between behavior tree and gameplay ability system.
Beautiful.
This is great.
This is a very good sign.
Now we don't have any attack abilities for our ranged attackers yet.
We'll get to that, don't worry.
But for now we know that our melee attack is working.
It's now time to start doing things in our melee attack other than drawing just debug shapes.
Right.
And this is also great because we have our system set up so that Ranger Warrior and Elementalist can
each get their own unique attack abilities or really any abilities that we want to give them.
And we know that if those are attack abilities and they all have their ability tags container containing
the abilities attack gameplay tag, then we can activate that ability just by specifying attack.
And no matter what kind of character it is, whether it's a ranger, an Elementalist or a warrior,
it will execute any and all abilities that it contains with the attack tag.
Perfect.
So this is a great stopping point.
Excellent job.
Save your work and I'll see you in the next video.