WEBVTT

00:06.940 --> 00:08.110
Welcome back.

00:08.350 --> 00:15.700
In this video, I'd like to make a custom calculation class so that we can have our max health and Max

00:15.700 --> 00:22.960
Mana not only dependent on other attributes, but other variables that are not attributes as well.

00:23.080 --> 00:29.710
So that's going to involve making some changes not only to our gameplay effect.

00:29.710 --> 00:37.630
If we go into default attributes here and open secondary attributes specifically or to secondary attributes,

00:37.660 --> 00:43.540
we have all of these modifiers and we have max health and Max Mana at the bottom.

00:43.570 --> 00:51.100
These have their modifier magnitude calculation type set to attribute based, but I'd like to use custom

00:51.100 --> 00:52.690
calculation class.

00:52.690 --> 00:58.720
So not only are we going to want to change this gameplay effect, but we're also going to want to create

00:58.720 --> 01:02.820
that custom calculation class and that's what we're going to do first.

01:02.830 --> 01:11.390
So to do that, we're going to go into our C plus plus classes folder into Aura public ability system

01:11.390 --> 01:17.030
as this is related to the ability system, we're going to right click and make a new C plus plus class.

01:17.030 --> 01:21.770
But we have to choose all classes and we can find the class we're interested in.

01:21.800 --> 01:30.170
If we type in Mod mag and we see that we have a gameplay mod magnitude calculation, this is that modifier

01:30.170 --> 01:34.310
magnitude calculation or MSI class that we're interested in.

01:34.310 --> 01:36.230
So we're going to choose that class.

01:36.230 --> 01:44.810
And here in ability system, we're going to put this in a sub folder called MSI for modifier magnitude

01:44.810 --> 01:45.470
calculation.

01:45.470 --> 01:52.430
If you don't like the acronym there, we can call it Mod mag Calc if you want to do that MSI.

01:52.880 --> 02:00.950
Either way, we'll go ahead and leave it at Mod Mag Calc and this is going to be the MSI for Max Health,

02:00.950 --> 02:05.900
So I'm just going to call it MSI, underscore Max Health.

02:06.260 --> 02:08.480
So let's go ahead and create this class.

02:08.480 --> 02:15.500
I'm going to go ahead and close the editor and I think I'll close all of my tabs up here so that way

02:15.500 --> 02:21.950
I'll have a clean slate and we can open our public folder open ability system.

02:21.950 --> 02:30.830
Here's our new mod mag calc folder and here's my new MSI called UMC Max Health.

02:30.830 --> 02:38.360
Now there's the you because this is based on the you gameplay mod magnitude calculation class.

02:38.480 --> 02:45.250
So Max health is going to be determined by the calculation we create here.

02:45.260 --> 02:54.170
Now I'm going to go ahead and alt o or control k o to open max health or MSI max health CPP.

02:54.170 --> 02:58.490
So I have both files open here and it's completely blank and empty.

02:58.490 --> 03:03.140
And if this is your first time creating one of these, you have no idea what you're supposed to do,

03:03.170 --> 03:03.710
right?

03:03.710 --> 03:08.300
And that's why we're going to do this together for the first time.

03:08.600 --> 03:17.510
Now, my Mod mag calc needs its own constructor and I'm going to make a public section and put my constructor

03:17.510 --> 03:18.020
in it.

03:18.020 --> 03:19.730
So first things first.

03:19.730 --> 03:27.530
We'll get our constructor declared like so and we'll go ahead and generate the definition for the constructor.

03:27.560 --> 03:27.890
Okay.

03:27.890 --> 03:29.180
That's step one.

03:29.330 --> 03:31.070
So far, so good.

03:31.460 --> 03:36.440
Now how do we actually calculate our custom calculation?

03:36.440 --> 03:37.580
Where do we put it?

03:37.580 --> 03:40.520
Well, we put it in a specific function that we override.

03:40.520 --> 03:42.320
It's going to be a virtual function.

03:42.320 --> 03:43.790
It returns float.

03:43.820 --> 03:44.210
Why?

03:44.240 --> 03:50.300
Because it returns the results that our modifier should produce.

03:50.300 --> 03:57.140
So in this case, all of the calculations that result in this float value we're going to determine here

03:57.140 --> 04:03.590
in this function and it's called calculate base magnitude implementation.

04:03.770 --> 04:12.260
Now I just let Autocomplete fill it out for me here in writer, but it's calculate base magnitude implementation

04:12.260 --> 04:19.070
and it takes an F gameplay effect spec look at that, we get the gameplay effect spec and that's going

04:19.070 --> 04:27.740
to be the effect spec of whatever gameplay effect that has a modifier using this custom calculation.

04:27.740 --> 04:33.020
So we have access to that gameplay effect spec, which means we have access to all the information inside

04:33.020 --> 04:36.050
of that and that's pretty great.

04:36.080 --> 04:40.310
Now mod mag Calcs can capture attributes.

04:40.310 --> 04:43.370
They have access to all the stuff in the effect spec.

04:43.400 --> 04:46.130
Yes, that's why they're so powerful.

04:46.160 --> 04:52.430
But they also have the ability to capture attributes and to capture attributes.

04:52.460 --> 04:57.410
We have to create a variable for the attribute we want to capture.

04:57.410 --> 05:00.290
So we're going to make a private section for that.

