WEBVTT

00:06.960 --> 00:07.650
Hey there.

00:07.650 --> 00:08.520
Welcome back.

00:08.520 --> 00:15.360
So in the last video we made the execution calculation class and we added an empty constructor.

00:15.360 --> 00:21.630
It won't be empty for long as well as overrode the execute implementation function.

00:21.630 --> 00:24.480
This is the heart of the execution calculation.

00:24.480 --> 00:28.200
This is where the calculation is going to be done.

00:28.200 --> 00:34.920
And we already saw that we have access to quite a bit of information already, but we do need to capture

00:34.920 --> 00:36.030
some attributes.

00:36.030 --> 00:43.140
So in this video, we're going to handle capturing the attributes now to make capturing the attributes

00:43.170 --> 00:45.390
a great deal easier for us.

00:45.390 --> 00:53.520
I'm going to use a technique that I've seen done in several projects, such as in the Action-rpg demo

00:53.520 --> 01:00.810
project released by Epic Games, and that technique involved creating a struct to store our attribute

01:00.810 --> 01:03.650
capture definitions and to define them.

01:03.660 --> 01:09.610
Now that phrase attribute capture definition that should sound familiar to you.

01:09.610 --> 01:16.060
As we've captured attributes before using something called an attribute capture definition, haven't

01:16.060 --> 01:16.540
we?

01:16.570 --> 01:24.250
Now, if that doesn't really ring a bell, I'm going to jog your memory by opening a couple of mics.

01:24.280 --> 01:24.790
Really?

01:24.790 --> 01:26.020
We can just open one of them.

01:26.020 --> 01:28.270
I'm going to open mic Maxhealth.

01:28.720 --> 01:30.280
Now check out this mic.

01:30.490 --> 01:31.570
I'm going to move it over here.

01:31.570 --> 01:32.260
To the right.

01:32.290 --> 01:38.470
We have a gameplay effect attribute capture definition called Vigor def.

01:38.500 --> 01:43.210
These attribute capture definitions are how we capture attributes.

01:43.210 --> 01:49.090
I'm going to alt oh right into the CPP file and let's take a look at how we capture the attributes.

01:49.090 --> 01:56.440
Well, notice that for one, we use the constructor to set some parameters on that capture definition

01:56.440 --> 02:00.460
and we add it to this relevant attributes to capture.

02:00.490 --> 02:06.550
This is a array of attribute capture definitions on the class itself.

02:06.550 --> 02:09.520
So that's how we captured attributes.

02:09.520 --> 02:18.400
Here in the MSI, we used a capture definition and in the actual function calculate base magnitude,

02:18.490 --> 02:25.600
we created some evaluation parameters and called this function get captured attribute magnitude, which

02:25.600 --> 02:27.730
required some evaluation parameters.

02:27.730 --> 02:31.720
We pass those in and we got the value of the captured attribute.

02:32.280 --> 02:41.270
So that's how capturing attributes happens in an MSI for a exec calc or an execution calculation.

02:41.280 --> 02:47.730
We're also going to use this type the gameplay effect attribute capture definition, but we're going

02:47.730 --> 02:49.440
to do things a little bit differently.

02:49.560 --> 02:56.040
So as I said in the exec calc, we're going to create a struct to hold all of our capture definitions

02:56.040 --> 02:57.690
and here's how it's going to work.

02:57.810 --> 03:02.490
We're going to create a struct, so I'm going to declare a new struct and I'm going to call this aura

03:02.520 --> 03:04.280
damage statics.

03:04.290 --> 03:09.390
Now statics is in the name for a reason and we'll see why in just a second.

03:09.420 --> 03:12.660
And notice, I'm not prefixing it with an F now.

03:12.660 --> 03:14.670
That's because this is just a raw struct.

03:14.670 --> 03:18.570
We're not going to expose it to blueprint or the reflection system at all.

03:18.570 --> 03:20.070
It's not going to be a use struct.

03:20.100 --> 03:22.440
It doesn't need a generated body macro.

03:22.470 --> 03:27.390
This is just a raw internal struct used right here in the CPP file.

