WEBVTT

00:06.890 --> 00:07.960
Welcome back.

00:07.970 --> 00:15.470
Now our abilities have the concept of a level requirement and we've created a gameplay ability electrocute

00:15.500 --> 00:17.130
which really does nothing.

00:17.150 --> 00:21.140
It prints a string and ends itself after one second.

00:21.140 --> 00:24.770
But in our class defaults its ability tag has been set.

00:24.800 --> 00:28.610
We have an ability tag of abilities lightning electrocute.

00:28.790 --> 00:35.660
Not only that in our ability info we have an entry for electrocute which has a level requirement of

00:35.690 --> 00:36.410
two.

00:36.530 --> 00:44.480
Now that means when we level up our spell menu should show this icon change because it's assigned to

00:44.480 --> 00:45.290
electrocute.

00:45.290 --> 00:52.130
So if I were to, let's say, kill an enemy, level up now that I'm level two, I expect this to show

00:52.130 --> 00:55.460
at least eligible rather than seeing the locked icon.

00:55.460 --> 00:57.290
I want to see the lightning bolt.

00:57.320 --> 00:59.900
That's what we're concerned with now.

00:59.900 --> 01:01.940
So how are we going to do that?

01:01.940 --> 01:09.660
Well, our ability system component has access to all activatable abilities as well as the capacity

01:09.660 --> 01:11.010
to give abilities.

01:11.010 --> 01:17.520
So I'm going to close the editor, I'm going to close all tabs and I'm going to open up my ability system

01:17.520 --> 01:20.910
component or a ability system component.

01:20.910 --> 01:27.900
I'd like a function on this class that we can call to update our statuses, basically to go through

01:27.900 --> 01:35.610
those ability info entries and the ability information array in our data asset and see if we meet the

01:35.610 --> 01:37.710
level requirements for any of them.

01:38.010 --> 01:44.310
So I'm going to make a function here on the ability system component to update ability statuses.

01:44.730 --> 01:52.800
It's going to be void, I'm going to call it update ability statuses and it's going to take in an INT

01:52.800 --> 01:54.390
32 called level.

01:55.020 --> 01:59.420
So it needs to know what level to check against our level requirements.

01:59.430 --> 02:05.280
Let's go ahead and generate the definition and what is this function going to do.

02:05.310 --> 02:07.820
It's going to need to get ability info.

02:07.820 --> 02:17.090
So I'm going to use you or ability system library that results in the header include and we're going

02:17.090 --> 02:19.310
to get ability info.

02:19.520 --> 02:22.040
This requires a world context object.

02:22.040 --> 02:25.370
I'm just going to call get Avatar actor and pass in that.

02:25.760 --> 02:33.590
Now the ability info is something we can store in a local variable of type you ability info and I'll

02:33.590 --> 02:35.330
call it ability info.

02:36.830 --> 02:39.740
So what am I going to do with ability info?

02:39.830 --> 02:44.150
Well, I'd like to loop through its array because we have an array in ability info.

02:44.180 --> 02:45.620
Let's just go look at it.

02:45.620 --> 02:51.590
It's in data ability info dot h and it's called ability information.

02:51.770 --> 02:59.330
So I'd like to loop over this ability information because each struct in ability information has the

02:59.330 --> 03:01.940
level requirement that I need to check.

03:02.330 --> 03:07.010
So here in the ability system component, I'm going to loop in a for loop.

03:07.670 --> 03:11.030
For each f or ability info.

03:11.060 --> 03:19.640
This can be a const reference an ability infos ability information t array.

03:20.510 --> 03:22.070
And I need to give it a name.

03:22.070 --> 03:23.100
I'll call it info.

03:23.120 --> 03:27.380
So for each info I want to check the level requirement.

03:27.410 --> 03:33.390
Now what happens if we find an ability in ability info that we've already given?

03:33.410 --> 03:36.650
Perhaps one of the startup abilities like firebolt.

03:36.830 --> 03:40.190
Well, we want to do nothing in that case.

03:40.400 --> 03:42.980
So how do we know if we've done that?

03:43.830 --> 03:49.980
Well, it'd be nice if we could check to see if we have that gameplay ability already.

03:50.340 --> 03:56.280
Now, luckily the ability system component already has an array of activatable abilities.

03:56.310 --> 03:57.930
We can check that array.

03:58.380 --> 04:05.970
Now a clever way I'd like to do this is by creating a handy function that will return the gameplay ability

04:06.000 --> 04:08.940
spec based on the ability tag.

04:09.060 --> 04:14.130
And if we don't find one, we know that that gameplay ability hasn't been given yet.

