Welcome back.
Now, in this video, I'm concerned with starting to make our spell menu functional.
And I'd like to start with the very bottom row down here.
We want to show our equipped abilities.
And right now we know the only equipped ability is the firebolt that we have here.
And the others should be empty.
So we should reflect that here.
Now, in addition, I'd like to add an equip button and that will allow us to select one of our abilities
from our tree and click equip to assign it to one of our rows.
So before we go about making our spell menu functional, let's add one more widget to it.
That's going to be a button.
So we're going to go to our UI folder into spell menu.
We'll open our spell menu widget and we're going to add one more wide button.
And I'd like that to be just beneath passive abilities, which means we may need to change the size
of some of these things.
Let's go ahead and create a little bit extra space.
I'm going to make my offensive spell tree a little smaller, so I'm going to open that widget and just
take my size box root, take my height override and bring it in.
And it looks like 300 might be perfect.
So I'm going to set that as my default box height.
So instead of 350 that that'll be 300.
We'll go ahead and save that.
So already we have a little bit more room.
I'll get my passive spell tree as well and we'll do the same thing.
I'll take the size box root, we'll drag the height override down until we see a good value.
I think 60 is just about right, so we can go ahead and set our box height variable to 60 and save that
as well.
Now our spell menu looks like it has some extra room and I'd like this equip button to be after my passive
abilities spell tree.
So that's going to be just above equipped abilities so we can search for a wide button and drag it in
between those two right here and we can search for properties in its details panel and change the text
to equip.
And we can take the box width for it and set it to a smaller value like 100.
And I do want to make sure that this button is going to make our equipped abilities text Go to the new
line.
If we select that equipped abilities, text and click Force new line, it will be forced to the new
line and then we can take our equip button and we can click fill Empty Space and Choose center, align
horizontally.
And that's going to allow it to be in the middle at the correct size.
Now obviously we're going to need some spacers in between, so let's grab a couple of spacers.
I'm going to take one of them and drag right above the wide button.
I'm going to increase its X size.
I'm going to take my passive tree and click Force New Line and my new spacer is going to be wide in
the X enough to.
Push the equip button down and then we can.
Make it a little taller, let's say 20.
Now I'm going to copy that spacer.
Click on my wide button Ctrl V and I have one beneath it too.
We can compile, we can save.
And let's see what it looks like.
Now we have an equip button and it looks pretty good.
Now.
I'll go ahead and just make it a little bit wider than 100.
Maybe 120.
Okay.
So that's the first thing I wanted to take care of.
But now we need to make this a functional spell menu.
And we know that our widgets need widget controllers.
So this spell menu needs a widget controller.
We're going to make a spell menu.
Widget controller.
And before we do that, I'm just going to take the width for my description box and just make it a little
wider.
245 looks pretty good and I'm going to do that for both.
That's better.
I like how that looks.
Now let's go ahead and create our spell menu widget controller.
So that's going to be a C plus plus class in Aura public UI, widget controller, and it's going to
be based on our base class for widget controllers or a widget controller.
So I'm going to right click on that, create a C plus plus class based on it and call this spell menu
widget controller and it'll go into widget controller.
Let's create that class and close the editor.
So here we are.
I can go into UI widget controller and here spell menu.
Widget controller and here's the CPP file.
Now spell menu.
Widget controller is an aura widget controller, so it's inheriting some things from aura widget controller
that we can override.
Our two key functions are broadcast initial values and bind callbacks to dependencies.
We're going to override these both, so I'm going to copy both of these functions and come into spell
menu, widget controller, create a public section and override both of these functions.
So we'll mark both of them with override.
And we'll generate definitions for both of them.
Now super is called by default, but or a widget controller if we go into the CPP file, doesn't actually
implement them.
So it doesn't matter if we call super or not, we can go ahead and remove those function calls until
we go and add something to the parent versions that we need.
Now, broadcast initial values needs to do something.
Our spell menu needs to know which abilities are equipped.
In other words, we need to broadcast whichever abilities we have already equipped so that our equipped
spells row can show them.
And our spell tree for that matter, can show them.
And we've already done something similar to this in our overlay widget controller if we open overlay
widget controller dot CP.
We can see what it is doing in bind callbacks to dependencies.
It's getting the aura ability system component, seeing if it's start up abilities have been initialized
and calling on initialized startup abilities.
In this function it double checks to make sure the ability system components startup abilities have
been given.
If not, it returns.
And then it does this business.
It creates a delegate and binds a lambda to it and then calls for each ability on the ability system
component, passing that delegate in the ability system component then goes and loops through all of
its activatable abilities executing this delegate.
And what the delegate does is in this lambda here.
So it finds the ability info for this abilities tag, it gets the input tag for that ability from its
ability spec and then broadcasts its ability info delegate.
So we want to do basically this same thing, except as we'll see later on, we're going to want to change
it a little bit.
We'll be needing to broadcast more information about our abilities to our spell menu.
Now we have a couple to dos that it looks like we've already done them.
Get information about all given abilities, look up their ability info and broadcast it to widgets.
We've done that.
That to do can be removed.
This to do says need to find a way to figure out the ability tag for a given ability spec.
Well we've done that.
It's called get ability tag from spec so that to do is done as well.
Now, because this is something we need to do in our spell menu widget controller as well, rather than
just copying ourselves with a duplicate function, we can move this function into aura widget controller,
which is the parent class to both of these, and then both of these classes can enjoy inheriting from
it.
Now that means we'll be taking our ability info.
Delegate a member variable of overlay widget controller and moving it into aura widget controller.
Which means all widget controllers will have an ability info delegate member variable.
If I go into overlay widget controllers, we can see that we've declared the ability info signature
here and we have the ability info delegate right here as a member variable.
So what we can do is instead move this ability info signature delegate declaration into aura widget
controller, and then all widget controllers will not only have this type defined, but they can also
inherit an ability info delegate member variable so all widget controllers will have one.
So I'd like to do that.
So to keep things organized, I'm going to rearrange my tabs here.
I'm going to move my Aura widget controller all the way to the left, both the H and CPP files.
And I'm going to move my overlay widget controller here into the middle and my new spell menu, widget
controller all the way to the right.
Now the overlay widget controller is defining the delegate F ability info signature inside of its H
file and then it has that ability info delegate member variable.
We're going to move this declare dynamic multicast, delegate one param from overlay widget controller
into or a widget controller.
So I'm just going to cut it with control X and bring it in and paste it right here and or a widget controller.
And now a widget controller has this type defined here.
Now overlay widget controller also has, as I mentioned, ability info delegate.
We're going to go ahead and cut that as well and move that into our widget controller.
So this will now be an inherited variable and this can go in the public section.
So now overlay widget controller is just using the inherited ability info delegate.
But on top of that, I'd like to move all of this stuff into or a widget controller.
Now that means or a widget controller is going to depend on the ability system component.
And if you didn't want that, if you wanted the aura widget controller base class to not depend on aura
ability system component, then you could just repeat yourself and have copies of this function into
child classes.
But aura ability, system component and aura attribute set are base classes for the whole project.
In other words, just about every ability system component in this project, actually every single one
is derived from our aura ability system component.
So it's kind of generic.
We can treat it almost like the engine class ability system component and a sense that it's a base class
that's super generic.
So we won't be really restricting aura widget controller by making it dependent on aura ability system
component.
And of course this dependency is one way, so it's still a good coding design.
So what I'm going to do is go into Aura widget controller and I'd still like all widget controllers
to have the four key variables and these be the engine classes, player controller, player, state
ability, system component and attribute set.
But in addition to that, I'd like to have four more specific variables aura player controller or a
player state or a ability system component and aura attribute set.
And then we can create getters that will cast these values to those specific classes and store them
in that way.
We'll only ever cast once and every subsequent time after that that we need those classes, we can retrieve
them.
So what I'm going to do is copy these four key variables in aura widget controller and paste them just
beneath.
The only difference now is that we're going to change their types.
The A player controller will now be aura player controller and its type will be a aura player controller.
Now we're going to forward declare that type.
So we're going to go up to our forward declarations here and we're going to forward declare aura player
controller and we can forward declare the others to a or a player state.
We can forward declare you or ability system component and we can forward declare you or a attribute
set.
And we can have the four key variables that are more specific here and they'll be lazily casted.
In other words, the first time we need them, we'll get that cast.
If we never need them, we'll never cast.
So we have a player controller.
The next will be an A or a player state called or a player state.
Next we'll have you or a ability system component called or a ability system component and you or a
attribute set called or a attribute set.
And now that we have these four key variables, I'd like to make public functions that can retrieve
them.
And these functions are going to be used to cast.
If these variables are null now, they'll just be protected.
So we'll have a function returning an A or a player controller pointer and we'll call it get or a PC.
We'll have one that returns a player state that does the same thing A or a player state get or a PS,
We'll have one that returns the ability system component.
Called get or ask, and we'll have one that returns the attribute set.
Called get or as.
And these functions can all be defined.
And what they'll do is cast if their corresponding pointers are null.
Otherwise they'll return them.
So we'll say in Git or APC if Ora player controller is null.
Then we'll say or a player controller equals cast to a or a player controller.
Player controller.
And then we'll return it.
Return or a player controller.
So in other words, if a player controller has not yet been cast successfully, then we'll cast it and
return it.
But if it's not a null pointer, we'll just return it without the cast.
Now, as soon as I use this type I got or a player controller auto included for me.
So don't forget that part.
Now for get or a PC, this is for the player controller we're going to copy these lines for get or PS
only.
The difference will be this is or a player state that we're setting.
So we'll say or a player state equals a cast to a or a player.
State player.
State.
And will return or a player state from this.
We'll do the same thing for the ASC and the A's so I can quickly time lapse the rest of these.
Okay, so we have these four getters that we can use to always access the aura versions of our four
key variables.
Now that I've added these member variables to Aura widget controller, I need to just try to compile
and see if we get any errors for using any identifiers that have these names in child classes.
And it looks like we are, we're using them.
It looks like an overlay widget controller so we can go to that.
Here in broadcast initial values.
We're casting two aura attributes set.
We're using cast checked also, but really we don't need to use a cast at all.
All we have to do is call get aura as
an aura.
Attribute set is actually now a member variable that will be set when we call get aura As So we don't
even need this local variable here.
Instead we'll just replace aura attribute set with get aura as and that's going to satisfy it.
We're also using Aura player State as a local variable here in bind callbacks to dependencies.
Once again, we don't need cast checked here.
We can just use aura player state so we can remove the local variable and use get aura player state
which is PS.
In place of a player state here.
Here we're getting or attribute set we don't need to use or attribute set we can use, get or raise
instead.
So right here where we're using it, we're going to call get auras.
So we're using it here, here and here as well.
Now here we're casting ability system component to aura as well.
Instead, we can just call get aura ASC.
Now if we call get Aura ASC right here in the If statement that will set our aura ability system component
and then each subsequent time we call it we will not cast again, we will just retrieve it.
So we'll just replace all uses of it there.
Now in on initialize startup abilities, the whole reason for all this, we're using our aura ability
system component right here.
I'd like to replace it with Aura ASC.
In fact we can use control H here.
And search for aura ability system component and replace with jet aura ask.
Now, if I click replace here, it'll replace it.
I can click the up arrow to go up to other uses, but I have to be careful here because we don't want
to replace it everywhere.
On initialized startup abilities takes an input parameter called aura ability system component.
We don't want to replace it there.
We want to actually change the name of this input parameter.
Now, usually adding in to the input parameter is a nice way to just make sure that it's not the same
name as anything else.
We need to change it in overlay widget controllers as well, so we'll replace it with in there.
But we can also replace aura ability system component by just highlighting here control H searching
for aura ability system component and we can skip all instances that we don't want to change.
So we want to change this one.
Replace for the capture list.
We're going to keep aura ability system component.
There.
In fact, we don't really need to capture it anymore because we're capturing this.
And that's where aura ability, system component exists.
So what we can do instead is remove this from the capture list now and just use the member variable
aura ability system component in the lambda.
That's fine.
Okay.
Now here in on XP changed if we replace aura player state right here with get aura ps, then we get
red squiggles saying that we can't convert this argument from type const overlay widget controller to
type aura widget controller function is missing const qualifier.
Now that's because on xp changed is a const function.
So if we're going to be calling get aura here we have to remove const from on XP changed.
So we're just going to remove const from on XP changed.
As it can no longer be a const function.
And now we don't need this or a player state.
We can use get or ops here.
And by the way, the first time we call git or Ops in any of these functions, we're pretty safe to
access or a player state after that in the function.
So that's another thing to be aware of.
I'm going to compile, see if there's anything else we missed.
And we're using or a player state in attribute menu widget controller.
So what we can do here is instead of casting again, we can use Git or a PS.
And we don't need or a player state here.
In addition, we're casting.
As for the aura attribute set, instead we can call get aura as here.
So get auras.
Now, we don't need this cast checked.
We can still check attribute info if we like.
Okay.
Control shift B again and we have one more in attribute menu player controller and broadcast initial
values.
We don't have to cast here.
We can call get aura ps and with that.
We should be good to go.
One last compile and it's successful.
Okay, so what we just did by doing all that was eliminated repetitious casting.
Now, those casts will only be performed once and never if they never need to be.
And because of that, we now have easy ways to access those four key variables here which are cast to
the Or versions.
So I can close attribute menu widget controller.
We're done with that.
And what I'm interested in now is a function that does what our on initialized startup abilities does,
namely it creates a delegate, it binds a lambda to that delegate and calls the asks for each ability
with that delegate.
So really what this function does is it forces a broadcast for all abilities broadcasting their ability
info with the ability info delegate and really it doesn't even need to take in the aura ability system
component.
It can get it with get or ask.
So this could be a function on or a widget controller called simply something like broadcast ability
info or something like that.
So here on Aura widget controllers, I'm going to add a function for that.
It'll be void called broadcast ability info.
And broadcast ability info.
Is going to do basically what on initialized startup abilities does.
In fact, I'm going to copy the lines in it.
Come back to Aura widget controller and paste them in here.
Now it's trying to usability info.
Now if ability info is a data asset member variable on overlay widget controller and it turns out we
need it in multiple widget controllers, why don't we just move that to Aura widget controller as well?
I'm going to go ahead and do that.
I'm going to cut it and paste it in Aura widget controller in the protected section, and now it's inherited
by all widget controllers and we can use it here.
That means we have an incomplete type that we need to not only forward declare here in aura widget controller
you ability info.
We'll make sure to do that.
But we'll also include it in or a widget controller and we can steal that include from here in overlay
widget controller right here.
Ability info will paste it right up in or a widget controller as well.
Now or a widget controller has this broadcast ability info function.
This is nice and handy.
We can use it in overlay widget controller instead of on initialize startup abilities.
So let's find where we're calling that.
We're calling it right here.
Now, instead, we can call broadcast.
Ability info.
And now this function is inherited so we can call it in spell menu widget controller as well.
And overlay widget controller no longer needs on initialize startup abilities.
Now of course ability is given.
Delegate is binding on initialized startup abilities to it.
And abilities given delegate.
If we go and just peek at it in our ability system component or ability system component class, it's
an ability is given which requires a you or a ability system component pointer.
We could change this to no longer take an input parameter.
We can just go ahead and remove that input from it, change it from one param to a delegate that doesn't
take parameters and make sure that when we broadcast it in the CPP file abilities given delegate when
we broadcast it, we don't pass this in.
So we can remove that in both cases where we're using it and then overlay widget controller doesn't
need to bind on initialized startup abilities.
Now it can bind the inherited broadcast ability info function.
So here in overlay widget controller, we can replace this with broadcast ability info instead and then
we can remove that function altogether as it's now redundant.
We can take on initialize startup abilities, cut it completely out both here in the CPP file and in
the header file.
Now we have to compile to make sure that we haven't broken things elsewhere in the code just in case
anything else is listening to that.
Delegate abilities given delegate.
But it looks like that was the only thing.
So now we've just rearranged our code a great deal, but now or a widget controller has the ability
to broadcast ability info and overlay widget controller is just using broadcast ability info here.
Now for that reason, this is kind of nice because spell menu widget controller can make use of broadcast
ability info and we'll do that soon.
We can do it as soon as we broadcast initial values, for example.
But we do need to make sure that a spell menu widget controller actually gets constructed and has its
key values set and we need a way to access the spell menu widget controller easily.
So or a ability system library comes to mind.
So we're going to need to do all that and we'll do that in the next video where we actually construct
a spell menu, widget controller, and then we'll make use of broadcast ability info before we do all
that.
Since we made lots of changes, I just want to make sure everything still works, especially with the
overlay.
We want to make sure our overlay widget controller is broadcasting the abilities that we have equipped
and that we can see them in the overlay at least.
So all we need to do here is press play and there's our ability.
And we can also check in multiplayer, make sure the client sees its equipped ability as well.
And it does.
So things are working.
So excellent job and we'll continue in the next video.
I'll see you soon.