03:27.390 --> 03:35.200
And to emphasize that fact, I'm not going to add that F that's required for a use struct for example.

03:35.230 --> 03:42.400
Now here in aura damage statics, I can create an aura damage statics constructor and just give it a

03:42.400 --> 03:43.450
body here.

03:43.450 --> 03:46.900
So what are we going to do with aura damage statics?

03:46.900 --> 03:48.940
How exactly are we going to use it?

03:48.970 --> 03:55.810
Well, I'm going to make a static variable of this type that has static storage duration.

03:55.810 --> 04:05.680
This means that this damage statics struct will be instantiated once and each time I access it or each

04:05.680 --> 04:07.030
time it's used.

04:07.030 --> 04:09.400
I'd like to access the same one every time.

04:09.400 --> 04:11.760
That's what static is good for.

04:11.770 --> 04:18.280
So I'm going to make a static function to return the one and only static variable.

04:18.280 --> 04:22.090
Now here's how static variables inside of functions work.

04:22.090 --> 04:29.410
I'm going to make a static function that returns a const or a damage statics reference called damage

04:29.410 --> 04:30.490
statics.

04:30.820 --> 04:36.730
Okay, so this static function returns an aura damage statics struct object.

04:37.000 --> 04:43.900
Here in the function I'm going to declare a static or a damage statics called statics.

04:43.930 --> 04:49.450
Okay, so this is creating a De statics object.

04:49.450 --> 04:57.490
It's kind of like when you create an object without using dynamic memory allocation with pointers and

04:57.490 --> 04:58.690
all that good stuff.

04:58.690 --> 05:01.480
We're just creating a variable the old school way.

05:01.480 --> 05:13.810
It's like saying int A or float B or my special struct s, even though my special struct is not a type

05:13.810 --> 05:15.670
that exists, but you get the drift.

05:15.670 --> 05:17.440
We're creating one only.

05:17.440 --> 05:19.330
We're creating a static one.

05:19.330 --> 05:25.630
And when you create a static variable here inside of a static function, then every time that function

05:25.630 --> 05:28.510
is called we get that same object.

05:28.510 --> 05:30.700
It has static storage duration.

05:30.700 --> 05:38.200
It doesn't go away when the function ends, even though it's not dynamically allocated on the heap as

05:38.200 --> 05:43.390
a pointer using the new keyword, it doesn't matter because it's static, it's going to live on.

05:43.390 --> 05:50.560
So every time we call this function over and over again, we're going to return this De statics and

05:50.560 --> 05:53.800
every time we call it, we'll get the same De statics object.

05:53.830 --> 05:55.720
There'll just be one of them.

05:55.720 --> 06:02.440
So anything we put here in aura damage statics, if we call damage statics to access it, then we'll

06:02.440 --> 06:04.180
get the same one every time.

06:04.300 --> 06:06.970
So what are we going to do with damage statics?

06:06.970 --> 06:12.820
Well, we want to declare some new capture definitions and there's a macro for that.

06:12.820 --> 06:16.510
It's declare attribute capture def.

06:16.510 --> 06:18.070
And what do we put in here?

06:18.070 --> 06:21.100
Well, we just put in something like armor.

06:21.640 --> 06:24.460
Now, this is a macro, right?

06:24.460 --> 06:27.820
It doesn't matter that we don't have an armor variable.

06:27.820 --> 06:29.680
We don't have to pass in a variable.

06:29.680 --> 06:35.430
We just have to put some text in here, some tokens and I'm just putting armor.

06:35.440 --> 06:37.510
Now, what is this going to do?

06:37.840 --> 06:43.450
Well, I can right click and I can go to declaration or usages and I can see the macro.

06:43.480 --> 06:44.320
What is it doing?

06:44.320 --> 06:49.000
It's making an F property pointer called P property.

06:49.030 --> 06:50.680
This is macro magic here.

06:50.680 --> 06:57.670
It's taking whatever I put in here, in this case armor and creating a new variable of type F property

06:57.670 --> 07:00.310
pointer called armor property.

07:00.310 --> 07:01.950
It's taking whatever I pass in.

07:01.960 --> 07:06.520
That's why I don't have to pass in a variable per se, because it's not treating it like a variable.