05:00.290 --> 05:05.480
And the variable type has to be and get ready because this is a long type.

05:05.480 --> 05:06.190
It's F.

05:06.860 --> 05:12.320
Game play effect, attribute capture definition.

05:12.320 --> 05:15.350
I'm going to go ahead and let Autocomplete fill that out.

05:15.350 --> 05:20.300
Now, this is a gameplay effect attribute capture definition.

05:20.300 --> 05:24.890
It's a struct that defines what attribute we're going to capture.

05:24.890 --> 05:29.990
And I'm going to call this vigor, def def, short for definition.

05:30.170 --> 05:33.020
Okay, So we've declared a new function.

05:33.020 --> 05:34.790
We've made a new variable.

05:34.790 --> 05:37.580
Let's create the definition for this function.

05:37.580 --> 05:40.700
And we don't want to return the super.

05:40.700 --> 05:44.180
We want to return the value that we calculate.

05:44.390 --> 05:49.460
Now if we're going to have this vigor def right now it's just an empty variable.

05:49.460 --> 05:57.380
We have to make sure we capture the vigor attribute and we do that here in the constructor we say vigor.

05:57.380 --> 06:01.760
Def dot attribute to capture.

06:01.760 --> 06:10.380
We specify the attribute to capture and we can access an attribute from or an attribute set with the

06:10.380 --> 06:19.170
static function u or attribute set colon colon get vigor attribute y.

06:19.200 --> 06:24.540
Can we do that because the attribute accessors macro that boilerplate macro.

06:24.540 --> 06:29.790
In case you forgot, I'm just going to show you real quick here in the ability system, here's our attribute

06:29.790 --> 06:33.000
set this one right here, Attribute Accessors.

06:33.000 --> 06:38.970
We know that attribute accessors consists of these macros and one of them is the property getter.

06:38.970 --> 06:39.570
Okay?

06:39.600 --> 06:47.940
This macro results in the creation of get Vigor attribute because we called it with the vigor attribute.

06:47.970 --> 06:51.390
This get vigor attribute is a static function.

06:51.390 --> 06:54.510
That kind of means a lot, right?

06:54.510 --> 07:00.840
It means we don't have to have a pointer to the object, the or attribute set object.

07:00.870 --> 07:04.770
We can just call the static function to get the attribute itself.

07:04.770 --> 07:08.070
That's why we can call it like that here.

07:08.070 --> 07:12.930
Now you or an attribute set is now included here.

07:12.930 --> 07:18.930
Make sure if you don't have fancy tools like writer doing these includes for you that you make sure

07:18.930 --> 07:20.970
to include that of course.

07:21.120 --> 07:29.760
And if we're capturing vigor, we have to define whether we're capturing vigor from the target or the

07:29.760 --> 07:30.600
source.

07:30.720 --> 07:39.720
Now, in our case for this, we're applying the gameplay effect from the aura character to the aura

07:39.750 --> 07:40.320
character.

07:40.320 --> 07:44.040
So they're both the same, but we're going to specify here.

07:44.040 --> 07:45.600
So we're going to say vigor.

07:45.600 --> 07:49.560
Def dot attribute source.

07:49.590 --> 07:59.490
We want to define the attribute source and we use an enum for this e gameplay effect attribute capture

07:59.490 --> 08:02.250
source and our options are source or target.

08:02.280 --> 08:09.150
These are settings that we see in the gameplay effect as well here in C plus plus there are enums,

08:09.480 --> 08:14.190
so we're going to choose target and we also should decide vigor.

08:14.190 --> 08:18.150
Def dot, we should decide whether or not to snapshot.

08:18.180 --> 08:22.620
Now I mentioned that we would talk about Snapshotting later.

08:22.620 --> 08:27.510
We're going to set this to false and Snapshotting has to do with timing.

08:27.660 --> 08:30.720
When do we want to capture the attribute?

08:30.720 --> 08:36.600
When the gameplay effect spec is created or when the gameplay effect spec is applied?

08:36.600 --> 08:40.410
Well, in our case, those two things happen one after the other.

08:40.410 --> 08:45.810
We create the gameplay effects back and we apply it immediately within the same function call, so it

08:45.810 --> 08:47.130
doesn't really matter.

08:47.340 --> 08:53.310
But later we're going to be creating gameplay effect specs and then not necessarily applying them immediately.

08:53.340 --> 08:59.520
For example, we might create an effect spec and set it on a fireball that flies through the air and

08:59.520 --> 09:03.840
then eventually that fireball may or may not hit something and then apply that effects back.

09:03.840 --> 09:09.120
And so the question is if we're capturing attributes in that gameplay effect, do we want to capture

09:09.120 --> 09:14.100
them when that gameplay effect spec was first created at that point in time?

09:14.100 --> 09:19.680
Or do we want to capture them when the effect is applied at that point in time?

09:19.800 --> 09:24.750
Snapshotting is capturing the attribute right away.

09:24.750 --> 09:33.060
As soon as the effect spec is created, not Snapshotting is getting the true value at the time of application

09:33.060 --> 09:34.170
of the effect.

09:34.170 --> 09:35.910
In our case, it doesn't matter.

09:35.910 --> 09:37.200
We're going to use false.

09:37.850 --> 09:45.530
Now after we've set these properties on vigor def then our modifier magnitude calculation needs one

09:45.530 --> 09:50.100
of its variables, which is an array of attributes to capture.

