WEBVTT

00:06.790 --> 00:07.720
Welcome back.

00:08.180 --> 00:12.620
Now our attributes are sort of behaving the way they should.

00:12.650 --> 00:15.400
They're grayed out when we have no points.

00:15.410 --> 00:21.080
They're not grayed out when we have points, but they don't do anything when we click on them.

00:21.080 --> 00:25.340
And that is something we are going to fix now.

00:25.520 --> 00:28.910
We need a way to upgrade our attributes.

00:28.910 --> 00:36.380
And what I'd like is a function on my widget controller, specifically my attribute menu widget controller

00:36.410 --> 00:40.070
that I can call whenever one of these buttons gets clicked.

00:40.100 --> 00:44.630
In other words, we can make a blueprint callable function to upgrade attributes.

00:44.660 --> 00:47.480
That's what we're going to do in this video.

00:47.750 --> 00:55.040
Now, if we call some function, whenever we click on a button, we should probably send information

00:55.040 --> 01:00.080
to the widget controller so it knows which of these has had its button pressed.

01:00.230 --> 01:04.680
Well, we know that each of these widgets have an attribute.

01:04.700 --> 01:05.900
Gameplay tags.

01:05.900 --> 01:06.230
Right?

01:06.260 --> 01:11.550
This is a text value button row which has its own attribute tag variable.

01:11.820 --> 01:19.530
So let's create a function we can call from Blueprint to send that info down and upgrade our attributes.

01:19.830 --> 01:22.950
So I'm going to get my attribute menu widget controller.

01:22.950 --> 01:29.130
I'm going to go ahead and just close other tabs and make a public function that we can call to upgrade

01:29.130 --> 01:30.120
attributes.

01:30.420 --> 01:35.670
It's going to be void and I'm just going to call it upgrade attribute.

01:36.240 --> 01:40.820
Now to upgrade an attribute, I want to know which attribute we want to upgrade.

01:40.830 --> 01:48.540
So this will take a const reference to an gameplay tag and this tag will be called attribute tag.

01:49.320 --> 01:57.070
Now I need to make sure that I have gameplay tag either included, which I don't or forward declared.

01:57.090 --> 02:00.950
Now it's a reference so we can forward declare gameplay tag.

02:00.960 --> 02:02.460
Let's go ahead and do that.

02:02.490 --> 02:05.550
We'll say struct f gameplay tag.

02:06.300 --> 02:10.710
Now this function is going to be a new function with blueprint callable.

02:10.950 --> 02:16.830
We plan on calling this from our widgets and I'm going to generate the definition for it.

02:17.130 --> 02:21.150
Now what exactly are we going to do when we call this function?

02:21.390 --> 02:27.450
Well, really, it's the ability system component that needs to know about this.

02:27.540 --> 02:33.390
The reason the ability system component needs to know about it is because the ability system component

02:33.390 --> 02:42.510
is capable of doing things related to attributes such as applying effects or sending gameplay events.

02:43.100 --> 02:49.940
So I'm going to make a function on the ability system component that we can call for upgrading attributes.

02:49.970 --> 02:58.100
Let's open our ability system folder and get our ability system component open and create a public function

02:58.100 --> 02:59.390
we can call here.

02:59.630 --> 03:02.120
Now, this will be also a void function.

03:02.120 --> 03:04.190
In fact, it's going to be the same function.

03:04.190 --> 03:07.550
I'm going to get my void upgrade attribute.

03:08.220 --> 03:11.040
Function signature here and just paste it.

03:11.040 --> 03:16.290
It's going to be the same function and I'll go ahead and generate the definition for it.

03:16.380 --> 03:21.090
Now our attribute menu widget controller is just going to call this function.

03:21.090 --> 03:28.200
That's all the attribute menu widget controller needs to do, but it does need to cast our ability system

03:28.200 --> 03:31.430
component to an aura ability system component.

03:31.440 --> 03:40.170
So I'm going to say you aura ability system component, aura, ASC equals and I'm going to cast checked.

03:42.230 --> 03:47.900
To you or a ability system component, and I'm going to cast the ability system component.