07:06.520 --> 07:12.310
It's treating it like a series of tokens and then creating a new armor property pointer.

07:12.460 --> 07:13.450
And then look at this.

07:13.480 --> 07:18.310
It's creating an F gameplay effect attribute capture definition called armor def.

07:18.310 --> 07:19.060
Look at that.

07:19.060 --> 07:22.900
So we don't have to declare an armor def, right?

07:22.930 --> 07:29.770
We're just using this macro to create an f property and a gameplay attribute capture definition variable

07:29.770 --> 07:30.610
for us.

07:31.410 --> 07:37.290
Notice there's also a define attribute capture def Notice that this does other things.

07:37.290 --> 07:43.800
It takes in four different things and yes, they are single characters, so that makes it a little bit

07:43.800 --> 07:47.190
hard to learn by just looking at the definition, doesn't it?

07:47.190 --> 07:48.630
But look at what it does.

07:48.660 --> 07:49.530
It takes in.

07:49.560 --> 07:55.800
P So in this case, if we passed in armor, then it would replace this part here with armor and it would

07:55.800 --> 07:59.220
be saying armor property equals right?

07:59.220 --> 08:04.530
And it's calling this template function find field checked specifying f property.

08:04.530 --> 08:08.940
And then here it's getting the static class for us.

08:08.940 --> 08:13.950
So that tells us that's is probably a class name that we pass in.

08:13.950 --> 08:14.640
Right.

08:14.760 --> 08:22.650
And then it's calling get member name checked with that class name and that P that in this hypothetical

08:22.650 --> 08:24.290
situation is armor.

08:24.300 --> 08:31.650
Now it's doing get member name checked which does something right Well it gets a member name and and

08:31.650 --> 08:38.640
checked indicates an assertion of some kind right so after getting that property it also takes armor

08:38.650 --> 08:46.290
def the capture definition and here look we have F gameplay effect attribute capture definition.

08:46.290 --> 08:48.120
This looks like a constructor, right?

08:48.120 --> 08:53.880
So it's constructing a new one of these and it's passing in armor property, right?

08:53.880 --> 08:57.660
It's using this P hash hash, macro magic.

08:57.660 --> 08:59.550
It's just replacing this here.

08:59.550 --> 09:05.040
It's actually concatenating it into one single identifier is what it's doing.

09:05.040 --> 09:11.940
And then look, we have an E gameplay effect attribute capture source T, So it's calling this constructor

09:11.940 --> 09:13.530
creating a new one of these.

09:13.560 --> 09:16.620
Initializing it with this enum.

09:16.620 --> 09:22.500
So presumably T has to be an enum constant on this enum type.

09:22.500 --> 09:22.980
Right?

09:22.980 --> 09:29.880
And then look, we have B, so there's this mysterious B that goes into gameplay effect attribute capture

09:29.880 --> 09:30.450
definition.

09:30.450 --> 09:35.770
I'll just spoil it for you here B stands for boolean and it's whether or not we want a snapshot.

09:35.770 --> 09:38.110
So that's it really should be called snapshot.

09:38.140 --> 09:39.490
These should be whole words.

09:39.490 --> 09:41.140
They shouldn't just be letters.

09:41.140 --> 09:44.980
But hey, whoever made this macro decided it was fine.

09:44.980 --> 09:53.050
So anyway, these macros exist and we can use them to help us out to make our attribute capture definitions

09:53.050 --> 09:54.550
and to define them.

09:54.550 --> 09:56.140
We're going to be using those.

09:56.140 --> 10:02.230
So right here we use declare attribute capture Def so we know that we're going to have an armor def.

10:02.260 --> 10:09.520
Remember, this macro creates something called armor def right here, replaces that P double hash with

10:09.520 --> 10:10.870
what we passed in there.

10:10.870 --> 10:15.400
So it's going to create an F gameplay effect attribute capture definition called armor def.

10:15.400 --> 10:21.070
It's going to do that for us and I'd like to use that other macro that define here.

10:21.070 --> 10:23.860
Let's go back, define attribute capture def.

