Welcome back.
Now our attributes are sort of behaving the way they should.
They're grayed out when we have no points.
They're not grayed out when we have points, but they don't do anything when we click on them.
And that is something we are going to fix now.
We need a way to upgrade our attributes.
And what I'd like is a function on my widget controller, specifically my attribute menu widget controller
that I can call whenever one of these buttons gets clicked.
In other words, we can make a blueprint callable function to upgrade attributes.
That's what we're going to do in this video.
Now, if we call some function, whenever we click on a button, we should probably send information
to the widget controller so it knows which of these has had its button pressed.
Well, we know that each of these widgets have an attribute.
Gameplay tags.
Right?
This is a text value button row which has its own attribute tag variable.
So let's create a function we can call from Blueprint to send that info down and upgrade our attributes.
So I'm going to get my attribute menu widget controller.
I'm going to go ahead and just close other tabs and make a public function that we can call to upgrade
attributes.
It's going to be void and I'm just going to call it upgrade attribute.
Now to upgrade an attribute, I want to know which attribute we want to upgrade.
So this will take a const reference to an gameplay tag and this tag will be called attribute tag.
Now I need to make sure that I have gameplay tag either included, which I don't or forward declared.
Now it's a reference so we can forward declare gameplay tag.
Let's go ahead and do that.
We'll say struct f gameplay tag.
Now this function is going to be a new function with blueprint callable.
We plan on calling this from our widgets and I'm going to generate the definition for it.
Now what exactly are we going to do when we call this function?
Well, really, it's the ability system component that needs to know about this.
The reason the ability system component needs to know about it is because the ability system component
is capable of doing things related to attributes such as applying effects or sending gameplay events.
So I'm going to make a function on the ability system component that we can call for upgrading attributes.
Let's open our ability system folder and get our ability system component open and create a public function
we can call here.
Now, this will be also a void function.
In fact, it's going to be the same function.
I'm going to get my void upgrade attribute.
Function signature here and just paste it.
It's going to be the same function and I'll go ahead and generate the definition for it.
Now our attribute menu widget controller is just going to call this function.
That's all the attribute menu widget controller needs to do, but it does need to cast our ability system
component to an aura ability system component.
So I'm going to say you aura ability system component, aura, ASC equals and I'm going to cast checked.
To you or a ability system component, and I'm going to cast the ability system component.
And after that I can take or ask and simply call upgrade, attribute passing in the attribute tag.
So that's all that our middleman class attribute menu widget controller needs to do.
The rest of this is on the ability system component so I can even close attribute menu widget controller.
Now we're working in the AC, so what is the AC need to do?
Well, keep in mind that when we click on this button in our widget controller calls this function,
we may be on a client or we may be on the server because we may be on a client.
We're going to want to make sure definitely that something happens on the server.
But before we go and say send an RPC up to the server, we should check here in upgrade attribute to
make sure that we have any attribute points.
If our attribute point count is zero, why should we send an RPC up to the server that's wasteful?
So we need to see if our character has those points.
Now, I don't really want my ability system component to be dependent on, say, my player state or
anything like that.
I'd rather just add an interface function that I can easily call to see if we have attribute points.
So my player interface would be a perfect place to add a getter function for attribute points.
We can already get attribute points, reward spell points reward.
We can even add to attribute points and spell points.
What we want are getters, and while I'm at it, I'm just going to add a getter for spell points as
well.
So this will be an int 32 returning function called get attribute points.
It's going to be const and it's going to be a blueprint Native event.
And as I said, while I'm at it, I'll just go ahead and add the getter for spell points and it will
be called get spell points.
And all we need to do is implement this in our character.
So we'll go to.
Character or a character and implement this from the player interface.
It's going to be a virtual int 32 called get attribute points implementation and a virtual int 32 called
get spell points implementation.
We can implement these two.
I'll just do them one at a time here.
And what do we do?
We get our aura player state and for get attribute points we're going to return or a player state get
attribute points and for spell points.
Well, you catch the drift return or a player state.
Get spell points.
So now we have some nice interface functions that are implemented for Aura.
So on the ability system component, we can just see if our avatar actor implements that interface.
We can say if get avatar actor call implements use you player interface.
Notice the header was included there for me and then we can check our attribute points.
We can say if I player interface execute get attribute points passing in the avatar with get avatar
actor.
So this gets our attribute points and we can see if that's greater than zero.
If it is greater than zero, then we can inform the server and say, Hey server, we need to upgrade
one of our attributes, right?
We need to increase one of our attributes, the one corresponding to this attribute tag.
And we also need to decrement our attribute points on the player state, which of course will use our
interface to do that.
But all of that is important stuff that should be done on the server only.
So I'm going to go into aura ability system component and make our server RPC that we can call called
server upgrade attribute.
So we'll create that right here.
Void server upgrade attribute and it'll take a const gameplay tag.
Now this gets a new function and it's going to be server reliable.
So we can generate the definition for this.
And if we have attribute points, then we'll call server upgrade, attribute passing in attribute tag.
So what are we going to do in server upgrade attribute?
Well, you may have had some ideas in your head leading up to this point as to how we're going to upgrade
our attributes, and that's great.
You may have a perfectly valid solution to this in your head and you may even want to give that a try
and do it a little differently than how I'm going to do it.
That's totally fine.
Now, the way I like to do it, however, is similar to what we're doing for our experience.
You see, we have our passive gameplay ability that's listening for events and sending events to an
actor is really easy to do.
So if I just send an event to an actor on the server, then our gameplay ability can listen for an event
with that specific gameplay tag that that event has and apply a gameplay effect using information in
that event.
So that's how I'd like to handle this.
I'd like to send an event, so I'm going to create an gameplay event data called payload.
And I need to take my payload and set its event tag.
Now the tag is going to be the attribute.
My passive gameplay ability is already listening for attribute tags.
Any tag that has attribute at its highest level in the tag hierarchy.
So we're going to set the event tag to attribute tag and the magnitude is going to simply be one.
We're going to take payload dot magnitude.
It's actually event magnitude and we're going to set that to one.
And this will result in our gameplay ability.
The passive one, it's called Listen for Events.
Remember to receive this gameplay event once we send it and then we can configure it to apply a gameplay
effect and modify one of our primary attributes.
So I'm going to use you ability system.
Blueprint library.
Notice the header was included automatically.
We're going to use sin gameplay event to actor.
We're going to use the avatar actor.
So get Avatar actor.
This will be attribute tag.
And finally, the payload.
We're going to send that.
So this will send the event.
We need to make sure that we handle receiving that event.
But that will allow us to increase one of our primary attributes.
Now, there's one more thing that we should do, and that's decrease our attribute points by one because
we're spending one, right?
So what we should do here is we should check to see if our Avatar actor implements the player interface.
So get Avatar actor.
We'll use implements you player interface.
And then we can take a player interface and call execute.
And two attribute points we have to pass in the Avatar actor first and then for the number of points
to add, it's going to be negative one.
So we'll subtract one from our attribute points.
All right.
So we need to make sure that we can handle a gameplay event with one of our primary attribute tags.
Let's go ahead and launch the editor.
All right.
So back in the editor, we know we're sending a gameplay event, right?
And we're listening for gameplay events.
If we go to ability system or a abilities passive start up, we have to listen for event.
We're listening for any event that has attributes in its tag at the highest level of the hierarchy.
Once we get that payload, we then assign a tag set by color magnitude to a gameplay effect spec we're
creating and then we apply a gameplay effect spec to self.
Now we're creating the gameplay effect based on our gameplay effect class called G event based effect.
Now we can open that and see that we have one modifier for incoming XP and it's using the set by color
magnitude.
We can add more modifiers, we can add one for each of our four primary attributes and they can be set
by color based.
So I'm going to add four modifiers.
The first is going to affect our strength attribute.
It's going to be Add.
And for modifier magnitude, it'll be set by color.
And the set by color magnitude is going to be the attribute tag for strength.
So that's attributes primary strength and we'll do the same thing for the other four attributes so I
can time lapse this.
Okay, so now that our event based effect has four more modifiers, one for each of our primary attributes
and they all have set by color magnitude calculation types, each of them listening for their own respective
attribute tag.
Now we want to actually send that gameplay event and we have to send that event and in order to send
that event, we have to call the blueprint callable function on our widget controller.
So this takes us all the way back to attribute menu widget controller where we have our blueprint callable
function upgrade attribute.
So the last piece of this puzzle is to call that that's going to be in our individual rows so we can
go into wbhp.
Text value, not the text value.
Row.
Not the attribute points.
Row.
Not the framed value.
Just going through my tabs here.
Here it is.
Text Value Button Row.
So all we need to do in this class is make sure that whenever the button gets clicked, we call that
blueprint callable function on the attribute menu widget controller.
And we know that this widget has access to the attribute menu widget controller.
We're getting it with our aura ability system library function.
We're not actually setting our own widget controller, we're just getting it and binding to a delegate
directly.
Well, now that we want to call a function on it a blueprint callable function, we're going to promote
it to a variable.
So I'm going to let's move some of these nodes out of the way that I'm not interested in using right
now, and I'm going to put a sequence node here.
And move that back.
And after getting the attribute menu widget controller, I'm going to promote that to a variable called
attribute menu widget controller.
And that's going to be the first thing in my sequence here.
I'm also going to replace this wire with attribute menu widget controller.
So it's no longer messy.
This will be my second thing I do in the sequence.
And the third thing is going to be to get my button.
Get its button widget called Button.
And from the button I'm going to drag off and type onclicked and assign an event to its onclicked.
We're going to go ahead and do that next.
And what will we do when this button is clicked?
We're going to take our widget controller, call the blueprint callable function upgrade attribute and
pass in the attribute tag that this widget has.
And that's it.
Now things should all be tied together.
So with a couple of reroute nodes.
Like so.
There we go.
Cleaning it up a bit.
We should now be able.
To upgrade our attributes.
Let's see how this works.
So with my attribute menu open, I'm going to level up.
Okay, leveled up.
Now I'm going to click plus for my strength.
And the strength went up.
My attribute points went down and my buttons all got disabled.
That is perfect.
Now I'm going to level up twice so I can have two attribute points.
There we go.
And I'm going to do this twice.
I'm going to upgrade my intelligence boom and my strength boom.
And of course we can always check to see that our other attributes are upgrading along with the primaries.
For example, resilience will affect armor and armor penetration.
If I go ahead and upgrade resilience, those go up in turn.
So now we have a functional attribute menu and it works and it's great.
And I think this is an excellent milestone and a good spot for us to take a look at our attribute menu
and make sure that it looks and sounds and feels excellent.
Now it looks pretty good.
We could probably tweak some of the colors and things, but I said sounds and well, there are no sounds.
So in the next video we'll tweak how it looks.
The cosmetics add some sound effects for hovering and clicking on buttons and things like that, and
make sure we're really happy with our attribute menu because after that we're done with it and we can
move on.
Excellent job and I'll see you in the next video.