03:48.110 --> 03:55.790
And after that I can take or ask and simply call upgrade, attribute passing in the attribute tag.

03:58.770 --> 04:03.800
So that's all that our middleman class attribute menu widget controller needs to do.

04:03.810 --> 04:10.260
The rest of this is on the ability system component so I can even close attribute menu widget controller.

04:10.290 --> 04:15.000
Now we're working in the AC, so what is the AC need to do?

04:15.240 --> 04:21.330
Well, keep in mind that when we click on this button in our widget controller calls this function,

04:21.330 --> 04:27.300
we may be on a client or we may be on the server because we may be on a client.

04:27.330 --> 04:32.520
We're going to want to make sure definitely that something happens on the server.

04:32.520 --> 04:39.720
But before we go and say send an RPC up to the server, we should check here in upgrade attribute to

04:39.720 --> 04:42.680
make sure that we have any attribute points.

04:42.690 --> 04:48.510
If our attribute point count is zero, why should we send an RPC up to the server that's wasteful?

04:48.690 --> 04:53.010
So we need to see if our character has those points.

04:53.400 --> 04:59.710
Now, I don't really want my ability system component to be dependent on, say, my player state or

04:59.710 --> 05:00.850
anything like that.

05:00.850 --> 05:07.240
I'd rather just add an interface function that I can easily call to see if we have attribute points.

05:07.240 --> 05:14.410
So my player interface would be a perfect place to add a getter function for attribute points.

05:14.410 --> 05:18.220
We can already get attribute points, reward spell points reward.

05:18.220 --> 05:21.060
We can even add to attribute points and spell points.

05:21.070 --> 05:26.590
What we want are getters, and while I'm at it, I'm just going to add a getter for spell points as

05:26.590 --> 05:27.160
well.

05:27.160 --> 05:32.920
So this will be an int 32 returning function called get attribute points.

05:33.880 --> 05:38.470
It's going to be const and it's going to be a blueprint Native event.

05:40.790 --> 05:47.270
And as I said, while I'm at it, I'll just go ahead and add the getter for spell points and it will

05:47.300 --> 05:49.130
be called get spell points.

05:50.600 --> 05:53.690
And all we need to do is implement this in our character.

05:53.690 --> 05:55.280
So we'll go to.

05:55.310 --> 06:00.600
Character or a character and implement this from the player interface.

06:00.620 --> 06:08.480
It's going to be a virtual int 32 called get attribute points implementation and a virtual int 32 called

06:08.480 --> 06:11.030
get spell points implementation.

06:11.030 --> 06:13.010
We can implement these two.

06:15.460 --> 06:17.080
I'll just do them one at a time here.

06:19.510 --> 06:20.790
And what do we do?

06:20.800 --> 06:30.070
We get our aura player state and for get attribute points we're going to return or a player state get

06:30.070 --> 06:33.850
attribute points and for spell points.

06:34.780 --> 06:39.670
Well, you catch the drift return or a player state.

06:41.200 --> 06:43.000
Get spell points.

06:43.810 --> 06:49.650
So now we have some nice interface functions that are implemented for Aura.

06:49.660 --> 06:56.230
So on the ability system component, we can just see if our avatar actor implements that interface.

06:56.260 --> 07:04.990
We can say if get avatar actor call implements use you player interface.

07:06.070 --> 07:12.310
Notice the header was included there for me and then we can check our attribute points.

07:12.340 --> 07:22.720
We can say if I player interface execute get attribute points passing in the avatar with get avatar

07:22.720 --> 07:23.470
actor.

07:23.620 --> 07:28.360
So this gets our attribute points and we can see if that's greater than zero.

07:29.110 --> 07:35.890
If it is greater than zero, then we can inform the server and say, Hey server, we need to upgrade

07:35.890 --> 07:37.870
one of our attributes, right?

07:37.900 --> 07:44.060
We need to increase one of our attributes, the one corresponding to this attribute tag.

07:44.060 --> 07:51.290
And we also need to decrement our attribute points on the player state, which of course will use our