10:23.860 --> 10:29.350
I'd like to use that for my armor and I'm going to do that in Aura Damage Statics constructor.

10:29.350 --> 10:30.700
So it's only done once.

10:30.700 --> 10:32.050
We only need it done.

10:32.080 --> 10:33.250
One time.

10:33.250 --> 10:41.590
So I'm going to use define attribute capture Def and I'm going to pass in those four things that we

10:41.590 --> 10:43.030
need Now.

10:43.030 --> 10:47.260
First is that's because it's going to call static class on it.

10:47.290 --> 10:51.430
Now S is going to be the class for our attribute set.

10:51.430 --> 10:53.950
That's you or a attribute set.

10:55.240 --> 11:02.110
Notice rider just goes and includes that there or attribute set dot h.

11:02.290 --> 11:11.140
Now the next input is going to be that P that gets replaced using that P double hash symbol.

11:11.140 --> 11:16.030
So in this case it's going to be armor, not armor def, but armor.

11:16.270 --> 11:18.790
Now next we need the enum.

11:18.790 --> 11:22.810
It's the T part of that macro and it's an E gameplay effect.

11:22.810 --> 11:25.630
Attribute capture source double colon T.

11:25.930 --> 11:32.110
We're passing in the T part of that and look at the name of the enum gameplay effect Attribute capture

11:32.110 --> 11:32.800
Source.

11:32.800 --> 11:38.350
Well, the two options are target and source and this is the armor.

11:38.350 --> 11:44.440
We're capturing the armor and if we're going to do a damage calculation, we want the armor of the target,

11:44.470 --> 11:45.670
not the source.

11:45.670 --> 11:51.040
The target is what's getting damaged and we need to see the armor value.

11:51.070 --> 11:53.410
We don't care about the armor of the attacker.

11:53.410 --> 12:00.350
We care about the armor of the victim so that we can use that value to lower the damage a bit.

12:00.350 --> 12:01.970
So we're going to use Target.

12:01.970 --> 12:05.390
And finally, the fourth and final input is that be there.

12:05.390 --> 12:06.410
That's a Boolean.

12:06.410 --> 12:09.050
And this is for whether or not we want to snapshot.

12:09.080 --> 12:11.450
We're going to not snapshot.

12:11.450 --> 12:13.280
So we're going to pass in false.

12:13.700 --> 12:15.110
And there we have it.

12:15.140 --> 12:22.070
We've created and define an attribute capture def called armor and it's stored in damage statics and

12:22.070 --> 12:28.910
we can access it through the damage statics function, the static function that will return that static

12:28.910 --> 12:29.690
variable.

12:29.690 --> 12:32.150
So that creates that capture def.

12:32.150 --> 12:34.520
That's one part of the puzzle there.

12:34.520 --> 12:45.140
But we also have to add this to a list, specifically an array on the calc damage class to tell this

12:45.140 --> 12:53.390
execution calculation class that this capture def should be used to capture that specific attribute.

12:53.510 --> 12:59.900
And we're going to do this in the exec calc constructor, and that array is called Relevant attributes

12:59.900 --> 13:00.800
to capture.

13:00.800 --> 13:08.150
We're going to call add on this array passing in that capture definition that we created with these

13:08.150 --> 13:08.990
macros.

13:09.020 --> 13:15.110
Now remember, declare attribute capture def is going to create an gameplay effect attribute capture

13:15.110 --> 13:17.660
definition called armor def.

13:17.690 --> 13:19.310
That's what it's called.

13:19.310 --> 13:27.080
So if we add here to this array, we can add that armor def, we can access it with the static function

13:27.080 --> 13:32.150
damage statics and from damage statics we can use Dot and look at that.

13:32.150 --> 13:35.630
There's the armor def it's created thanks to that macro.

13:36.080 --> 13:43.280
And now we've successfully added that capture definition to the exit Calcs relevant attributes to capture

13:43.280 --> 13:43.790
array.

13:43.820 --> 13:51.200
This is a similar process to what we did in our MSI, but in the MSI we did it right here after just

13:51.200 --> 13:54.830
setting some properties on our vigor def here.