09:50.120 --> 09:57.420
We need to add this vigor def to it and that array is called relevant attributes to capture its a t

09:57.440 --> 10:01.730
array of type f gameplay effect attribute capture definition.

10:01.730 --> 10:04.670
That's the type that our vigor def has.

10:04.700 --> 10:07.670
So we're going to call Add and we're going to add vigor.

10:07.670 --> 10:08.270
Def.

10:11.320 --> 10:16.370
So we've created this VGA def, which is an F gameplay effect.

10:16.390 --> 10:18.520
Attribute capture definition.

10:18.520 --> 10:25.450
We've configured that capture definition and added it to our MKs array of capture definitions called

10:25.450 --> 10:27.310
relevant attributes to capture.

10:27.340 --> 10:35.590
This way, when the modifier is executed, when the effect is applied, then we will be sure to have

10:35.590 --> 10:43.420
VGA captured from the target at the time of application and we can access that here in our calculate

10:43.420 --> 10:46.230
base magnitude implementation function.

10:46.240 --> 10:50.620
Now we have things that we can do here in this function.

10:50.620 --> 10:57.430
We can get any gameplay tags that the source or the target have, and we're not going to use gameplay

10:57.430 --> 11:03.700
tags on the source and target for this MSI, but just in case you may want to do so in the future,

11:03.700 --> 11:05.710
we're going to learn how to do it anyway.

11:05.710 --> 11:11.900
So let's make a comment that says Gather tags from source and target.

11:12.410 --> 11:15.470
They can affect things if you want them to.

11:15.470 --> 11:23.780
So first we make an F gameplay tag container and that's going to be it has to be a pointer and we call

11:23.780 --> 11:24.740
it source tags.

11:24.740 --> 11:31.190
So I made it a const pointer and we can get it from the spec because the gameplay effect spec has the

11:31.190 --> 11:39.560
captured tags from the source and the target we access them with the spec dot captured source tags,

11:39.560 --> 11:45.590
dot get aggregated tags and any tags that that source has.

11:45.620 --> 11:48.110
We now have in this gameplay tag container.

11:48.110 --> 11:50.270
We can do the same thing for target tags.

11:50.270 --> 11:57.260
We can say F gameplay tag container, it's got to be a pointer and we're going to call this target tags

11:58.310 --> 12:06.290
and we can get it from spec dot captured in this case, captured target tags, dot get aggregated tags.

12:06.290 --> 12:07.790
That's how you get the tags.

12:08.240 --> 12:16.460
Now, in order to capture an attribute and get that attributes magnitude its value, we have to create

12:16.460 --> 12:20.600
something called an F aggregator, evaluate parameters.

12:20.600 --> 12:27.230
So we have an F aggregator, evaluate parameters.

12:27.230 --> 12:31.550
We're going to call this evaluation parameters.

12:31.880 --> 12:38.990
And when we create one of these, the evaluation parameters has its own source tags and target tags.

12:38.990 --> 12:47.090
So we pass those on, so we get our source tags and pass those in and we take our evaluation parameters.

12:48.660 --> 12:54.180
Dot target tags, and we also set that using our target tags.

12:56.930 --> 13:05.240
So these are parameters that we have to pass in to a specific function in order to capture the attribute

13:05.240 --> 13:06.230
we're interested in.

13:06.230 --> 13:12.770
In our case, it's vigor and we get that captured value with the function get captured.

13:14.000 --> 13:20.660
Attribute magnitude and this takes the gameplay effect attribute capture definition.

13:20.660 --> 13:21.290
We have that.

13:21.290 --> 13:22.790
That's the vigor def.

13:22.940 --> 13:24.410
So we get that.

13:24.920 --> 13:28.190
We also have to pass in the gameplay effect spec.

13:28.220 --> 13:29.750
Good thing we have that right.

13:29.750 --> 13:35.810
So we pass that in and then it requires those aggregator evaluate parameters.

13:35.810 --> 13:40.070
So that's why we have to pass in our evaluation parameters.

13:41.660 --> 13:46.230
And then finally, how are we going to get that actual value for vigor?

13:46.250 --> 13:51.140
Well, we pass in a float by reference and it's non-const reference.

13:51.140 --> 13:58.970
This function is going to set that float equal to the magnitude or value of vigor at the time it was

13:58.970 --> 13:59.690
captured.

13:59.690 --> 14:04.790
So what we do is we make a local float non-const called vigor.

14:05.330 --> 14:10.310
We initialize to zero because we're good and never have uninitialized variables.

14:10.310 --> 14:11.960
And then we pass in vigor.

14:11.960 --> 14:18.870
And after calling this function, vigor will now have the value of the vigor attribute on the target.

14:19.110 --> 14:23.160
We can always run in debug mode and see if that is the case.

14:23.160 --> 14:31.080
But for now we're going to assume that it is and we're going to take that vigor and usually sometimes

14:31.080 --> 14:39.750
we clamp it so we can take vigor and set it equal to f math and a common trick to make sure that this

14:39.750 --> 14:47.880
is never a negative value is we use Max so we can use Max specifying float, which takes two values

14:47.880 --> 14:49.740
and returns the maximum.

14:49.740 --> 14:52.740
And we would pass in vigor and zero.

14:52.740 --> 14:57.330
And that way, if vigor is less than zero, then we set it to zero.