04:14.840 --> 04:19.340
So I'm going to make a useful function in our ability system component.

04:19.370 --> 04:23.360
I'm going to put it up here next to our other get functions.

04:24.290 --> 04:30.770
It's not going to be static, but it's going to return an gameplay ability spec, but I'd like to return

04:30.770 --> 04:34.700
the spec as a pointer and we'll see why in a second.

04:34.730 --> 04:38.420
I'm going to call it get spec from ability tag.

04:39.200 --> 04:46.130
So this will take in a const gameplay tag by const reference called ability tag.

04:48.020 --> 04:53.990
So this function will be designed to return a pointer to a game playability spec corresponding to this

04:53.990 --> 04:55.180
ability tag.

04:55.190 --> 05:02.360
If this ability system component has that ability with that tag, otherwise it'll return a null pointer.

05:02.360 --> 05:07.760
So that's why I'd like to return a pointer as we can perform that null check and we'll consider a null

05:07.760 --> 05:11.140
pointer to mean that we don't have the ability with that tag.

05:11.150 --> 05:18.770
So let's go ahead and generate this definition and this function is going to loop over our activatable

05:18.770 --> 05:23.480
abilities, which means we want a scoped ability list lock.

05:23.510 --> 05:29.930
We want to lock it so that we don't run into complications from abilities being added or removed or

05:29.930 --> 05:32.420
changed while we're looping over them.

05:33.290 --> 05:37.130
So to create a scoped ability list lock, we've done this before.

05:37.130 --> 05:40.820
We create an scoped ability list lock.

05:41.240 --> 05:43.910
I'm going to call it active scope lock.

05:44.390 --> 05:47.300
We initialize it with the ability system component.

05:47.300 --> 05:50.240
So we dereference this and pass that in.

05:50.660 --> 05:53.930
Now we can loop over our activatable abilities.

05:53.960 --> 06:00.380
These are gameplay ability specs, so I'm going to use gameplay ability spec references.

06:00.410 --> 06:05.330
I'll call each one ability spec and we'll get activatable abilities.

06:07.670 --> 06:13.790
So we're looping over each ability spec now for each ability spec we need to get their ability tags

06:13.790 --> 06:15.520
and loop over those.

06:15.530 --> 06:17.720
So we're going to make another for loop.

06:18.020 --> 06:20.930
This is for gameplay tags.

06:21.710 --> 06:29.180
Each one will be called tag and we're going to loop over ability spec dot, ability dot get as.

06:29.210 --> 06:31.640
That's a pointer wrapper.

06:31.640 --> 06:32.090
Right?

06:32.090 --> 06:34.580
It's a t object pointer.

06:34.580 --> 06:43.010
And from this ability we're going to get ability tags and we'll check if the tag matches the tag we've

06:43.010 --> 06:44.360
had passed in.

06:44.360 --> 06:50.240
So we're going to say if tag dot matches tag ability tag.

06:53.250 --> 06:59.400
And we'll return the ability specs address because we're returning a pointer after all.

06:59.400 --> 07:03.660
So we'll use the address of operator and return a pointer.

07:03.690 --> 07:08.010
If we reach the end of this, we return a null pointer.

07:08.430 --> 07:15.540
So now we have a nice function to return the ability spec pointer based on a gameplay tag.

07:15.810 --> 07:22.830
We can really use this to check to see if a given ability with this tag exists on our ability system

07:22.830 --> 07:23.730
component.

07:24.850 --> 07:31.360
So back to update ability statuses as we're looping over all of the info in ability info's, ability,

07:31.360 --> 07:39.330
information array, we can check to see if we can get a valid pointer using this gameplay ability tag.

07:39.340 --> 07:44.170
We can say if and we can call get spec from ability tag.

07:44.660 --> 07:48.920
Passing an info dot ability tag.

07:49.620 --> 07:51.720
And if that's a null pointer.

07:52.560 --> 07:59.910
Then we know that we've stumbled across an ability that is not already here in our ability system components,

07:59.910 --> 08:01.890
activatable abilities.

08:02.250 --> 08:07.530
If it does not return null pointer, it's already in our activatable abilities and we don't need to

08:07.530 --> 08:08.190
do anything.

08:08.190 --> 08:10.710
We can just go to the next iteration of the loop.

08:11.340 --> 08:18.240
Now if it's null pointer, that means it doesn't exist in our activatable abilities and we need to check

08:18.240 --> 08:19.740
its level requirement.

08:20.490 --> 08:25.860
In fact, we can check its level requirement before even bothering to do this, which would be even

08:25.860 --> 08:27.150
more performant.