13:54.830 --> 14:03.740
So this was doing it kind of manually creating the vigor def ourselves, setting properties on it ourselves.

14:03.740 --> 14:10.190
Whereas over here in the exit calc, we're using this macro magic to kind of initialize stuff.

14:10.190 --> 14:15.560
This is a kind of shorthand version of doing what we did in the MSI and in the MSI.

14:15.590 --> 14:19.850
We added that capture Def to relevant attributes to capture.

14:19.850 --> 14:25.370
We're doing that here as well because the exit calc also has relevant attributes to capture.

14:25.370 --> 14:28.070
So a couple of different ways to do the same thing.

14:28.340 --> 14:35.900
Now the question how do we actually capture it here in our execution calculation function execute?

14:35.930 --> 14:39.470
How are we going to actually get that armor definition?

14:39.470 --> 14:43.160
Well, the way to do it is through a function on execution.

14:43.160 --> 14:51.830
Params we're going to take execution params dot and remember this struct has lots of useful functions,

14:51.830 --> 14:52.340
doesn't it?

14:52.340 --> 14:55.490
And some of them say capture in them.

14:55.580 --> 15:01.340
The one I'm interested in is attempt calculate captured attribute magnitude.

15:01.370 --> 15:04.100
Let's call that and see what it requires.

15:04.100 --> 15:08.240
No surprise here it requires an attribute capture definition.

15:08.240 --> 15:12.050
The gameplay effect attribute capture definition.

15:12.050 --> 15:13.400
Well, we know how to get that.

15:13.400 --> 15:18.770
We can use the static damage statics function.

15:18.770 --> 15:24.500
I'm not really going to call it a getter, but it's essentially a getter for our static instance of

15:24.500 --> 15:26.930
this struct which contains the armor def.

15:27.170 --> 15:29.780
So that can satisfy that first input.

15:29.870 --> 15:35.270
Now, next, it requires an aggregator evaluate parameters.

15:35.300 --> 15:40.820
Remember in our MSI, when we had to create one of these, it was called evaluation parameters.

15:40.850 --> 15:42.350
No, I don't either.

15:42.350 --> 15:43.670
Let's go back and look.

15:43.670 --> 15:50.450
And right here in calculate base magnitude, we made one of these an aggregator evaluate parameters,

15:50.450 --> 15:54.830
we called it evaluation parameters, and we also had to set.

15:54.880 --> 16:00.610
Source and target tags on it, which we could get through this effect spec.

16:00.700 --> 16:06.520
We're going to go through that same process here and you should probably know how we're going to do

16:06.520 --> 16:06.790
that.

16:06.790 --> 16:11.710
Look, we have an effect spec right here, so why don't we go through that process?

16:11.710 --> 16:16.000
And if you feel up to a tiny mini challenge, why don't you do it yourself?

16:16.000 --> 16:22.300
Make the evaluation parameters, set the source and target tags and pass it into the function.

16:22.330 --> 16:25.480
Go ahead and pause and do it real quick if you're so inclined.

16:28.330 --> 16:31.570
Okay, so first we need the source and target tags.

16:31.570 --> 16:32.940
I'm going to make a const.

16:33.280 --> 16:44.140
Gameplay tag container reference called source tags and use this gameplay effect spec spec dot captured

16:44.140 --> 16:48.160
source tags dot get aggregated tags.

16:48.160 --> 16:50.710
That's the function that I need.

16:50.740 --> 16:58.300
And yes, of course this function returns a pointer to a gameplay tag container, not a reference.

16:58.300 --> 17:00.550
So that's going to actually be a const pointer.

17:00.550 --> 17:03.760
Let's do the same for the target tag.

17:03.760 --> 17:10.660
So I'm going to call this one target tags and instead of captured source tags, we're going to get captured,

17:11.440 --> 17:14.830
target tags, dot get aggregated tags.

17:14.910 --> 17:24.250
Now that we have these, we can make an aggregator evaluate parameters called evaluation parameters,

17:25.780 --> 17:28.250
and we'll set the source and target tags.

17:28.250 --> 17:33.980
So we have evaluation parameters, dot source tags.