14:57.330 --> 15:00.330
So that's a common thing that you'll see happen.

15:00.330 --> 15:02.430
So now we have the value of vigor.

15:02.460 --> 15:03.780
That's step one.

15:03.780 --> 15:11.910
But as I mentioned, we want max health to be dependent not only on vigor but also on the player's level.

15:11.910 --> 15:19.320
And that's the whole reason we created the combat interface, because we can always get the source object

15:19.320 --> 15:21.690
of this gameplay effect.

15:21.720 --> 15:31.050
We can get that from the spec, we can say spec dot, get context, dot get source object.

15:31.050 --> 15:35.220
And the source object, as we can see, is a new object.

15:35.220 --> 15:41.610
And as long as this gameplay effect has a source object, we can cast it to that interface.

15:41.610 --> 15:46.800
So in our case, the source object is going to be, well, aura, right?

15:46.800 --> 15:48.000
The Aura character.

15:48.000 --> 15:58.260
So we're going to cast to our interface and we're casting to a combat interface.

15:58.260 --> 16:01.050
And of course the header was auto included.

16:01.050 --> 16:02.880
So there it is there.

16:02.880 --> 16:09.510
And I'm going to create an eye combat interface, local variable called interface.

16:10.960 --> 16:14.200
Actually we'll call it combat interface to be exact.

16:14.200 --> 16:22.570
And then we can have access to the level by saying const int 32 player level equals and we can take

16:22.570 --> 16:25.630
our combat interface and call get player level.

16:25.720 --> 16:27.460
So just like that.

16:28.060 --> 16:35.980
So now that we have our level and our vigor, we decide what this custom calculation returns.

16:35.980 --> 16:42.520
It returns a float here, which means we can have a return statement and we can calculate the value

16:42.520 --> 16:46.780
returned for this modifier calculation however we want.

16:46.900 --> 16:57.670
So the design that I'd like is to have a base value of 80 F plus, and I'd like to have my vigor multiplied

16:57.670 --> 16:58.600
by 2.5.

16:58.630 --> 17:01.930
So I'm going to say 2.5 F times vigor.

17:02.890 --> 17:05.800
And I'd also like to add ten times.

17:05.800 --> 17:08.710
So ten point F times player level.

17:09.190 --> 17:13.430
So now our calculation can be whatever we want it to be.

17:13.430 --> 17:15.950
We could make this as complicated as we want.

17:15.980 --> 17:18.650
We have full freedom here in C plus plus.

17:18.890 --> 17:22.490
What I want to do is just have a base value of 80.

17:22.490 --> 17:26.300
And for every vigor point that we have, we get 2.5.

17:26.300 --> 17:29.060
And for every player level we have, we get ten.

17:29.060 --> 17:35.930
So as the player levels up, maybe they gain some points that they can spend on their attributes and

17:35.930 --> 17:37.430
they upped their vigor.

17:37.520 --> 17:43.580
If they spend one point and up the vigor by one, then their max health will go up by 2.5.

17:43.610 --> 17:50.120
If the player levels up and their level goes up from 1 to 2, then they get ten more added to their

17:50.120 --> 17:50.660
max health.

17:50.660 --> 17:53.360
So that's how I'd like this to behave.

17:53.420 --> 18:00.800
And now we have a custom calculation that we can use in a modifier for max health.

18:00.800 --> 18:04.040
So the next thing to do is to test this out.

18:04.040 --> 18:08.060
So I'm going to run in debug mode and let's see how this works.

18:09.590 --> 18:11.270
Okay, so we're back in the editor.

18:11.270 --> 18:17.630
Let's open our G ora secondary attributes and go down to our modifiers.

18:17.630 --> 18:21.410
And it looks like I have my max health modifier already open.

18:21.500 --> 18:23.960
And let's go through the settings.

18:23.960 --> 18:31.010
Its attribute is max health modifier OP is override, but magnitude calculation type is attribute based.

18:31.040 --> 18:32.930
That's not what we want anymore.

18:32.930 --> 18:36.800
We now want to choose custom calculation class.

18:36.950 --> 18:38.900
Now our options are different.

18:38.900 --> 18:44.990
As soon as we expand custom magnitude, we can now choose a calculation class.

18:44.990 --> 18:52.520
And if we expand the dropdown, the only option we have, aside from none, is our MSI called Max Health

18:52.700 --> 18:53.300
MSI.

18:53.330 --> 18:54.410
Max Health.

18:54.500 --> 18:56.210
Now here's the crazy thing.

18:56.210 --> 19:02.830
You can even sign coefficients and pre and post multiply additive values to this.

19:02.840 --> 19:10.230
So even though this is a arbitrarily complex calculation that we created, we can even scale it by a

19:10.230 --> 19:10.980
coefficient.

19:10.980 --> 19:16.890
Whatever it returns, we can scale it, we can add a post, multiply additive value, a pre multiply.

19:16.890 --> 19:20.730
It really is kind of crazy that we can do that.

19:20.760 --> 19:23.910
Now remember, we captured the source and target tags.

19:23.910 --> 19:24.720
We'll check this out.

19:24.720 --> 19:32.280
We have dropdowns for those and we can choose, require and ignore tags require tags are tags that must

19:32.280 --> 19:35.910
be present on the source in the case of the source tags.

19:35.940 --> 19:42.450
In order to have this modifier applied, Ignore Tags says none of these tags may be present, so there's

