Welcome back.
Now we have our damage damage effect.
And so far we've added a custom execution calculation called exit calc damage.
And it also still has a modifier modifying the incoming damage attribute.
It's set to add.
And if we expand the modifier magnitude, it's set by caller expanding the set by caller magnitude,
we see that it's set to damage.
That's the damage gameplay tag.
So if this gameplay effect has a set by caller magnitude assigned with the damage tag, then we're going
to modify incoming damage on whatever gets hit by this effect by that amount.
But now we're going to be using our damage execution calculation and I'd like to be able to get that
set by caller magnitude in our exec calc damage rather than through a modifier here on the gameplay
effect.
So here on modifiers, I'm going to hit the trashcan icon.
So we no longer have modifiers.
We've seen that we can have modifiers and we can have an exec calc, but I'm going to remove the modifier
and just have the exec calc and I'd like our exec calc to be set up to get that set by caller magnitude
and use that to affect the target's incoming damage meta attribute.
So let's just quickly set that up.
I'm going to go ahead and save all and close the editor.
And we're going to get that set by caller magnitude.
So here in execute implementation, let's do that.
I'm going to consider all of this stuff up here, more or less pretty much boilerplate.
And then everything down here is where our calculation will begin.
I'm going to put a comment here that says get damage set by caller magnitude and I'm going to make a
float, not a const float, but just a float, because we're going to be doing calculations to change
this.
This is going to be damage.
Now, how are we going to get that set by caller magnitude?
Well, we can always get that if we have the effect spec and we do we have spec spec has get set by
caller magnitude.
And this of course can take a game play tag.
It can take an F name, but I prefer gameplay tags over F names as they're less prone to errors as we
don't have to type in a name with a string literal and an f name object.
We can just get a gameplay tag now we can get the gameplay tags from f or a gameplay tags.
Now there was a little pause there because writer went and found our gameplay tags and included it for
me.
Now if I get the or gameplay tags and call the static get and hit dot, well there's the damage gameplay
tag.
So now I can get the set by caller magnitude for that and we see that the next couple of inputs for
this function are optional.
A boolean called warn if not found set to true by default.
We'll get a warning.
If we can't find that tag and then a float default if not found set to zero by default.
So we'll get a zero if we can't find this set by caller magnitude and then damage will just be zero.
So after calling this function damage should get that set by caller magnitude if there is one.
So now that we have damage, I don't really want to do anything with armor at the moment, so I'm just
going to remove those lines where we're doing something with armor and instead I'm going to make our
evaluated data, modify the incoming damage meta attribute on the target.
So this first input to the constructor for evaluated data can take an attribute, a gameplay attribute,
and we saw that damage statics can provide that for us for any of our captured attribute capture definitions,
but we're not capturing incoming damage on the target, are we?
But we do know that the getters for our attributes are static functions.
We can use you or attribute set get incoming damage attribute and that will satisfy that input.
Now we just have to specify the mod op whether that's additive we're going to use additive and the magnitude
that we're going to add to that, we're going to add damage because damage is that set by color, magnitude
value that we got.
So now that we've removed the modifier that was previously causing the damage, now we're going to be
setting that incoming damage meta attribute on the target because we're setting that output modifier
with our evaluated data.
Now we should just test this out and see if we're still causing damage.
So I'm going to go ahead and hit the debug button.
All right.
So I'm going to go ahead and open up g damage and just make sure that we understand what's going on
here.
We have no modifiers.
Modifiers is an empty array.
What we are doing is using exec calc damage and exec calc damage should be getting our set by caller
magnitude from this gameplay effect associated with damage.
So before the modifier was capturing that.
Now our exec calc is getting that value and then we've set our evaluated data to modify incoming damage
that's going to be on the target.
We're adding damage to that.
So we should get the same effect as before.
We should be seeing about 16 damage being caused.
Let's launch a fireball and there's that 16 So we're causing 16 damage.
And again, that's from our exec calc.
Now, no longer using the modifier with a set by caller magnitude.
Okay.
So now that we understand that, we can now start using our exec calc, because right now it's just
behaving as a glorified modifier.
It's doing exactly what our modifier was doing before getting a set by caller magnitude.
But we want to do something a little more special than that.
We want to start using our combat related attributes such as O block chance.
For example, I'd like to capture the block chance of the target and use that to see if we got a successful
block.
I'm going to add just a comment here and say capture.
Block chance on target and determine if there was a successful block.
Now, we'll also say if block half the damage, we'll have the damage.
In other words, cut the damage in half.
So now that we know what we want to do with block chance.
Now we just need to use it.
And you knew this would be your quest, didn't you?
Yeah, you did.
You're going to implement blockchains.
So here's what you need to do.
You need to capture blockchains, capture it from the target.
Now, don't snapshot, even though you know it's not going to be snapshotted anyway and check for a
successful block.
So figure out how you're going to use that block chance and if successful, cut the damage in half and
then go ahead and playtest see if you can hit an enemy and get a successful block on an enemy.
This is a chance to block, right?
So we're not going to always get a block and we're not always going to not get a block.
There's a chance that we should get a block.
So sometimes we'll get a block, sometimes we won't.
Test that out.
You can even go in and change that block chance for the enemy that you're shooting fireballs at.
If you want to try that.
So pause the video and implement block blockchains now.
Okay.
So this should be relatively straightforward.
This is one of the more simple types of calculations for our damage execution calc.
Now we need to capture block chance, which means we need to declare an attribute capture def.
So we're going to do that.
We're already capturing armor.
We're going to get block chance.
We're going to call this capture Def Block Chance and we're going to go ahead and use the define attribute
capture def so that we can have it defined here.
We're going to pass in block chance instead of armor and we're capturing the block chance on the target
and false for no snapshotting.
So now that we've defined our capture def we need to add that to the relevant attributes to capture
here in the constructor.
So we're going to go ahead and do that passing in block chance def there.
So now that we can capture block chance, let's capture that value here and we're going to do it right
after getting our damage set by caller magnitude so we can create a float called block chance.
Now we can be specific here because this is the block chance on the target.
So I think it's probably best if we make the float called Target block chance and we set it to zero,
but we're going to use the execution params to call attempt calculate.
Captured attribute magnitude.
So we need to pass in the capture def.
We can get that from damage statics.
So damage statics dot and that's the block chance def that we're interested in here.
Now we need to pass in evaluate parameters or evaluation parameters.
And we need to pass in by reference our target blockchains variable.
And after we've successfully gotten that captured blockchains, we can then make sure that it's not
a negative value.
So we'll use Max for that.
So we'll say target blockchains equals F math max specifying the float type.
And we're going to take the max of target blockchains and zero.
And we need a comma right there, of course.
So now we have target blockchain.
So how do we determine if this was a successful block?
Well, it's a chance, right?
It's kind of like the percentage out of 100.
If we were to take a random number between 1 and 100, and if that random number is less than target
block chance, let's say target block chance is 25%.
If we take a random value between 1 and 100, there's a 25% chance that it'll be between 1 and 25.
So we can make a const bool called Be Blocked and we can get a random value.
F Math has those random number functions.
We have rand range in which we can specify that we'd like a number between 1 and 100 inclusive.
So this will give us a random value between 1 and 100.
We can check to see if that's less than target block chance.
If it is, then this expression will return true and we'll have a successful block.
So this tells us if we have a successful block now, if we do, we want to cut the damage in half.
We could use a simple if statement if be blocked.
Then damage times equals 0.5 F.
That's one way to do it.
Or damage divided equals to point F, right.
Divided by two.
Or if you want it to be really explicit, you could say if B blocked damage equals damage divided by
two point F.
How you express this is really a matter of personal preference and style.
I kind of like the compactness of the ternary operator.
I like saying things like damage equals B blocked question mark.
And if it is true, then damage divided by two point F colon damage.
So set it equal to itself if blocked is false.
I personally like this expression.
It's nice and sort of compact.
So now we have successfully implemented a block chance, we get the block chance of the target.
And if it's lucky if our random value is less than its target block chance, it gets the block and it
takes half the damage.
So sometimes we should see a block in which we're getting half what we expected.
So the last thing to do is test it out.
Okay.
So we can test this out.
We can just start throwing fireballs and seeing if some of them are half the value.
That's maybe what I'd like to do at first and see if we can just get a couple of blocks.
There's 16, which is what we've been getting.
Let's see if we can get any blocks.
There was an eight.
Yes, we got a block and I don't really know what the block chance is, but I can find out by debugging.
I can see what the target block chance is.
By the time we get down to say here, let's see what it is, let's go ahead and.
Cause damage hit the break point.
Here's the target block chance.
And it is for target block chances for which means that be blocked is going to be false most of the
time because a random value between 1 and 100 will be for not that often 4% of the time.
Right.
So it's kind of amazing that we even saw an eight instead of a 16 because there isn't that high of a
block chance.
But anyway, in that case, we get a block, we cut the damage in half.
Now that's pretty cool.
We can also force a block for testing purposes by setting the block chance to 100% or 100.
And we can do that because we know the class that these enemies are.
This one's the goblin spear and we have data related to their initial starting attributes, of course.
Block Chance is derived, right?
It's a derived attribute, but we could go to ability system data and go to character class info and
take a look at our warrior.
That's what the spear is and take a look at its primary attributes warrior.
In fact, what we could do instead of messing with primary attributes and doing math, is we could set
the secondary attribute directly here.
G Secondary attributes enemy.
We can go to that gameplay effect and we can just override block charts, right?
We're overriding it with an attribute based modifier backed by look at this, we're backing it by armor
with a coefficient of 0.25 and a post multiply additive value of four.
We could switch this if I switch it from attribute based to scalable float and just set it to a value
of 100, then we'll have 100% block chance.
So now we should always see eights.
There's an eight, There's an eight, there's an eight.
Everybody gets an eight because it's always a block.
Now I'm going to go back and just change that back.
If I set this back to Attribute Based, it remembers those values.
Thankfully, I don't have to go back and look those up in my notes and put that back.
That's totally fine.
Now for testing, sometimes what I like to do is create a test gameplay effect.
So I'll come in here for my secondary attributes.
I'll duplicate it and call this one G Secondary attributes underscore test, and then I can modify the
test attribute and not have to worry about what my real values are supposed to be.
I can come into the test attribute and use this one instead.
So here for block chance I can set this one to scalable float with 100.
Look at that.
It remembered the 100 that's really handy.
And then I can go back and change my data asset to use instead of secondary attributes.
Enemy I can use secondary attributes test and now I can always test 100% block chance and whatever else
I'd like to change.
So that's nice and handy there.
We can use that if we want to continue testing for our damage execution calculations that take these
attributes into account.
For now, I'm just going to set this back to what it was before.
Secondary attributes enemy.
But now we have this test secondary attributes, gameplay effect to test things out.
All right, So excellent job.
This is a really great milestone because damage execution calculations are pivotal to RPGs.
They're one of my favorite things to implement in a project because now we get to do all the fun math
behind RPG combat that really makes an RPG what it is.
So in the videos to come, we're going to implement more damage calculations in our execution calculation.
It's really the heart of our combat here, and it's going to get a lot more interesting.
Great job.
And I'll see you in the next video.