07:51.290 --> 07:52.730
interface to do that.

07:52.730 --> 07:56.780
But all of that is important stuff that should be done on the server only.

07:56.780 --> 08:04.580
So I'm going to go into aura ability system component and make our server RPC that we can call called

08:04.580 --> 08:06.630
server upgrade attribute.

08:06.650 --> 08:08.390
So we'll create that right here.

08:08.420 --> 08:15.320
Void server upgrade attribute and it'll take a const gameplay tag.

08:16.740 --> 08:20.970
Now this gets a new function and it's going to be server reliable.

08:22.850 --> 08:25.400
So we can generate the definition for this.

08:25.400 --> 08:34.520
And if we have attribute points, then we'll call server upgrade, attribute passing in attribute tag.

08:35.570 --> 08:39.320
So what are we going to do in server upgrade attribute?

08:39.350 --> 08:46.010
Well, you may have had some ideas in your head leading up to this point as to how we're going to upgrade

08:46.010 --> 08:48.290
our attributes, and that's great.

08:48.290 --> 08:55.520
You may have a perfectly valid solution to this in your head and you may even want to give that a try

08:55.520 --> 08:57.800
and do it a little differently than how I'm going to do it.

08:57.800 --> 08:59.090
That's totally fine.

08:59.120 --> 09:06.260
Now, the way I like to do it, however, is similar to what we're doing for our experience.

09:06.350 --> 09:14.300
You see, we have our passive gameplay ability that's listening for events and sending events to an

09:14.300 --> 09:17.330
actor is really easy to do.

09:17.360 --> 09:24.420
So if I just send an event to an actor on the server, then our gameplay ability can listen for an event

09:24.420 --> 09:31.770
with that specific gameplay tag that that event has and apply a gameplay effect using information in

09:31.800 --> 09:33.040
that event.

09:33.060 --> 09:35.210
So that's how I'd like to handle this.

09:35.220 --> 09:42.570
I'd like to send an event, so I'm going to create an gameplay event data called payload.

09:43.930 --> 09:47.500
And I need to take my payload and set its event tag.

09:47.650 --> 09:50.830
Now the tag is going to be the attribute.

09:50.860 --> 09:55.530
My passive gameplay ability is already listening for attribute tags.

09:55.540 --> 10:00.910
Any tag that has attribute at its highest level in the tag hierarchy.

10:00.910 --> 10:09.010
So we're going to set the event tag to attribute tag and the magnitude is going to simply be one.

10:09.010 --> 10:11.950
We're going to take payload dot magnitude.

10:12.040 --> 10:16.090
It's actually event magnitude and we're going to set that to one.

10:16.390 --> 10:19.810
And this will result in our gameplay ability.

10:19.810 --> 10:22.390
The passive one, it's called Listen for Events.

10:22.390 --> 10:29.350
Remember to receive this gameplay event once we send it and then we can configure it to apply a gameplay

10:29.350 --> 10:33.340
effect and modify one of our primary attributes.

10:33.640 --> 10:38.230
So I'm going to use you ability system.

10:39.480 --> 10:40.920
Blueprint library.

10:41.430 --> 10:43.920
Notice the header was included automatically.

10:43.950 --> 10:46.740
We're going to use sin gameplay event to actor.

10:46.770 --> 10:49.510
We're going to use the avatar actor.

10:49.530 --> 10:51.480
So get Avatar actor.

10:52.050 --> 10:54.000
This will be attribute tag.

10:54.660 --> 10:56.760
And finally, the payload.

10:56.910 --> 10:58.140
We're going to send that.

10:58.350 --> 10:59.930
So this will send the event.

10:59.940 --> 11:03.110
We need to make sure that we handle receiving that event.

11:03.120 --> 11:09.120
But that will allow us to increase one of our primary attributes.

11:09.150 --> 11:14.970
Now, there's one more thing that we should do, and that's decrease our attribute points by one because

11:14.970 --> 11:16.800
we're spending one, right?

11:16.830 --> 11:24.370
So what we should do here is we should check to see if our Avatar actor implements the player interface.