17:34.310 --> 17:41.870
We'll set that equal to source tags and evaluation parameters, dot target tags.

17:41.900 --> 17:44.150
We'll set that equal to target tags.

17:44.240 --> 17:51.110
So now that we have evaluation parameters and it has those tags, let's pass that in as the next input

17:51.110 --> 17:52.190
to this function.

17:52.280 --> 17:57.800
Now, next, it requires a float passed in by reference called out magnitude.

17:57.800 --> 17:59.330
It's an out parameter.

17:59.330 --> 18:04.490
So just like we did in the MSI, we're going to create a local variable, not a const one.

18:04.490 --> 18:05.690
We're going to pass it in.

18:05.690 --> 18:13.850
And then after calling this function, it will now have presumably the value of the captured attribute

18:13.850 --> 18:15.710
in this case armor, right?

18:15.710 --> 18:18.380
So we're going to create a float called armor.

18:18.740 --> 18:22.580
We're going to set it equal to zero and we're going to pass in armor.

18:23.210 --> 18:24.710
So armor here.

18:25.490 --> 18:28.850
And after this function, we should have armor.

18:28.880 --> 18:30.020
Pretty cool.

18:30.200 --> 18:37.520
Now, just like we mentioned in the slide a couple videos ago, if we're clamping armor, for example,

18:37.520 --> 18:42.860
in pre attribute change, I know we're not, but if we were, we'd clamp it again here.

18:42.890 --> 18:48.290
Also, if we wanted to make sure that it's never zero, we can also do that too.

18:48.320 --> 18:50.170
We've seen how to do that.

18:50.180 --> 18:53.450
We would do something like armor equals F math.

18:54.740 --> 18:57.260
Max specifying.

18:57.290 --> 19:03.470
The max function for float and we would get the max between zero point F and armor.

19:03.590 --> 19:08.300
So this would make sure that armor is never a negative value, for example.

19:08.860 --> 19:09.740
And that's it.

19:09.760 --> 19:11.230
Now we have armor.

19:11.350 --> 19:21.220
So one of the last things to know how to do is how do we determine what exactly happens as a result

19:21.220 --> 19:23.630
of this execution calculation?

19:23.650 --> 19:31.150
How do we modify the actual value of an attribute with this execution calculation?

19:31.360 --> 19:36.730
Well, as you probably guessed this out, execution output is related to that.

19:36.760 --> 19:39.310
This is an output parameter itself.

19:39.310 --> 19:44.620
We modify attributes using this out, execution output.

19:44.620 --> 19:47.800
So we're going to take it out, execution output.

19:47.800 --> 19:51.520
And what we can do is add output modifier.

19:51.550 --> 20:00.580
Now this requires the gameplay modifier evaluated data type called an output mod.

20:00.610 --> 20:05.890
So we need to make one of those and we can make one right here in the parentheses or we can make one

20:05.890 --> 20:06.880
outside of it.

20:06.910 --> 20:13.420
It's an F gameplay modifier evaluated data.

20:13.420 --> 20:15.880
We can call this evaluated.

20:16.630 --> 20:22.600
Data and for its constructor we have to initialize it with a couple things.

20:22.810 --> 20:28.780
The first input is an gameplay attribute, so we need the attribute that we'd like to modify.

20:29.370 --> 20:31.100
Now, here's the cool thing.

20:31.110 --> 20:40.320
If we're using these macros up here, then we can take our damage statics dot and look at this.

20:40.350 --> 20:44.790
We have armor property, it's an F property pointer.

20:45.120 --> 20:52.470
We can pass that in and that is going to satisfy that gameplay attribute.

20:52.620 --> 20:53.940
Pretty cool, right?

20:53.970 --> 21:02.850
Now the next input is a enum in a enum as byte, but we can pass in an enum of type e gameplay mod op.

21:02.850 --> 21:06.330
So let's type e gameplay mod op.

21:06.540 --> 21:09.720
And this is the modifier operation.

21:09.990 --> 21:14.640
If we hit a double colon, we can see the different types of operations.

21:14.760 --> 21:22.980
So whatever we calculate up here, if we decide that we'd like to modify the armor attribute, well,

