Welcome back.
Now that our spells have the concept of status, we can show those spells in our offensive and passive
ability trees.
Now, by default, these icons aren't associated with any specific abilities.
Right now, they just have locked.
They each need to have their own concept of ability.
Much like the equipped abilities, Rho has globes, each of which know what their input tag is and the
trees.
They need to know what ability they're assigned to, not input tag.
So for that reason, these spell globes, the kind that are in the offensive and passive ability trees
each need to know what ability is assigned to them.
Now, so far we only have one ability that belongs in these trees and that's our firebolt.
So really, just one of these is going to get its ability tag.
But the class, the widget blueprint class itself needs an ability tag variable.
So I'm no longer interested in my equipped row button or my equipped spell row or my firebolt ability.
Looks like I have my overlay.
I'm going to close that too.
What I want is the widget I'm using in my offensive abilities and that's going to be my spell globe
button, not my equipped row button that goes in the equipped row.
This one, the spell globe button goes in the trees.
This class needs a gameplay tag variable to identify the ability associated with it.
So I'm going to add a variable and call it ability tag.
And we'll change its type to gameplay tag.
So now that we have an ability tag and it's going to be set to none by default, we can assign the ability
tags in our trees by going to our spell menu folder and I'm going to open offensive spell tree and click
on this spell globe down here.
It's going to be the spell globe that I assign the ability of Firebolt to.
Here's the design I have in mind.
I'm going to have all fire spells in the first column, all lightning spells in the second column,
and all arcane spells in the third column, and they'll go from bottom to top.
So we'll start off with the bottom left ability with our firebolt ability in it.
So I'm going to take this and set its ability tag.
Now, that means that that ability tag variable that we just added needs to be instance editable so
we can take the ability tag, check the eye icon, compile it and back in offensive spell tree, we
can select that one and search for ability tag.
And we can set the ability tag to abilities fire firebolt.
Now whenever we broadcast ability info, we can check that ability tag broadcast along with it.
So our spell glow button needs to listen for that type of event.
So here in the event graph, notice that it's using the overlay widget controller because we made this
from another widget.
We don't want overlay widget controller.
We're going to delete that.
I don't need that.
Our spell glow button is going to have the spell menu widget controller, and we're going to set that
from the spell menu here.
Here in spell menu, we're already setting the equipped spell row widget controller.
We also want to set the widget controllers for our spell trees.
Our offensive spell tree, which we need to select and check is variable for and our passive spell tree,
which also needs to be a variable.
So back on the event graph, we need to set their widget controllers as well.
So we're going to get offensive spell tree and passive spell tree and call set widget controller for
both of them using the widget controller variable.
So let's call set widget controller for offensive spell tree.
Passing that into target and widget controller in two in widget controller.
And we'll do the same thing for passive spell tree.
We'll set its widget controller and we'll go ahead and hook up these nodes.
Well, straighten up the nodes as well and we'll expand our comment to contain these now.
And now that we know that those widgets will have their widget controller set, we can assign events
to delegates in them.
I'm just going to do this in the offensive tree.
As soon as the offensive spell tree has its widget controller set, it can set the widget controllers
for all of its globes.
So I'm going to select all of them and check is variable.
As soon as I do that, their names all change.
So they're unique.
They all have numbers after them.
I'm not going to bother renaming them for now.
I'm just going to set their widget controllers.
So we're going to use event widget controller set.
And we're going to take each of our spell globe buttons, starting with the first and call set widget
controller.
Using our widget controller.
We'll pass that in for widget controller.
I'm going to get widget controller up and out of the way.
And drag in each of my other spell globe buttons.
We'll start with one and go all the way up to eight.
So we can time lapse this.
And with that, all of our sub widgets have their widget controllers set and we can collapse this to
a function set.
Widget Controllers.
And once all of these sub widgets have their widget controllers set.
Our spell glow buttons can assign an event to respond to the ability info Delegate.
On the spell menu widget controller.
Which means first we need to get our widget controller.
Cast his spell Menu Widget Controller.
We'll promote that to a variable.
Beep.
Spell.
Menu.
Widget Controller.
Go ahead and comment that.
And then we can take BP spell Menu Widget Controller.
And assign ability info delegate.
And here we can break the ability info.
Now, here's the thing.
We need to identify the ability by its ability tag, but we also need to know its status now because
if the status is locked, we just need to keep this with the locked icon.
If the status is eligible, we need to change the icon.
But keep the background as gray.
But if it's unlocked or equipped, we need to set both the background and the icon.
So now that we need to know that status, we're going to want our ability info struct to contain an
ability status and we'll need to set that before broadcasting it up to our widgets.
So we have a few things to do in code.
Let's go ahead and close and save and make sure that our spell globes can receive the ability status
in our ability info.
Now that means we should start by adding the status to our ability info struct that we're broadcasting.
So I'm going to go ahead and close all tabs and enter my public ability system data folder and go into
ability info where our aura ability info struct is defined.
We're going to add a new gameplay tag and it can be blueprint read only.
We don't need to make it edit defaults only.
It doesn't make sense to set it in the data asset.
This depends entirely on the current status of the gameplay ability, so we need to set that dynamically.
So let's add a new gameplay tag with blueprint read only called status tag.
It'll be set to an empty gameplay tag by default.
Now that this status tag exists, we need to set it when we broadcast from the spell menu widget controller.
So we're going to go into our private folder into UI, widget controller Spell Menu.
Widget controller.
Where we're broadcasting ability info.
Actually this is a function on a widget controller.
So let's go into a widget controller where we're broadcasting ability info from here and here is where
we can set the status because we have our ability info that we're about to broadcast up to our widgets.
So how are we going to do it?
Well, we can take our info, we can take its status tag and we can set it.
We just need to know what that status is.
Well, we have our ability spec, right?
And recall we recently added a function to our ability system component.
Let's go to our ability system component CPP file and that function is called get status from spec.
We pass in an ability spec we loop through its dynamic ability tags and search for the first tag.
We find that has abilities dot status in it and return that.
So we had the foresight to know that we would need this.
So back in our widget controller or a widget controller, since we have access to our ability system
component and we know that this variable has been set because we've called get or ask previously in
the function.
So we know that it's been set, we can get that ability system component and call get status from spec
and we can pass in the ability spec.
Now every time broadcast ability info is called, we're setting the status tag and passing that on up
in our ability info struct.
Now we can check that status when receiving it in our spell globes.
We'll do that next.
Let's go ahead and compile and launch.
All right.
We're back in the editor.
Let's go back into our spell globe button here.
In the event graph, we're listening to Ability Info Delegate.
And check this out.
We now have a status that we can check.
So there are two tags we need to check here.
We need to make sure that this info has the ability tag matching our spell globe, but we now need to
check its status tag as well.
We'll first check the ability tag.
We're going to say matches tag.
We're going to use exact match and make a branch.
And if the info matches this Globes tag, we can continue.
And before we continue, I'm now going to collapse this into a function so we can work all within a
function.
And this function we can collapse.
We can call this receive ability info.
So let's go into our function.
And the reason I want this to be a function is so we can organize this a little bit.
Now, the first thing we want to do after making sure that the tag matches is check what the status
is in the status tag.
I'm going to promote this status tag to a local variable.
Called status tag.
We'll just call it status, actually.
That way we don't have to drag a bunch of wires around.
We can just do a branch to check our status for each of the four statuses.
So I'm going to bring that status in and use matches tag.
And we're going to use an exact match and we're going to check our status against abilities.
Status and we'll check.
Locked first.
And if it's locked, well, that's the easiest case, right?
We just need to make sure that the icon and the background are set to these textures here.
So we're going to take our icon, make sure it's a variable and our background, and we'll drag those
in here.
Image icon.
Image Background.
And we can simply call set brush from texture.
For the icon and we can just hard code the locked icon.
Locked underscore SM.
We'll set that.
For the image background we're going to set.
Brush from material.
And we're going to choose.
The locked material.
And this can be collapsed to a function.
Collapse.
The function set globe locked.
Now, if we make it past this, then we need to check against the next status.
So we're going to duplicate those nodes and add another branch.
And this time we're going to check against a different status.
We just checked.
Locked.
The next easiest one is going to be equipped.
So I'm going to change this to equipped.
And for this one, we know what we need to set the textures to, don't we?
We need to use the icon in the background material.
I'm going to promote these two variables too.
So this is easy.
So the icon I'm going to promote to a local variable.
Called ability icon.
And the background material I'm going to promote to a local variable.
Ability background.
And if our status is equipped, we're going to take image icon.
We're going to set brush from texture.
Using ability icon and we're going to take image background.
Set brush.
From material.
Using ability background.
Now these could be collapsed to a function.
Only ability icon and ability background are local variables.
So what we have to do is pull them out and collapse the rest of this to a function so we can do that
and call this set globe equipped.
But we do need to make sure to keep these outside of the function because they're local.
Now after equipped, we need to check the next status.
So we'll check matches tag here.
Another branch hook the false up to it and we've already checked locked and equipped.
We're going to check against eligible and this is kind of a hybrid of locked and equipped.
We're going to set the image icon.
So we're going to call set.
Brush from texture to the ability icon.
Only we're going to set the background to locked.
The gray one.
So we're going to take image, background and call set brush from material.
And I'm going to hard code in that locked material.
So this one is kind of a hybrid, so I need to bring that ability icon out.
Hook this up and then collapse to a function.
This will be collapsed to set Globe eligible.
And then the last one, we haven't checked.
We've checked locked, equipped, eligible.
And there's also unlocked.
Now unlocked and equipped are the same.
So we could just check both of those at the same time and make an Or boolean here.
So this one will be.
Unlocked.
So if it's equipped or unlocked, that will be for this case because both of these.
Ability, icon and ability background should be set.
So it could be set globe equipped or.
Unlocked, so I'm just going to rename it to set.
Globe equipped or unlocked?
Like so.
Okay.
So receive ability info now handles all of the cases.
For ability statuses.
I just really want this to look as neat as I possibly can make it, and I think that's about as good
as I can get.
But it doesn't look too bad.
Okay, so now our spell glow button.
An event widget controller set is casting its widget controller to a spell menu.
Widget controller Assigning an event to ability info delegate receiving that info and updating its globe
based on the status.
So as long as that status is set, then our spell globe button is going to receive it.
Now in our spell menu when we're setting our sub widget widget controllers.
It looks like we're setting our offensive spell tree widget controller, after which we call broadcast
initial values and our offensive spell tree has its widget controller set, at which point it sets the
widget controllers for all of its spell globe buttons, including this one.
This is the one we're interested in because we set its ability tag to abilities.
Fire Firebolt.
So because this globe has the ability tag abilities, fire firebolt and our spell glow button and receive
ability info, we're checking matches tag.
Checking the ability info struct ability tag against.
Well, we should be checking against our spell globes ability tag here.
And if we make it past that we'll update it.
So moment of truth.
Let's press play and open our spell menu.
And sure enough, there's our ability that we assigned the ability tag.
Now that's pretty cool, but we're not really testing any of the other statuses.
We need to test whether this shows the correct thing based on the other statuses.
So what we can do is we can close the editor, we can save all of our work and in our ability system
component, when we're giving abilities in add character abilities, we can change that status that
we're giving the ability just to test out what we're seeing in the HUD.
So we know that equipped works, we can check eligible, which should look the same, except that background
should be gray.
Let's check that out.
So we'll just compile and test.
Okay.
So we can press play.
We can open our menu.
And this is what eligible should look like.
We have the firebolt icon, but we have the gray background.
So this is what it would look like if you now meet the level requirement for an ability, but you have
not yet spent a spell point on it and you cannot yet equip it.
So it's still grayed out, but you can see what it is, right?
So that's eligible.
We can also check the other statuses.
We know what equipped and eligible look like.
We can check what locked looks like, and it shouldn't be too surprising.
It's going to be the locked icon, same as its default.
But we can still check.
So we can press play open and see the locked icon as expected.
And finally, we can just test out the last we tested equipped, locked, eligible.
Now we can see what unlocked looks like and unlocked should be when we've unlocked the spell.
It was eligible.
We spent a spell point on it.
Now it should be colorful.
It should look the same as if we had equipped it.
So let's make sure that that's the case.
Okay.
Pressing play, opening the menu, and there's what it looks like.
Unlocked.
All right, so at least we know that we're showing the correct thing.
We do want to make sure that this is set back to equipped, though, and now things are working.
All right.
So that's going to pretty much conclude the video.
There's one thing I want to just show you that I ran into when testing that I want to fix real quick.
Okay.
So I'm going to show you one thing I ran into when testing, and that's if I open one of my menus and
kill the game, stop simulation, then I get this error that says set input mode game and UI expects
a valid player controller.
So we're killing the game.
The player controller gets destroyed apparently before our widgets get destroyed and we're attempting
to call set input mode game in UI on a widget controller that is not valid.
So we need to go into where we're doing that, which is in UI overlay, WB overlay, open that graph
and here when we're closing the menu attribute menu and spell menu for that matter, we need to make
sure that we're only calling this function on the player controller if it's valid.
So we're going to use is valid here.
And remember, this is for the false case.
So don't go and plug the true up into it.
Use false.
Otherwise you're creating a logic error there.
So false goes to is valid which goes to set input mode game and UI.
That's for the attribute menu.
We're going to do it for the spell menu too.
So.
Take that player controller call is valid on it before trying to use it.
And now.
We can press play, we can open our menu, we can kill the game.
No errors.
And that goes for both menus.
Just something I noticed in testing that I figured we'd clean up and fix.
So that's looking good.
Everything can be saved.
Excellent job and I'll see you in the next video.