08:27.510 --> 08:39.120
So what we'll do is we'll check if level the level passed in is greater than or equal to info dot level

08:39.120 --> 08:40.200
requirement.

08:40.530 --> 08:44.160
If so, then we can continue working.

08:44.160 --> 08:45.630
We can put this inside of that.

08:45.630 --> 08:50.280
Now, if you don't like the nesting inside of the nesting here, we can move to the next iteration of

08:50.280 --> 08:50.910
the loop.

08:50.910 --> 08:57.240
If level is less than level requirement, I tend to like less nesting.

08:57.240 --> 09:04.530
So I'm going to bring this back out and I'll just continue to the next iteration of the loop with continue

09:04.860 --> 09:08.120
if level is less than level requirement.

09:08.130 --> 09:11.160
So we're looping over our ability information.

09:11.160 --> 09:17.370
If level is less than level requirement, just continue to the next element in ability information.

09:17.400 --> 09:18.660
Don't do anything else.

09:19.240 --> 09:27.070
Now, another thing is we can also continue early if our infos ability tag is not valid.

09:27.100 --> 09:34.420
So we can also say if info ability tag dot is valid and put a big fat not here.

09:34.750 --> 09:36.940
We can continue in that case to.

09:38.920 --> 09:44.920
And the spec from ability tag returns null, which means we don't already have that ability.

09:44.950 --> 09:47.500
Then finally we can give that ability.

09:47.530 --> 09:52.180
That involves making an ability spec from the ability in that info.

09:52.210 --> 09:57.700
We can say f gameplay ability spec, we'll call it ability spec.

09:58.890 --> 10:06.690
And we'll make one F gameplay ability spec and we'll make one using the ability in info because we now

10:06.690 --> 10:10.080
have info ability that subclass of.

10:10.170 --> 10:13.680
And since we're giving it for the first time, we'll give it at level one.

10:13.680 --> 10:16.140
Unless of course we're loading in from disk.

10:16.170 --> 10:18.420
Then we would load in that ability.

10:18.420 --> 10:22.440
But we're not saving and loading just yet, so hang tight on that one.

10:22.620 --> 10:29.790
Now that we have the ability spec, we can give the ability, but not before first setting its status.

10:29.790 --> 10:30.600
Right?

10:30.600 --> 10:37.500
And since we're updating ability statuses, we know that because that ability hasn't been given yet,

10:37.530 --> 10:39.990
we're going to consider it to have been locked.

10:39.990 --> 10:46.170
And now that we're leveling up and this ability is becoming eligible, we're going to give it that eligible

10:46.170 --> 10:46.830
tag.

10:46.830 --> 10:52.020
We're going to take ability spec, we're going to take its dynamic ability tags, we're going to call,

10:52.020 --> 10:56.910
add tag to it, and we're going to add F or a gameplay tags.

10:57.570 --> 11:05.010
We're going to get it and use abilities status, and it's going to be eligible now.

11:05.280 --> 11:07.710
So we're now changing its status.

11:08.310 --> 11:10.050
Okay, so that's pretty cool, right?

11:10.050 --> 11:12.660
We're setting its ability status to eligible.

11:12.660 --> 11:20.250
And finally after that, we can give the ability by calling, give ability, passing in ability spec

11:20.250 --> 11:26.640
and we'll have the ability, but it'll be eligible so we won't be able to actually activate it yet.

11:26.640 --> 11:29.880
But at least we have it and it has a status.

11:30.450 --> 11:37.080
Now, as soon as we add an ability and change something on that ability, there's a way to force it

11:37.080 --> 11:38.670
to replicate right away.

11:38.700 --> 11:45.390
We do that by calling mark ability spec dirty and passing in that ability spec.

11:45.600 --> 11:52.110
So if you ever want to force an ability spec to replicate now instead of waiting till the next update,

11:52.110 --> 11:57.330
you call mark ability spec and we're going to do that as it's important that our clients know right

11:57.330 --> 12:04.890
away if this change has occurred and if we do that, then we can start thinking about making a broadcast

12:04.890 --> 12:10.170
to our widget controller, our spell menu widget controller, so that it can update itself.

12:10.440 --> 12:13.980
So for now, I think this is a good stopping point.

12:13.980 --> 12:21.360
And the next video we're going to make a delegate we can broadcast when an ability status has changed

12:21.360 --> 12:28.020
and then our spell menu can update its widgets accordingly and we can start seeing icons in our spell

12:28.050 --> 12:31.120
tree for abilities that are now eligible.

12:31.120 --> 12:32.590
So we'll do that next.

12:32.740 --> 12:33.940
I'll see you soon.