11:24.390 --> 11:26.370
So get Avatar actor.

11:26.850 --> 11:30.570
We'll use implements you player interface.

11:34.120 --> 11:38.320
And then we can take a player interface and call execute.

11:40.470 --> 11:46.920
And two attribute points we have to pass in the Avatar actor first and then for the number of points

11:46.920 --> 11:50.040
to add, it's going to be negative one.

11:50.040 --> 11:53.610
So we'll subtract one from our attribute points.

11:53.820 --> 11:54.540
All right.

11:54.540 --> 12:00.960
So we need to make sure that we can handle a gameplay event with one of our primary attribute tags.

12:00.960 --> 12:03.300
Let's go ahead and launch the editor.

12:04.450 --> 12:05.140
All right.

12:05.140 --> 12:09.220
So back in the editor, we know we're sending a gameplay event, right?

12:09.220 --> 12:11.080
And we're listening for gameplay events.

12:11.080 --> 12:17.920
If we go to ability system or a abilities passive start up, we have to listen for event.

12:17.950 --> 12:24.700
We're listening for any event that has attributes in its tag at the highest level of the hierarchy.

12:25.000 --> 12:32.200
Once we get that payload, we then assign a tag set by color magnitude to a gameplay effect spec we're

12:32.200 --> 12:35.980
creating and then we apply a gameplay effect spec to self.

12:35.980 --> 12:43.210
Now we're creating the gameplay effect based on our gameplay effect class called G event based effect.

12:43.240 --> 12:50.740
Now we can open that and see that we have one modifier for incoming XP and it's using the set by color

12:50.740 --> 12:51.760
magnitude.

12:51.850 --> 12:58.570
We can add more modifiers, we can add one for each of our four primary attributes and they can be set

12:58.570 --> 12:59.650
by color based.

12:59.650 --> 13:02.080
So I'm going to add four modifiers.

13:02.170 --> 13:05.630
The first is going to affect our strength attribute.

13:05.630 --> 13:07.370
It's going to be Add.

13:07.610 --> 13:10.820
And for modifier magnitude, it'll be set by color.

13:10.820 --> 13:16.190
And the set by color magnitude is going to be the attribute tag for strength.

13:16.190 --> 13:22.430
So that's attributes primary strength and we'll do the same thing for the other four attributes so I

13:22.430 --> 13:23.870
can time lapse this.

13:30.480 --> 13:39.720
Okay, so now that our event based effect has four more modifiers, one for each of our primary attributes

13:39.720 --> 13:48.510
and they all have set by color magnitude calculation types, each of them listening for their own respective

13:48.510 --> 13:50.010
attribute tag.

13:50.040 --> 13:57.600
Now we want to actually send that gameplay event and we have to send that event and in order to send

13:57.600 --> 14:02.760
that event, we have to call the blueprint callable function on our widget controller.

14:03.060 --> 14:10.470
So this takes us all the way back to attribute menu widget controller where we have our blueprint callable

14:10.470 --> 14:12.930
function upgrade attribute.

14:13.140 --> 14:22.380
So the last piece of this puzzle is to call that that's going to be in our individual rows so we can

14:22.380 --> 14:24.060
go into wbhp.

14:25.620 --> 14:28.230
Text value, not the text value.

14:28.260 --> 14:29.100
Row.

14:29.130 --> 14:31.170
Not the attribute points.

14:31.200 --> 14:32.100
Row.

14:32.220 --> 14:33.840
Not the framed value.

14:33.840 --> 14:35.190
Just going through my tabs here.

14:35.190 --> 14:35.980
Here it is.

14:36.000 --> 14:37.770
Text Value Button Row.

14:38.810 --> 14:44.690
So all we need to do in this class is make sure that whenever the button gets clicked, we call that

14:44.690 --> 14:48.500
blueprint callable function on the attribute menu widget controller.

14:48.560 --> 14:53.360
And we know that this widget has access to the attribute menu widget controller.

14:53.360 --> 14:57.620
We're getting it with our aura ability system library function.

14:57.620 --> 15:02.870
We're not actually setting our own widget controller, we're just getting it and binding to a delegate