21:22.980 --> 21:24.930
we can choose a mod op.

21:24.930 --> 21:26.310
I'm going to choose additive.

21:26.310 --> 21:27.210
Why not?

21:27.210 --> 21:33.790
And then we pass in a magnitude that's a float so we can pass in some value like armor.

21:33.820 --> 21:40.750
Now all we're doing here is taking the value of armor and passing it into this evaluated data.

21:40.750 --> 21:47.650
So we're not actually changing its value unless it was negative, then we'd be making it zero.

21:47.650 --> 21:53.800
But just to prove to ourselves that it's working, we can do plus plus armor.

21:53.800 --> 21:55.660
So we're adding one to armor.

21:55.840 --> 21:59.260
That's our very complicated calculation that we're doing.

21:59.260 --> 22:08.980
And then we have an evaluated data which we can pass in to add output modifier so we can pass in evaluated

22:08.980 --> 22:11.890
data like so.

22:12.040 --> 22:16.870
And this is how we modify the armor attribute.

22:16.930 --> 22:20.130
But the cool thing is we can modify multiple attributes.

22:20.140 --> 22:27.130
We can add output modifier with another evaluated data using a different attribute that we've performed

22:27.130 --> 22:28.990
some other calculation for.

22:28.990 --> 22:34.240
So really we're not limited to just one, but we can just use one.

22:34.780 --> 22:37.780
Okay, I'm going to make that evaluated data const.

22:37.930 --> 22:39.250
There's no point in having it.

22:39.250 --> 22:46.390
Non-const And now we've made a custom calculation designed to capture the armor from the target.

22:46.390 --> 22:47.350
And look at that.

22:47.350 --> 22:49.000
We're adding to the target.

22:49.030 --> 22:49.930
You're welcome.

22:49.930 --> 22:50.590
Right.

22:50.620 --> 22:58.180
We're adding to the armor on the target so we can test this out by using this custom calculation class.

22:58.180 --> 22:59.650
I know it's kind of silly.

22:59.650 --> 23:06.370
All we're doing is adding armor, but we do plan on using this for our calculation regarding combat

23:06.370 --> 23:07.150
damage.

23:07.150 --> 23:08.410
So we'll get to that.

23:08.410 --> 23:15.580
But now we have all of the basic backbone of this thing and we know how to actually modify attributes

23:15.580 --> 23:16.270
using it.

23:16.270 --> 23:18.640
Let's go ahead and run in debug mode.

23:21.900 --> 23:22.410
All right.

23:22.410 --> 23:29.190
So we're back here in the editor and I'm going to use this G damage gameplay effect and scrolling down

23:29.190 --> 23:33.120
in G damage, we see that we have one modifier collapsing.

23:33.120 --> 23:38.070
That dropdown or modifiers has index zero and we're familiar with this.

23:38.070 --> 23:43.290
This is modifying attribute incoming damage with an add modifier op.

23:43.290 --> 23:47.820
It's set by caller specifying the gameplay tag damage.

23:47.820 --> 23:50.340
So I'm going to collapse that.

23:50.490 --> 23:52.710
And just under modifiers, look at this.

23:52.710 --> 23:54.420
We have executions.

23:54.600 --> 24:00.630
I'm going to click plus to add an execution to this gameplay effect and expand that.

24:00.630 --> 24:04.530
And as soon as I expand the index we see calculation class.

24:04.620 --> 24:09.240
So here's where we can specify execution calculation classes.

24:09.240 --> 24:12.360
Now there's also a conditional gameplay effects.

24:12.360 --> 24:17.520
We're not going to touch that just yet, but for calculation class, we can expand the dropdown.

24:17.520 --> 24:19.890
And here's our execution calculation.

24:19.890 --> 24:21.760
Exec Calc damage.

24:21.760 --> 24:29.170
Now that I've selected that exec, calc damage should have its execute implementation function called

24:29.170 --> 24:31.840
when this gameplay effect is applied.

24:31.930 --> 24:37.840
Why don't we test that out by sticking a breakpoint here in execute implementation?

24:37.840 --> 24:43.960
I'm going to go right down to the bottom there and we'll go ahead and launch a fireball at one of our