19:42.450 --> 19:49.470
the ability to say if the target has a specific tag, then we cannot apply this modifier.

19:49.470 --> 19:53.640
So there's just yet even more options for you.

19:53.760 --> 20:00.960
But now that we're using the custom calculation class, we should see something different for our max

20:00.960 --> 20:01.590
health.

20:01.620 --> 20:03.840
Let's just look at our calculation, Max.

20:03.840 --> 20:10.080
Health should be 80 plus 2.5 times vigor plus ten times player level.

20:10.080 --> 20:12.330
Let's see if the math works out there.

20:12.330 --> 20:20.670
I'm going to go ahead and press play and right away, since we're running in debug mode, I got a problem

20:20.670 --> 20:21.030
here.

20:21.030 --> 20:30.000
Combat interface is null and that's because we called get source object and I'm assuming our source

20:30.000 --> 20:32.010
object is null.

20:32.010 --> 20:38.430
Let's make sure let's hover over spec or either that or coming down here and expanding the dropdown

20:38.430 --> 20:39.270
for spec.

20:39.720 --> 20:44.280
And our source object will be buried deep in effect context.

20:44.310 --> 20:47.610
Let's expand its data and here's source object.

20:47.610 --> 20:52.830
And we see that its null pointer, which makes sense because we're not setting a source object.

20:52.830 --> 20:54.450
Where do we set the source object?

20:54.450 --> 20:55.980
This is something you should know.

20:56.010 --> 21:02.550
Remember, it goes back to where we're applying the effect and we're doing that in the character class.

21:02.580 --> 21:11.970
If we open the private folder, open character and go to Aura character dot CP, scroll down.

21:12.390 --> 21:15.660
Nope, it's actually Aura character base.

21:15.660 --> 21:16.290
Yes.

21:16.290 --> 21:18.060
Apply effect to self.

21:18.360 --> 21:23.850
Here we're applying the effect and here is where we have the opportunity to set a source object.

21:23.850 --> 21:24.420
Right?

21:25.080 --> 21:27.720
So let's make sure we're setting a source object.

21:27.720 --> 21:29.880
Let's go ahead and hit stop.

21:29.880 --> 21:33.090
And how do we set a source object?

21:33.120 --> 21:40.180
Can you remember if you can't remember, at least think back to where we did this before, right?

21:40.180 --> 21:42.580
Where did we set a source object before?

21:42.580 --> 21:46.300
If you thought about aura effect actor, you'd be right.

21:46.300 --> 21:51.010
We can go back to apply effect to Target where we added a source object here.

21:51.010 --> 21:54.220
We added it to the effect context handle.

21:54.220 --> 22:00.010
So we have our gameplay effect context handle which has add source object.

22:00.010 --> 22:02.350
So let's go back to Aura Character base.

22:02.350 --> 22:05.230
We have an gameplay effect context handle.

22:05.230 --> 22:10.690
Now here's the thing is we made it const, but now we need to change something on it so we're not going

22:10.690 --> 22:12.400
to make it const anymore.

22:12.400 --> 22:18.640
We're going to take context, handle and use add source object.

22:18.640 --> 22:21.760
And for the source object, this is very important.

22:21.760 --> 22:23.980
We have to add the character.

22:23.980 --> 22:24.220
Right?

22:24.220 --> 22:25.720
We have to add this.

22:25.750 --> 22:26.260
Why?

22:26.290 --> 22:32.590
Because the object itself, which will be aura in this case, or in the case of the enemy, the source

22:32.590 --> 22:39.790
object is the class that has the implemented interface function get player level from our combat interface.

22:39.790 --> 22:43.030
So that's why we need to use the character itself.

22:43.030 --> 22:48.430
So now when we apply the effect to self, it'll have a valid source object.

22:48.430 --> 22:55.090
So this was a pretty good learning exercise running in debug mode and capturing that problem, right?

22:55.090 --> 23:01.420
If we were not running in debug mode, we would simply have crashed the engine and we might not be really

23:01.420 --> 23:03.760
all that aware of what caused the crash.

23:03.760 --> 23:12.850
But since we did it this way here in Maxhealth, we were able to see that our cast to combat interface

23:12.850 --> 23:20.290
failed and we could dig deep into our gameplay effects spec to see that that source object was indeed

23:20.290 --> 23:20.800
null.

23:20.800 --> 23:25.240
So let's run in debug mode yet again and try this again.

23:26.460 --> 23:33.320
And keeping in mind that calculation, 80 plus 2.5 vigor plus ten player level.

23:33.330 --> 23:39.750
Let's make sure that that is checking out when we look at the value for max health.

23:40.860 --> 23:41.400
Okay.

23:41.400 --> 23:42.720
So first things first.

23:42.720 --> 23:52.110
I'm going to go back into blueprints, ability system, gameplay effects, default attributes, GE or

23:52.110 --> 23:52.940
a secondary.

23:52.950 --> 23:56.070
The reason is because we kind of crashed.

23:56.070 --> 24:01.410
I mean, we hit a breakpoint in debug mode and then closed the engine with that stop button.

24:01.410 --> 24:07.860
So that means that any changes we made that we didn't save are not going to be here.

24:07.860 --> 24:13.260
And as we can see, our max health modifier is back to being attribute based.

24:13.260 --> 24:20.310
So we need to set its magnitude calculation type to custom calculation class and expand that dropdown