15:02.870 --> 15:03.740
directly.

15:03.740 --> 15:09.050
Well, now that we want to call a function on it a blueprint callable function, we're going to promote

15:09.050 --> 15:09.860
it to a variable.

15:09.860 --> 15:15.350
So I'm going to let's move some of these nodes out of the way that I'm not interested in using right

15:15.350 --> 15:19.700
now, and I'm going to put a sequence node here.

15:23.200 --> 15:24.820
And move that back.

15:24.970 --> 15:31.660
And after getting the attribute menu widget controller, I'm going to promote that to a variable called

15:31.660 --> 15:36.400
attribute menu widget controller.

15:36.790 --> 15:39.610
And that's going to be the first thing in my sequence here.

15:41.050 --> 15:45.370
I'm also going to replace this wire with attribute menu widget controller.

15:45.370 --> 15:47.290
So it's no longer messy.

15:49.040 --> 15:53.300
This will be my second thing I do in the sequence.

15:53.930 --> 15:58.880
And the third thing is going to be to get my button.

15:59.830 --> 16:02.620
Get its button widget called Button.

16:04.020 --> 16:10.830
And from the button I'm going to drag off and type onclicked and assign an event to its onclicked.

16:10.860 --> 16:13.110
We're going to go ahead and do that next.

16:13.560 --> 16:17.130
And what will we do when this button is clicked?

16:17.160 --> 16:24.300
We're going to take our widget controller, call the blueprint callable function upgrade attribute and

16:24.300 --> 16:28.500
pass in the attribute tag that this widget has.

16:30.310 --> 16:31.420
And that's it.

16:31.690 --> 16:34.990
Now things should all be tied together.

16:35.410 --> 16:37.720
So with a couple of reroute nodes.

16:40.140 --> 16:41.370
Like so.

16:48.870 --> 16:49.530
There we go.

16:49.530 --> 16:51.060
Cleaning it up a bit.

16:51.920 --> 16:53.750
We should now be able.

16:55.160 --> 16:57.410
To upgrade our attributes.

16:59.820 --> 17:01.500
Let's see how this works.

17:04.790 --> 17:08.000
So with my attribute menu open, I'm going to level up.

17:09.590 --> 17:10.940
Okay, leveled up.

17:10.940 --> 17:13.370
Now I'm going to click plus for my strength.

17:13.640 --> 17:15.200
And the strength went up.

17:15.200 --> 17:20.510
My attribute points went down and my buttons all got disabled.

17:20.870 --> 17:22.040
That is perfect.

17:22.070 --> 17:27.020
Now I'm going to level up twice so I can have two attribute points.

17:32.320 --> 17:33.310
There we go.

17:33.490 --> 17:35.410
And I'm going to do this twice.

17:35.420 --> 17:40.330
I'm going to upgrade my intelligence boom and my strength boom.

17:41.930 --> 17:50.030
And of course we can always check to see that our other attributes are upgrading along with the primaries.

17:50.030 --> 17:53.750
For example, resilience will affect armor and armor penetration.

17:53.750 --> 17:57.830
If I go ahead and upgrade resilience, those go up in turn.

17:58.190 --> 18:03.830
So now we have a functional attribute menu and it works and it's great.

18:03.830 --> 18:11.780
And I think this is an excellent milestone and a good spot for us to take a look at our attribute menu

18:11.780 --> 18:14.990
and make sure that it looks and sounds and feels excellent.

18:15.020 --> 18:16.790
Now it looks pretty good.

18:16.790 --> 18:23.660
We could probably tweak some of the colors and things, but I said sounds and well, there are no sounds.

18:23.660 --> 18:26.870
So in the next video we'll tweak how it looks.

18:26.870 --> 18:33.230
The cosmetics add some sound effects for hovering and clicking on buttons and things like that, and

18:33.230 --> 18:39.200
make sure we're really happy with our attribute menu because after that we're done with it and we can

18:39.200 --> 18:39.950
move on.

18:40.340 --> 18:43.620
Excellent job and I'll see you in the next video.