24:43.960 --> 24:44.890
enemies here.

24:46.710 --> 24:48.420
And there we go.

24:48.420 --> 24:53.100
We hit the break point and we can hover over some of these properties.

24:53.100 --> 24:59.670
We can even show the menu down here to the right as well if we want to expand some things.

25:00.000 --> 25:03.090
But we have lots of data here.

25:03.180 --> 25:07.530
I'm hovering over armor and I see that armor is 11.25.

25:07.560 --> 25:09.900
Don't let this armor equals zero fool you.

25:09.930 --> 25:14.060
We paused way down here and we've already set our armor.

25:14.070 --> 25:21.480
Now this is still a little bit hard to prove to ourselves that we're actually modifying the armor on

25:21.480 --> 25:25.800
the enemy as we're only seeing the value here of armor.

25:25.800 --> 25:27.720
It's 11.25.

25:27.720 --> 25:35.100
But what we could do is we could continue and throw another fireball and see if that armor comes out

25:35.100 --> 25:36.270
to 12.25.

25:36.270 --> 25:37.320
Why don't we do that?

25:37.320 --> 25:38.760
I'm going to click resume.

25:39.620 --> 25:43.340
And I'm going to launch another fireball at the same enemy here.

25:43.820 --> 25:44.360
All right.

25:44.360 --> 25:48.050
So now that we've paused, let's take a look at armor.

25:48.050 --> 25:51.530
And we see that it's now 22.5.

25:51.740 --> 25:52.340
Okay.

25:52.340 --> 25:58.280
And actually, that is correct, because the modifier op is additive, not override.

25:58.310 --> 25:58.880
Right.

25:58.880 --> 26:07.970
So if the armor was 11.25 after we added one to it, that means that after executing this exec calc,

26:08.000 --> 26:13.640
then armor would have had 11.25 added to whatever it was before.

26:13.670 --> 26:17.000
So that should come out to 21.5.

26:17.300 --> 26:20.420
Let's just prove that this is working properly.

26:20.450 --> 26:27.260
Now that we're looking at this from the correct perspective, if armor is 22.5 and we're going to be

26:27.260 --> 26:35.840
adding this using the gameplay mod op additive to the current value of armor and we've added one to

26:35.840 --> 26:45.120
it here, then that means the current value of armor is 21.5, so we'll be adding 22.5 to 21.5 and that

26:45.120 --> 26:48.180
should come out to 44.

26:48.300 --> 26:56.040
So if we resume and we do another fireball, we should see 44 at least before we get to this plus plus.

26:56.040 --> 27:00.750
So if we pause right there before the plus plus, we should see 44.

27:00.750 --> 27:02.820
Let's prove that to ourselves.

27:04.200 --> 27:12.090
Yes, there's 44 and then plus plus armour will make it 45 and then we'll add that to our armour.

27:12.090 --> 27:17.250
So 45 plus 44, that's going to give us 89, right?

27:17.250 --> 27:24.840
So if we resume and we fire yet another fireball, then yes, we see 89.

27:24.840 --> 27:32.370
So that right there proves to us that our execution calculation is being carried out and is actually

27:32.370 --> 27:35.040
modifying the armor attribute.

27:35.370 --> 27:43.710
So kind of a silly modification, but adding one to the armor and then adding that result to the armor

27:43.710 --> 27:49.860
attribute on the target, even though it's not that impressive of an outcome.

27:49.860 --> 27:56.250
The implications of this are massive because we can perform an arbitrarily complex calculation here,

27:56.250 --> 28:01.350
capturing any attributes that we wish and affecting any attributes that we wish.

28:01.350 --> 28:09.160
And that's going to allow us to make a damage calculation that will take all of our primary and secondary

28:09.160 --> 28:12.640
attributes concerned with combat into account.

28:12.640 --> 28:18.100
And we can make some real RPG style damage calculations.

28:18.100 --> 28:20.230
So this is actually really exciting.

28:20.590 --> 28:25.570
So we'll continue with our damage execution calculation in the next video.

28:25.600 --> 28:26.770
I'll see you soon.
