Welcome back.
In this video, we're going to take care of an edge case, but it's actually an important edge case.
And that's when we have our spell menu open with one of our icons selected and we happen to level up.
So if we level up with an icon selected, we expect those buttons to update, but they don't.
And there are two things that should trigger the update.
One is when spell points change, we just changed from 0 to 1 spell points with an equipped ability
globe selected and we expect the spend point button to be enabled.
That's one case.
And another is if we have a locked spell globe selected and we level up and we expect.
Once it becomes eligible for the spend point button to be enabled.
And for that reason, we're going to need to broadcast those two booleans for the enabled status of
these buttons when spell points changes and when an ability status changes.
So we need to handle that.
So I'm going to close out of the editor and back in our spell menu widget controller.
I'm looking at buying callbacks to dependencies because we have two lambdas here.
One is bound to ability status changed and one is bound to on spell points change delegate.
Now, every time the status of an ability changes, we need to know what the currently selected ability
is, which we're not really setting when we click on a spell globe.
Same goes for when a spell point changes.
We need to know what the currently selected ability is.
So we need to store that.
We could store it as a gameplay tag, for example, but we also need to store that as current status
as well.
And here's the reason why.
When we level up, both, the status of some abilities might change and our spell points is going to
change.
Now let's just say that we've selected a spell globe that is currently locked and that we've just leveled
up and that we now meet the level requirement for that spell, which means it should now be eligible.
In that case, both of these delegates will be broadcast.
And it won't be clear which one will happen first.
Our on spell points change delegate is broadcast from the player state and when that happens, depends
on if we're on the server or if the spell points is replicated down to clients and so on.
And our ability status is broadcast from the ability system component.
And again, that depends on whether we're on the server, on clients and so on.
So it isn't clear which will happen first.
Now we could code this in a way that takes care of either situation, either one being broadcast first.
But we have to be careful because if we don't keep those situations in mind, then we may not code something
that works in all scenarios.
Now let's imagine for a moment that the ability status changed delegate is broadcast first, which means
that spell points change delegate has not yet broadcast.
Now, at this point, we could check what those booleans should be.
And if we check what those booleans should be, say using should enable buttons, we need to know the
status and we need to know the number of spell points before we can determine those two booleans.
And those are for enabling the spell points button and the equip button.
Now let's say that our spell points haven't yet updated, so we've just leveled up.
But let's say our spell points is still zero.
Well, in that case, we would determine the wrong boolean for whether or not our spell points button
should be enabled.
It should be enabled.
But since our spell points hasn't updated yet, it'll still be zero and that button will not enable.
Now, you might think, well, that's okay, because by the time spell points does update, we'll broadcast
it here too.
But in that case, what if we try to get the status from, say, the ability corresponding to whatever
we've selected and that that status has not yet replicated down from the ability system component to
a client?
Well, it's possible that our spell points will be correct, but then our status will not.
Now, the way to get around this is to keep in mind that when we level up, both of these delegates
will be broadcast eventually.
So what we can do is when the status for a given ability changes, if it's our currently selected ability,
we'll store that ability status.
And then shortly after when the spell points change delegate is broadcast, we'll check what that status
is that recently changed?
So we'll keep a local record of the status of our currently selected ability and update it every time
our spell menu widget controller catches wind of the change.
And we'll also keep a local count for the spell points as well.
So when we click on a spell globe, we need to keep track of what that ability is and the status for
that ability which will update as soon as we know.
Now, in order to keep track of both of those, I'd like a custom struct that simply has two gameplay
tags, one for the ability tag and one for the status.
So I'm going to make this struct and call it F selected ability and I'm not even going to expose it
to blueprint.
It's just an internal data structure that I'll use as a tool to keep track of our currently selected
ability.
And we'll have an gameplay tag called ability inside of it.
We'll set it equal to an empty gameplay tag by default and we'll have an F gameplay tag called status
and we'll set it equal to an empty gameplay tag as well.
So we'll just have an F selected ability and we'll keep track of our currently selected ability and
its status.
So we'll make one right here in the private section.
So it's going to be an F selected ability, we'll call it selected ability and we can initialize it
with two gameplay tags.
We'll use F or a gameplay tags get.
And for the ability, we'll just initialize it with abilities.
None.
And for the status, we'll just initialize it with the locked status.
So we're going to get that static get function and we'll say abilities status locked just to give it
a default value.
But as soon as the spell menu widget controller knows that it's changed, we'll store that new value
and we'll also have an INT 32 called current spell points and we'll set that to zero by default.
Okay.
So what we'll do is we'll set our selected ability every time we select a spell globe.
So we'll go into spell globe selected right here.
And as soon as our spell globe has been selected, we know its ability tag and we've also taken a look
at what its ability status is.
So by this point, we know the status of it.
So we can set our selected ability, we can say selected ability, dot ability equals ability tag.
And we know its status too.
So we can say selected ability.
Dot status equals ability status.
So at this point, we know our selected ability and its status and we're storing both of these.
Now we need to go up to bind callbacks to dependencies, because in these lambdas we're going to know
when the status has changed.
So we need to update that.
If the ability tag, whose status changed is equal to our currently selected ability.
Otherwise, we don't care.
So we're going to check we're going to say if our selected ability, dot, ability, dot matches, tag
exact, and we're going to see if it matches the ability tag for the ability, that's status just changed.
If that's the case, then we can take our selected ability and set its status to the newly updated status
tag.
And at this point, because we now know the status, we can broadcast those booleans up to our widgets
so they can update the buttons.
In other words, we want to create a local BOOL for each of those booleans, set those based on our
currently selected ability status and our spell points that we've been setting every time they change
and broadcast this delegate.
So we're going to take these four lines and we're going to paste them up here.
Now, the difference here is that the status is going to be status tag.
And the spell points will be the spell points that we've been keeping track of.
Our current spell points here.
So every time they change, we'll keep track of them here.
And to keep track of them, we do so right here in spell points change Delegate What we do is we set
our current spell points and we set them equal to the spell points value.
And as soon as spell points have changed, we also need to do these for lines right here.
So we're going to paste these down here.
Only the status is going to be the status that we've stored in our selected ability.
So we're going to say selected ability.
Dot status and we're passing in our current spell points, which is equal to spell points.
And then we broadcast here.
So every time the status changes or the spell points change, we update our local variables, keeping
track of these.
And when we level up, one will happen, then the other and both will have access to the current information
that we have in the spell menu widget controller.
So with that we can compile and see how this works by testing these edge cases.
So back in the editor, all we need to do is press play, open our menu and select one of our spell
globes and level up.
So let's see what happens.
One more should do it.
And I'm expecting the pinpoint button to become enabled because our spell points will become one.
And it does, Sure enough.
Now the next edge case is going to be when we have this spell globe selected, because when we level
up, it's going to become an eligible spell, which means the spin point button should also become enabled
in that case.
So let's level up.
And there we have it.
It's updating as well.
So that handles the edge cases.
And we can't test them all because we don't have the ability to change the statuses yet.
We can't spend a point and change this spell globe from eligible to unlocked, for example.
So our next steps is to start actually making these buttons functional.
All we're doing right now is setting their enabled status based on what's selected.
But now we need to actually make these buttons do something when we click on them.
And we'll do that next.
Excellent job.
I'll see you in the next video.