Welcome back.
In this video, we're going to start making our spell menu.
Buttons actually work.
We're going to start with spending spell points.
Now, if we level up, we're going to get a spell point.
And as soon as we do when we have a spell globe selected, depending on its status, we should be able
to spend a spell point.
The button should be enabled if it's an equipped spell.
In the case of our firebolt, we should be able to click spend point.
We should see the spell points go down by one and our ability should level up.
It should go up to the next level.
Now I also want to show in the description box what the current level is of whatever ability we have
selected as long as it's not a locked ability.
So in the case of our equipped ability, I want to see what its level is here along with the description,
and I'd like to see the description for the next level in this box down here.
Now, if I were to say click on an eligible ability, then I should be able to spend a point on it to
unlock it, and then it should now be in the unlocked state.
It should be colorful, not grayed out as this one is, and then I should be able to equip it with the
equip button.
So we should see the equip button become active.
So that's a lot of things.
We're going to take this all one step at a time.
In this video, I'd like to handle actually being able to spend a spell point.
So if I click the spend point button, then depending on which ability we have selected, I want to
use up one of my spell points and upgrade it if it's in the equipped state, actually equipped or unlocked.
But if it's eligible, I want to upgrade its status to unlocked.
So that's what I'd like to handle in this video.
So we're going to close the editor and we'll start by creating a function we can call when we attempt
to spend a spell point.
So we'll make a blueprint callable function here.
I'm going to keep my ability system component open right there, but we're going to make a blueprint
callable function for pressing the spawn point button.
So I'm going to make a void function called spend point button pressed.
And it'll be blueprint callable and we can generate a definition for it.
It's not going to take any inputs.
If we click the spawn point button, then all I really want to do is pass that information along to
the ability system component and tell it what our currently selected ability is.
So I'm going to make a function on the ability system component.
But here's the thing.
We might be on a client and things like spending points is something that should be managed on the server.
So in the ability system component class, I'm going to make a new function we can call, it'll be public,
but it's going to be a server RPC, so that way it'll be only executed on the server.
So we're going to make a void function called server spent point and we'll call it actually server spend
spell point.
So we know what we're talking about.
Now server spend spell point needs to receive the gameplay tag.
We'll pass it in by const reference.
So a const gameplay tag reference and it needs to know the ability.
So it's going to be the ability tag.
And this is going to be a new function with server and reliable so we can go ahead and generate this
RPC function definition.
And server spin point is going to need to perform a few checks so we know the ability tag.
We need to know the status of the ability we're trying to spend a point on.
Now, in order to get the status it needs to be an ability in our activatable abilities.
Otherwise, if we try to get the spec from the ability tag, we'll get a null pointer.
In other words, if we call get spec from ability tag passing in that ability tag this returns a pointer
that could be a null pointer, right?
So what we can do is we can make an gameplay ability spec pointer for gameplay ability spec, we can
call this ability spec and we can check to see if it's a null pointer.
In fact, we could just place this in an if statement.
Because if we don't get inside this if statement, then we know that this game playability does not
exist in activatable abilities, which is just as good as locked.
And if it's locked, we can't spend a spell point on it, so we shouldn't do anything.
Now, if we have a valid ability spec, we know that we can get the status from the ability spec so
we can make an gameplay tag called status and set it equal to the result from get status from spec passing
in the ability spec we have to dereference it, but we know it's not a null pointer at this point.
So we have our status.
So at this point, we know that this ability spec is in our activatable abilities, which means it's
not a locked ability, it's at least unlocked, eligible or equipped.
So for that reason we can check its status and see if it's eligible or equipped or unlocked.
Now we have two major scenarios.
One of them is if our status is eligible, we're going to say if status Dot matches tag exact, and
we're going to see if it matches for a gameplay.
Tags get dot abilities status eligible.
Why is that one of the major scenarios?
Well, if it's eligible and we're wanting to spend a point on it, it should now become unlocked.
That's going to be a major change.
Right now we're going to be using our gameplay tags multiple times.
So I'm going to just make an const for a gameplay tags here called Gameplay tags.
And we'll use gameplay tags.
So if eligible, we have to change the status.
We're also going to have an else if here, and that's going to be when our status dot matches tag exact
the equipped status.
So we're going to say gameplay tags.
Abilities.
Status.
Equipped.
But we're going to have an oar here because we're going to do the same thing if it's equipped as if
it's unlocked.
So we're going to say status.
That match is tag exact.
Gameplay tags.
Dot ability status unlocked.
Why are we doing the same thing if it's equipped or unlocked?
Because either way, we're just leveling up the ability.
We're going to increase the ability level.
So let's handle the first case.
If the status is eligible, if the ability is eligible, then we can now change its status from eligible
to unlocked.
Now, how is status actually managed?
Well, it's managed in the dynamic ability tags.
We can see that if we look at git status from spec.
Let's see if we can find that.
Here it is.
Here's git status from RSpec.
What we do is we take that spec and we loop through its dynamic ability tags.
And if we find one that has abilities dot status in it, we return that.
So dynamic ability tags contains the status tag and we do need to make sure that there's only one status
tag for any spec at a time.
So if we're going to change this ability spec to have the unlocked status instead of eligible, then
we need to remove the eligible tag.
So what we'll do is we'll take the ability spec which we know is a valid pointer and we'll get its dynamic
ability tags and we can remove a tag from it.
So we're going to use remove tag and we're going to remove the eligible tag because we know that's what
it has.
So we're going to have gameplay tags, dot ability status eligible, we're going to remove that tag
completely.
And then we need to add the new status.
So we take ability spec, take its dynamic ability tags and we're going to call add tag and we're going
to add the unlocked tag.
So gameplay tags dot ability status unlocked.
So after this it'll no longer have the eligible tag.
It'll now have the unlocked tag.
So that takes care of changing its tag.
Now, if it's equipped or unlocked, we don't need to change its status.
What we need to do instead is change its level.
Now, there's two ways to level up a gameplay ability.
One is to take the ability spec and simply take its level and use plus equals one or plus plus however
you prefer.
So we're just incrementing its level by one.
That's one way to do it.
What this results in is changing its level without canceling an ability if it's active.
Now, if you want to level it up and cancel the ability, if it's currently active, then you have to
remove the ability and give it back.
So all we're going to do is increase its level if it's already active.
I don't want to end the ability.
I just want to increase the level.
So next time we activate it or next time we use its level, it'll be one more than what it was.
Okay, so we've just changed our abilities status.
We need to also spend a point.
In other words, we need to subtract one from spell points.
We need to do that regardless of what the status is either way, whether it's eligible, equipped or
unlocked.
If we're in this if statement, we need to spend a spell point.
So to do that.
I'm first going to make some room up here at the top.
We'll do the spell point spending First.
I need to change the number of spell points and luckily we have an interface that our Avatar actor implements
if we go to our interaction folder in public.
And look at our player interface.
We have add to spell points and our character or a character implements add to spell points.
All it does is gets the player state and calls add to spell points.
But the player state broadcast a delegate in response to changing spell points which are spell menu
responds to.
So that should take care of our spell menu updating.
So I'm going to close our A character and player interface and we're going to see if our Avatar actor
implements the interface.
We know it does, but we're going to say if get Avatar actor.
We're going to call implements.
Checking if it implements you.
Player interface.
And then we're going to take iPlayer interface and call execute add to spell points and we're going
to add negative one to the spell points.
So we're spending a spell point.
Of course we have to pass in the avatar first.
Get Avatar actor.
So this results in us spending a spell point and all of that stuff is handled for multiplayer, so that
handles spending a spell point.
But what about the status?
Our spell menu needs to know of this change in status and we do have a client RPC client update ability
status so we can call that and that will result in the ability status changed delegate broadcast.
And because it's a client RPC that will work in multiplayer too.
So we could just call client update ability status after changing the status, we know that the status
has been changed.
If it was eligible now it's going to be unlocked so we can broadcast that change, so we can just call
it right there.
But here's the thing.
I also want my spell menu to know the level of the ability now because we're going to be displaying
information in our description boxes, and that depends on the level.
So I really think that whenever we update the ability status and broadcast this delegate, we should
also broadcast the current ability level for this ability.
I think that's important enough information to broadcast along with the tag and the status.
Now that means we have to change it wherever we're calling client update ability status, which includes
update ability statuses.
But in update ability statuses, that's not a problem.
We know what the level is.
If we're updating ability statuses, right, If we're giving the ability for the first time, it's level
one.
And here in spend spell point when we're upgrading it, well, we know the level here too, because
we can get the level from the ability spec here.
So I'd like to take client update ability status and add another input parameter to it for the abilities
level.
Let's do that in the header file.
So here's client update ability status.
We're just going to add an int 32 called ability level.
And that means we must add that to the implementation as well.
And we also need to take ability status changed and change this delegate so it can take an INT 32 as
well.
So we'll go to ability status changed and change it so that it can also take an INT 32 and we'll make
a inline comment here that says what the 32 is, it's going to be the ability level.
So now this delegate takes an INT 32.
We can broadcast the ability level that gets passed in to client update ability status.
And of course this will be red because declare multicast delegate now has to be three params.
So that'll take care of that.
So now whenever we call client update ability status, we have to pass the level in.
So I'm going to just quickly search for client update ability status and find all cases where we're
calling it, we're calling it an update ability statuses.
And here if we got the spec and it's null pointer, we're adding the ability for the first time with
a level of one.
So client update ability status in this case needs to take in one and then that's the only place we're
calling it, except we're now going to call it again here in server spin spell point.
Now we're going to call it passing in a different value depending on if we're changing its status or
if we're leveling it up.
Right.
Really, we're just going to broadcast the abilities level.
So we're going to call client update ability status passing in the ability tag, which we have its ability
tag passing in the status we just called that status.
And now passing in the ability level, which is ability spec level.
And that will result in our delegates broadcast to the spell menu widget controller and then they'll
update.
And at this point, because we changed our ability spec, if we'd like to force it to replicate now
rather than on the next update, we can call mark ability spec dirty passing in the ability spec which
it's a pointer, so I have to dereference it to pass it in.
So with that we're now broadcasting the ability status changed when we've spent a point and we've subtracted
one from spell points and we've upgraded the status or the level of one of our abilities.
Either way, we're broadcasting ability status changed and our spell menu widget controller is receiving
that ability status change.
But this lambda now has to receive an int 32 called level.
We'll call it new level.
So we're not using the level yet, but now our spell menu widget controller will receive it and as soon
as the status changes, we'll know what that new level is and we can use that in the future.
So for now, let's see what happens when we try to spend a spell point.
Okay.
We're back in the editor.
I'm going to go ahead and press play.
Open up my spells.
I don't have any spell points, so I'm going to need to level up once.
Now I have a spell point.
So here's the thing.
Right now, my firebolt spell is level one.
At least it should be.
And if I launch a single firebolt without being blocked or a critical hit, I should see.
Well, of course I get a critical hit, but let's see what I get.
I get.
I should see ten if it's not blocked or critical.
That was a critical but ten.
Yes, I should see ten normally now, if I upgrade my firebolt spell by spending a point on it.
Of course, nothing happens because I'm not calling my blueprint callable function.
I do need to do that.
So let's go into spell menu and make sure that we call that when we click our spend point button.
So we need to assign an event for on clicked.
We'll do it here for our other clicked events.
So I'm going to take my button, spend point.
I need to get its button widget because this is a wide button widget.
So getting its button, I'm going to assign onclicked.
So Onclicked I'm going to take my spell Menu Widget Controller.
And call spin point button pressed.
Now we're assigning to on clicked using a spell menu widget controller.
Right here in event construct.
We're doing it before widget controllers have been set.
Now we're just relying on that happening before we go and click anything.
But to be absolutely safe, we could make sure to bind this after widget controllers have been set.
So that would be right here after we've set widget controller.
So we should put this down here.
So here when we click the spin point button, then we'll call spin point button pressed.
So I'm going to comment this and say spend point button pressed.
And all that stuff up here.
This is just for.
Clicking on spell globes.
So we'll say spell globes selected.
But what we're interested in right now is actually pressing on the spend point button.
We want to see things happen.
So let's try that again.
I'm going to level up once we know that our damage is ten unblocked or on critical hit.
And if I select my firebolt and click spend point.
Okay.
Spin point button pressed should be called.
Oh yes, it is called, but I never called my ability system components function.
I forgot another thing, so I'm going to need to call my ability system component function that I called
server spin spell point.
We need to call that function.
So we're going to go back to spin point button pressed and call, get AC get or AC that is.
And call server spend spell point and it's going to be our selected ability.
Dot ability tag.
It's just called selected ability dot ability.
That's the gameplay tag.
That's what we need to do.
And just in case we call this before, the ability system component has been set, we can say if get
aura, ability, system component and only do this if the ability system component is set.
Okay.
So that's an important step.
I'm going to go ahead and close.
We need to save our progress there.
And now we should see this function called let's try this yet one more time.
All right.
So we're back.
I expect something to happen, so I'm going to level up first.
And now that I have a point, I'm going to select my firebolt spell, click spend point.
There we go.
That's what I expected to happen.
So spell points.
Updated the button.
Updated.
Excellent.
And we should see more damage than ten.
Okay, so it still says ten.
It could be still ten.
Based on our calculations, what we need to do is see if we're actually upgrading that ability.
So we should be down here where we're increasing the abilities level.
We'll see if we make it and I'll place a breakpoint down here just in case.
So let's go ahead and level up.
And upgrade and in server spend point.
Yes, we are changing the ability spec level and we are calling client update ability status with firebolt
status shouldn't change.
It's still equipped.
The level is now two, so our ability spec should now be two.
And what I can do to make sure of that is I can go to blueprints, ability system or abilities, fire
Firebolt, Firebolt and I can print the ability level right here as soon as we activate the ability.
So I'm going to print string, I'm going to get ability level.
Going to print that right there.
I'm going to launch and I see one server, one I'm going to level up.
And I'm going to spend a point and launch my ability.
Yes.
So my ability is level two.
We still see that it's causing ten damage, which means I have the feeling something I must have hardcoded
for testing purposes.
I'm going to go to ability system abilities or a projectile spell and see what level I'm setting for
my spec handle.
I'm setting it to ability level.
I'm setting my scale damage based on my ability level and my Firebolt if I go to class, defaults has
my damage types with fire.
We're using our firebolt curve in this curve table.
At level one, it should be ten at level two.
It's still ten.
Look at that.
It doesn't go up more than 0.168.
So what I'm going to do just for testing purposes is take this other key here and bring it down to level
two and make sure that it's 20.
You know what?
Let's put it up to 40.
Why not?
In fact, I'm just going to scale the whole thing up a little bit.
Let's do more damage, shall we?
So at level two, we should see now closer to 40 damage.
At level one, it'll just be a measly ten.
So.
Well, that was a critical hit.
But there we saw ten there.
And if I upgrade it now, we should see something closer to 40.
Boom, 39.
So it's working.
Awesome.
So upgrading our ability worked.
Now we need to change the status for this one here.
We need to change it from locked to eligible.
Let's gain an ability point.
There we go.
Let's select it.
Let's spend a point.
Okay.
So it should have upgraded from eligible to unlocked, right?
It should have gone from eligible to unlocked in our ability system component.
We see that it should be right here.
We should remove eligible and add unlocked.
Let's see if we reach that.
Yeah, we're reaching it.
We're setting its status tag.
We're removing eligible.
We're setting unlocked.
We're calling client update ability status with the new status eligible.
No, we're not.
It should be unlocked.
We're passing in eligible.
It should be unlocked.
Right.
That's because we're passing in status here.
We're not passing in unlocked because we never set status to unlocked.
Okay.
So that's another thing to change.
So what I'm going to do is resume.
And close the editor.
Saving all and we need to make sure to pass in that updated status because it's now changed.
So right here, status needs to be updated right here if we're changing it to unlocked.
That way we'll pass in unlocked.
Otherwise we're just passing in that status before we changed it.
So now that we're passing in the updated status, it should be correct.
So let's test this again.
So a little details that you get wrong sometimes.
That's where debugging capabilities really comes in handy.
The better your debugging abilities, the better you are as a software developer.
All right, we're back.
Let's test this again.
So I have.
A locked ability here.
Let's go ahead and level up.
We'll take this ability, click spend point and boom, look at that.
It is now eligible.
Amazing.
That just makes me really happy to see that next ability there with the blue color.
It's working.
It looks great.
That is just a huge milestone and already this spell menu looks so much better with two different abilities.
But now that it's unlocked, we need to be able to click, equip and then assign it and then be able
to activate it.
That's the next step.
But for now, we have the ability to spend our spell points.
It looks great.
Let's try this in multiplayer so we're not out of the woods yet.
We need to try this on a client, right?
So we're going to go ahead and I'm just going to click on it just because I can.
I'm going to upgrade.
Let's level up.
There we go.
We see that it's spend point has been activated.
Let's spend a point and boom, there it is.
It works.
I'm going to level up again.
Just so I can increase the damage from my firebolt and test that mechanic.
Don't feel like dying.
Okay, There we go.
And I'm going to upgrade my firebolt.
Ha!
Can't get me over here.
And let's do some damage and 39 so basically 40.
So it works on clients.
That is good news.
That is great news because this is really, really starting to come along.
I'm really happy about it.
It's just so satisfying to see a nice pretty HUD working.
So just going to do it one more time upgrade and boom, we see it.
I just need to be able to click, equip and equip it so we'll handle those things in the videos to come.
Excellent job and I'll see you in the next video.