24:20.310 --> 24:22.980
and set the class to max health.

24:22.980 --> 24:24.870
And that way we can use this.

24:24.870 --> 24:30.350
And you know, to avoid losing that progress, we can just save all and let's press play.

24:30.360 --> 24:30.780
All right.

24:30.780 --> 24:33.390
So we're so far, we're good.

24:33.390 --> 24:36.270
Let's see if we can see our max health value.

24:36.300 --> 24:40.540
We may not be able to because we just have too many attributes.

24:40.540 --> 24:40.930
Yes.

24:40.930 --> 24:43.210
So unfortunately.

24:43.300 --> 24:44.020
No, wait.

24:44.020 --> 24:45.370
I see it right here.

24:45.370 --> 24:46.180
Here it is.

24:46.180 --> 24:47.980
I don't know if you can see it on your screen.

24:47.980 --> 24:53.350
It might depend, but I see 112 .51 12.50.

24:53.380 --> 24:56.560
Let's see if 112 .50 makes sense.

24:56.560 --> 25:00.070
We have 80 plus 2.5 times vigor.

25:00.070 --> 25:01.870
And what was our vigor?

25:03.010 --> 25:11.620
I can't see it in debug, but I can know by checking on the vigor modifier here and this will be a lot

25:11.620 --> 25:15.850
easier once we make our attribute menu where we can see all these.

25:15.850 --> 25:18.010
But let's find it.

25:18.250 --> 25:20.950
It's actually our one of our primary attributes.

25:20.950 --> 25:22.390
So we'll open that.

25:22.540 --> 25:26.110
And here are our four modifiers.

25:26.110 --> 25:28.170
Vigor starts off at nine.

25:28.180 --> 25:30.370
Okay, so vigor starts at nine.

25:30.370 --> 25:34.630
So we have 80 plus 2.5 times nine.

25:36.710 --> 25:45.740
80 plus 2.5 times nine plus ten times player level.

25:45.740 --> 25:47.510
Now, our player level should just be one.

25:47.510 --> 25:50.150
We set a default value of one.

25:50.150 --> 25:54.440
Now I'm going to just pop up a calculator and see if we can calculate this.

25:54.440 --> 25:56.480
So I'm going to add that 80 at the end.

25:56.510 --> 26:03.740
First, I'm going to do nine times 2.5, nine times 2.5, 22.5 plus ten times one.

26:03.740 --> 26:05.540
So that's plus ten.

26:05.720 --> 26:08.060
32.5 plus 80.

26:09.330 --> 26:12.120
And that gives us one 12.5.

26:12.150 --> 26:13.470
Is that what we had?

26:13.500 --> 26:15.250
I believe it was.

26:15.270 --> 26:18.030
Let's just double check one 12.5.

26:18.060 --> 26:19.660
Yes, one 12.5.

26:19.680 --> 26:21.180
So the math adds up.

26:21.180 --> 26:22.560
It checks out.

26:22.560 --> 26:24.030
This is correct.

26:24.120 --> 26:26.720
And we also know that this is working properly.

26:26.730 --> 26:30.720
In fact, we can place a breakpoint here and simply start the game.

26:30.900 --> 26:36.750
That's going to trigger the breakpoint immediately because we apply this effect right away.

26:36.750 --> 26:38.970
And we can see all sorts of information.

26:38.970 --> 26:39.270
Right?

26:39.270 --> 26:42.770
We see that player level is one as we expected.

26:42.780 --> 26:47.550
We see that vigor is nine as again, we expected that.

26:47.550 --> 26:56.430
And of course we can hover over properties here in debug mode and expand dropdowns to get all the information

26:56.430 --> 27:00.390
at this point in time where the breakpoint was triggered right on this line.

27:00.980 --> 27:10.220
So as you can see, the mod magnitude calculation is a very powerful way to have a custom calculation

27:10.220 --> 27:16.250
type in one of our modifiers, and it does have its limitations.

27:16.250 --> 27:20.290
It can only modify a single attribute.

27:20.300 --> 27:28.970
So if we want to use more than one calculation, we'd have to add another modifier and modify the same

27:29.000 --> 27:35.690
attribute again, but for what we needed, which was to access a non attribute value that player's level.

27:35.690 --> 27:37.160
This works just fine.

27:37.160 --> 27:45.080
So that's how we can have our max health dependent on both vigor and level which exists on the player

27:45.080 --> 27:45.770
state.

27:45.800 --> 27:54.380
However, if this effect was applied to say, an enemy whose level is not on the player's state but

27:54.380 --> 27:56.900
instead on the character, it doesn't matter.

27:57.020 --> 28:00.900
This mod magnitude calculation doesn't care about that.

28:00.900 --> 28:04.500
It actually checks for the combat interface.

28:04.500 --> 28:08.640
So really that enemy would just have to implement the combat interface.

28:08.640 --> 28:12.390
And we're good, we're flexible, we're well coded.

28:12.690 --> 28:18.090
So now that we know how to do this for max health, we can do it for Max Mana.

28:18.680 --> 28:21.200
And this will be your quest.

28:21.590 --> 28:29.570
So you're going to create a mod mag, calc yourself, create an MSI for Max Mana, and this will be

28:29.570 --> 28:32.460
its own modifier magnitude calculation.

28:32.480 --> 28:38.780
Now you're going to want Max Mana dependent on some attribute and the player level.

28:39.050 --> 28:44.570
I'm using intelligence, so that means you're going to need to capture intelligence and you're going

28:44.570 --> 28:51.350
to need to decide on a calculation for how to calculate Max Mana in this calculation.

28:51.920 --> 28:55.760
So pause the video and conquer this quest now.

28:58.540 --> 28:59.230
All right.

28:59.230 --> 29:01.960
So we need to create an MC class.

29:01.960 --> 29:07.360
So I'm going to go back to C plus plus classes or a public ability system.

29:07.360 --> 29:10.600
And we have our mod mag calc folder.

29:10.600 --> 29:11.740
I'm going to put it here.

29:11.740 --> 29:20.020
So new C plus plus class choosing all classes and searching for mod mag not mag but mag.

29:20.020 --> 29:24.880
We can use gameplay mod mag calculation or magnitude calculation.

29:25.510 --> 29:30.070
Now I'm going to call this one MC underscore max mana.

29:30.100 --> 29:34.030
I just like to prefix mine with MC so we know what we're looking at.

29:34.030 --> 29:35.580
So let's create the class.

29:35.590 --> 29:41.770
I'm going to close the editor and we're going to do something very similar to what we did for Max Health.

29:41.770 --> 29:50.800
So let's go ahead and close out of some of these unused files and we'll open I'm going to actually close

29:50.800 --> 29:54.970
private and public just so they open all neat and tidy like this.

29:54.970 --> 30:04.450
And here's my MC Max Mana dot CP Control co brings open the header file as well, so I'm going to take

30:04.450 --> 30:11.980
max Mana dot CP all the way to the left and max mana dot h right next to it and we have our health right

30:11.980 --> 30:14.770
there for reference and we can just check.

30:14.770 --> 30:21.370
And if this is what you did for the challenge, congratulations, because that is exactly what I expected

30:21.370 --> 30:28.120
you to do, is to look at Max health and see how we did it here, because really that's what programming

30:28.120 --> 30:34.240
is all about, doing whatever is necessary to make your job easier, and you're always going to be able

30:34.240 --> 30:37.810
to look at other code, look at things you've done before.

30:37.840 --> 30:38.980
It'll help you out.

30:39.310 --> 30:42.850
So first we have a constructor here in Max Mana.

30:42.850 --> 30:45.040
We're going to implement that.

30:45.040 --> 30:46.780
We need a public section though.

30:47.650 --> 30:49.900
So we have our constructor there.

30:49.900 --> 30:53.230
We're going to generate the definition for that.

30:53.860 --> 30:54.910
Perfect.

30:54.940 --> 30:59.660
Now let's look at the next thing we want, which is this function we want to override.

30:59.680 --> 31:02.890
We can go ahead and copy that and paste it on in.

31:03.040 --> 31:04.000
Perfect.

31:04.000 --> 31:06.910
Let's go ahead and generate the definition for that.

31:06.910 --> 31:09.010
And remember, we don't want to call super here.

31:09.010 --> 31:11.920
We just want to return our calculation.

31:12.070 --> 31:18.010
And then next we had a private section with a gameplay effect attribute capture definition.

31:18.010 --> 31:22.600
I'm going to go ahead and copy that whole thing and paste it on in right here.

31:22.630 --> 31:28.090
The only difference is I don't want to capture vigor, so I'm not going to call this vigor def, I'm

31:28.090 --> 31:36.670
going to call it int def for intelligence, and that's what I'm going to capture in max Mana dot CP.

31:37.060 --> 31:38.920
Now back to Max Health.

31:38.920 --> 31:41.920
We can see exactly how we captured this stuff.

31:41.920 --> 31:49.120
We set the attribute to capture, we set the attribute source to Target, we set snapshot to false,

31:49.120 --> 31:54.380
and then we added our capture definition to the array of capture definitions in the MK.

31:54.950 --> 31:56.300
That's exactly what we're going to do.

31:56.300 --> 31:57.980
So let's copy it and paste it.

31:57.980 --> 32:00.560
And here's a nice trick we can do.

32:00.590 --> 32:08.510
After hitting alt enter to include the aura attribute set, I'm just going to use control H to replace

32:08.510 --> 32:13.280
all vigor here with.

32:13.280 --> 32:15.650
What is it that I want to capture?

32:15.680 --> 32:17.900
I want to capture intelligence.

32:17.960 --> 32:23.090
Actually I can just do INT but this will be changed to get int attribute.

32:23.090 --> 32:24.800
It has to be intelligence attribute.

32:24.800 --> 32:26.000
That's fine, I'll fix that.

32:26.000 --> 32:27.740
Let's click replace all.

32:27.740 --> 32:29.840
And then I just have one thing to fix.

32:29.840 --> 32:34.010
This has to be get intelligence attribute.

32:36.780 --> 32:39.180
Other than that, that was pretty smooth.

32:39.210 --> 32:40.440
So same thing.

32:40.440 --> 32:42.670
Just int instead of vigor.

32:42.690 --> 32:47.730
Now let's see what we did in the calculate base magnitude function.

32:47.730 --> 32:55.710
We got source and target tags, we made evaluation parameters and then we called get captured attribute

32:55.710 --> 32:59.970
magnitude, passing those in, creating a local vigor.

32:59.970 --> 33:02.580
We're going to make a local int this time.

33:02.700 --> 33:08.090
And then we got the player level using the source object, casting it to an interface.

33:08.100 --> 33:14.910
So why don't we just let's just copy the whole function and we'll paste it in here and we'll just change

33:14.910 --> 33:15.390
things.

33:15.390 --> 33:22.110
The first like half of the function is fine, but we don't want vigor, so our local variable will be

33:22.110 --> 33:22.740
called.

33:22.740 --> 33:30.750
I'm just going to call it int and we're going to pass in int def instead of vigor def and we're going

33:30.750 --> 33:38.290
to pass in int instead of vigor, we're setting vigor equal to the result of a max between int and zero.

33:38.290 --> 33:39.130
Did I say vigor?

33:39.160 --> 33:41.500
I'm meant int sorry, that was confusing.

33:41.500 --> 33:42.250
Let me say it again.

33:42.280 --> 33:46.330
We're setting our local int variable equal to the result of max.

33:46.330 --> 33:51.370
And the result of that is that we're making sure that it's not negative.

33:51.400 --> 33:58.060
If it is negative, then we will set it to zero and this keeps popping up.

33:58.060 --> 33:59.230
It's really annoying.

33:59.230 --> 34:05.440
Writer says, Hey dude, you're going to include the header anytime soon, so I'm going to hit alt enter

34:05.440 --> 34:11.830
and choose to not forward declare but include the header for combat interface.

34:12.340 --> 34:19.150
So once we've captured int successfully, then we can cast the source object to a combat interface.

34:19.150 --> 34:25.480
We should never attempt to apply a gameplay effect that uses this calculation to anything that does

34:25.480 --> 34:27.340
not implement a combat interface.

34:27.340 --> 34:33.640
I'm going to consider that a mistake and for that reason I'm not going to check the pointer.

34:33.640 --> 34:37.660
I'd rather it just crash instead or running in debug mode.

34:37.660 --> 34:40.450
Just halt right here instead.

34:40.450 --> 34:44.110
So I'm not going to check the pointer and we're getting the player level from it.

34:44.110 --> 34:47.080
And now we choose a calculation here.

34:47.080 --> 34:56.710
Now for Max Mana, I'd like a base value of 50 no matter what, and I'd like to also add every time

34:56.710 --> 35:04.690
our intelligence goes up, I'd like to add some like at least like 2.5 F times our intelligence.

35:04.690 --> 35:07.810
But as the level goes up, let's add even more.

35:07.810 --> 35:15.400
Let's add, say ten, maybe even 15 point F times player level, something like that.

35:15.400 --> 35:17.680
So pretty simple calculation.

35:17.680 --> 35:21.910
You know, there's potential here to be much more complicated if we needed to.

35:21.910 --> 35:26.170
But for my Max Mana, here's the calculation that I'd like.

35:26.170 --> 35:28.570
And with that we now have an MSI.

35:28.810 --> 35:30.370
We can go ahead and run.

35:30.370 --> 35:31.930
I'm going to run in debug mode.

35:33.230 --> 35:41.870
And with that we can open up our secondary attributes effect, scroll on down and our last one, index

35:41.870 --> 35:43.580
nine is Max Mana.

35:43.610 --> 35:44.810
It's attribute based.

35:44.810 --> 35:50.420
We're going to switch that to custom calculation class and expand that and choose.

35:50.450 --> 35:52.940
Now we have Max Mana.

35:52.940 --> 35:55.400
We're going to choose that and that's it.

35:55.430 --> 35:59.750
We can go and press play and I don't know if we can see Max Mana anymore.

35:59.750 --> 36:06.890
We have so many attributes and so many infinite effects applied to them that we can't really see our

36:06.890 --> 36:07.850
max mana.

36:07.850 --> 36:10.100
At least I don't see it on my screen.

36:10.100 --> 36:17.990
So what I could do is simply place a breakpoint there and run the game and then we can see that we at

36:17.990 --> 36:19.460
least have the correct values.

36:19.460 --> 36:21.080
INT is 17.

36:21.110 --> 36:22.130
That's correct.

36:22.130 --> 36:23.660
Our level is one.

36:23.660 --> 36:27.890
So yeah, this function will return this value.

36:28.010 --> 36:33.270
And once we add some more UI elements, I'm going to go ahead and resume.

36:33.270 --> 36:40.980
Then we'll be able to display some more of our gas variables to the screen a lot more easily.

36:40.980 --> 36:43.770
And so that'll be some of the next things we do.

36:43.770 --> 36:51.570
But notice that we're starting off our health and mana pretty low and I don't want to have to hard code

36:51.570 --> 36:52.940
those values, right?

36:52.940 --> 36:54.150
So I'm going to save all.

36:54.600 --> 37:00.510
If we go up to our attributes, set up to the constructor, we see that we're setting these both to

37:00.510 --> 37:02.610
low values ten each.

37:02.760 --> 37:04.230
I don't want to do that.

37:04.260 --> 37:08.340
I want to set them equal to the value of max health.

37:08.340 --> 37:12.060
But the value of max health depends on the value of other attributes.

37:12.060 --> 37:20.370
So how are we going to get the health and mana initialized to the correct value, the exact value they

37:20.370 --> 37:23.160
need to be to fill up those globes?

37:23.160 --> 37:25.890
We'll figure out how to do that next.

37:25.920 --> 37:27.060
I'll see you soon.
