Welcome to the next quest.
In this quest, you're going to implement critical hits.
Now, this means you're going to need to capture some attributes and determine whether the hit is critical.
Now, you can use the critical hit chance for this and use critical hit resistance to reduce that effective
chance.
And if you get a critical hit, double the damage and add a critical hit bonus for critical hit damage.
Now, if you want a bonus challenge, you can add a critical hit resistance coefficient and we have
a curve table for our damage calculation coefficients.
So if you feel so inclined, make that a parameter and then you can scale your critical hit resistance
by a coefficient that changes based on level and you're going to have to decide whether these attributes
are captured on the source or the target.
So there are a few steps to this quest, but I think you're capable of handling it.
So go ahead and pause the video and conquer this quest now.
All right.
I'm back in my exec calc damage class and I'm going to scroll up to the top because we're now going
to need to capture a couple more attributes.
Now for critical hit calculations, we obviously need our three critical hit attributes.
We're going to need critical hit chance.
Now, this is going to be captured from the source, obviously.
So let's declare attribute capture Def and we'll pass in critical hit chance.
And we're also going to add a define attribute capture def.
So define attribute capture def and for s we're passing in you or an attribute set for P, that's the
attribute that's going to be critical hit chance not def.
We're going to capture critical hit chance from the source and we're not going to snapshot any of these.
Now in addition to critical hit chance, we need critical hit resistance and critical hit damage.
Let's go ahead and just add those macro calls for both of them.
We have critical hit resistance and critical hit damage.
And we'll make two more macro calls here in the constructor for a damage statics specifying critical
hit resistance.
Now critical hit resistance is going to be on the target, isn't it?
And critical hit damage that should be from the source.
And it looks like I have a typo.
This should be critical hit damage not critical hit chance damage.
So we'll go ahead and fix that.
So it's very important to make sure that we have the right parameters in our capture def we want to
capture from the target or the source, depending on what it is we're calculating.
So that's very important.
So now that we've defined these, we need to add these attributes to relevant attributes to capture.
So I'm going to add three copies of this line and change the capture def first, we're going to have
critical hit chance def.
Next we'll have critical hit resistance def and then we'll have critical hit damage def.
Now that we have those three, we know that we can capture those values.
So let's do our critical hit calculation way down here.
We want our out execution output down at the bottom and after we've just ignored a percentage of incoming
damage, we can do critical hit calculations.
Now we're going to make a float and I'm going to call this source critical hit chance and initialize
it to zero.
But then we're going to call execution params dot attempt.
Calculate captured attribute magnitude.
So first we pass in.
We're going to use damage statics dot critical hit chance def.
We need to pass in evaluation parameters
and we need to pass in source critical hit chance the float and we'll make sure that it's not negative.
So we'll say source critical hit chance equals F math max.
Specifying float.
And will max between source critical hit chance and zero.
So we now have source critical hit chance.
I'm going to need both the resistance and the damage, so I'm going to copy these three lines and paste
them.
But this is now going to be called target critical hit resistance.
And we're going to change this capture.
Def passed in to critical hit resistance def and we're going to change what we pass into this.
Our float is going to be the target critical hit resistance and then we're going to use target critical
hit resistance with our max call passing in the target critical hit resistance and zero.
And finally, we need our source critical hit damage.
So we're going to change this to source critical hit damage.
We're going to change the capture def here to critical hit.
Damage def and the float passed in will be source critical hit damage and we're going to change this
line to use source critical hit damage.
Now we have our three captured attribute values.
So how are we going to do the math here?
Well, we have a critical hit chance, right?
This should be a value that has to do with our chance to get a critical hit.
I'd like to just treat it like a percentage and see if we got a critical hit.
But I'd like it to be affected by critical hit resistance.
Critical hit resistance should reduce the critical hit chance.
So just like we had a effective armor up here, I'd like to have an effective critical hit chance as
well.
So I'd like a const float called Effective critical hit Chance.
So what I'd like is to take my source critical hit chance and subtract my critical hit resistance from
the target.
So target critical hit resistance like so.
And we can even scale this by a factor like 0.15, for example.
And that way, critical hit resistance is not as effective as if we hadn't scaled this so critical hit
resistance will scale down by this factor and then we'll subtract that from the critical hit chance.
So critical hit chance is just a little bit lower and then we can roll the dice.
We can see what a random value between 1 and 100 will be and see if it's less than this effective,
critical hit chance.
So I'm going to make a const bool called Be Critical Hit and we'll do an F math rand range.
Between 1 and 100 and see if that's less than our effective.
Critical hit chance.
So we'll know if we have a critical hit at this point and then we can scale our damage.
So we're going to take our damage and set it equal to and I'd like to use the ternary operator again.
So we'll say be critical hit question mark.
If it is a critical hit, then I'd like to scale my damage by two.
So 2.5 times damage.
So we're scaling damage by two.
But I'd also like to add my critical hit damage.
This is going to be a bonus critical hit damage value.
So we're going to say plus source critical hit damage and then colon damage.
So if critical hit is false, then we set damage equal to itself.
That's just how I'd like to do it.
And we can put a comment here that says.
Critical.
Hit resistance reduces critical hit chance by a certain percentage and we can say that double damage
plus.
A bonus if critical hit.
Okay, so we're scaling.
Target critical hit resistance by 0.15.
But we could easily make this data driven.
That was the bonus part of the challenge.
So why don't we go ahead and launch the editor and then we can go ahead and tackle this bonus part of
the challenge by adding a curve to our curve table for damage coefficients.
So I'm going to go ahead and open up my CT damage calculation coefficients and add a curve and rename
the curve to critical hit resistance.
And we can specify what this should be.
Now, as the levels go up, critical hit resistance, I think should be less and less effective.
So I'm going to start at 0.15 for level one, but we'll reduce that down to 0.1.
For level ten, we'll say 0.8 for level 20 and actually I should say 0.08 here.
And for level 40, we'll say 0.06.
So we can see what that curve looks like.
Here it is.
So just throwing some values out there.
But we could change that as we test the game.
But now that we have this, we should be able to retrieve this value in our damage execution calculation.
So I'm going to save and close and take a look by scrolling up and seeing how we got our curve values
for armor penetration and effect of armor here.
Really, it just has to do with these two lines where we get the real curve, we get our damage calculation
coefficients, we find the curve specifying the name of that curve, and then we evaluate that curve
at the player level.
Now we need to know which player, the source or the target, right?
So we'll determine that.
Let's copy these two lines.
We'll go down here to just before our calculation, we'll paste them.
And this is going to be critical hit resistance curve and we're going to find the curve for critical
hit resistance.
We're going to call this const float.
Critical hit resistance coefficient.
And we're going to evaluate the curve at the Target combat interface, get player level, because it's
the resistance, it's the thing getting hit that we're checking the resistance for.
And that's going to depend on the level of that character or target.
And then we can take critical hit resistance coefficient and replace that magic 0.15 with that value.
So the only thing left to do is to see if we can get a critical hit and boost that damage by our critical
hit damage.
And I've made one mistake, and I can tell because Ryder's telling me that this curve is not being used.
And that's because I copied and pasted.
So we're still getting the value here from effective armor curve.
I need to change that to critical hit resistance curve.
And now this should work.
So with that, we can play test and see if we can get some critical hits.
Okay, so we have our curve.
We know that this curve is already set in our data asset for character class info.
And we also know that we're initializing the attributes for our enemies using a gameplay effect.
Let's go to that gameplay effect and see what it looks like.
We're going to go to blueprints, Ability system, gameplay effects, default attributes and we have
a G attributes test, secondary attributes test, and we can make sure that we're using that by going
to the data folder.
Character, class info and secondary attributes is using this test attribute so we can pump up the values
of some of our attributes.
Now, really, the only thing we can change here is our critical hit resistance.
If we wanted to guarantee a critical hit, we'd have to modify ora's secondary attributes.
Right?
But let's just see if we can get a critical hit.
If I can get my damage doubled in some circumstances, then I'll be happy.
So I'm getting a four.
There was a 21.
There was an eight.
So that 21, I believe, was a critical hit.
And it looks like a critical hit is pretty rare.
And we're getting a block quite frequently.
And I think that's because our block chance is high.
Yes, our block chance is set to 100.
So I can set that to say 12% and we'll get a lot less blocks.
And of course, we could just set that gameplay effect back to the regular one and not the test gameplay
effect so we can see the actual values.
But every once in a while we do get a critical hit and that is manifested as 21.
Now this is all great.
We know that we're sometimes getting blocks and sometimes getting critical hits, which is great, but
it would be awesome if we could get some kind of visual feedback and know when we get a block and when
we get a critical hit.
This is kind of common in games like this where you'll see some kind of feedback here that shows whether
this was a blocked hit, a critical hit and what have you.
The way that I'd like to show that is with our damage number, I'd like to change the color of it if
it's a block or a critical hit.
And I'd also like to show some kind of message, just like a little flashing message, just like our
damage number that pops up and fades away that says block or critical hit or perhaps even blocked critical
hit.
The way that we've coded this, we can have both.
We can get a block first, cut that damage in half and then see if we got a critical hit.
And if we did, then that half damage would then be doubled and added to with a critical hit damage
bonus.
So we have several different scenarios that can occur here and I'd like visual feedback for that.
So the question is how?
How do we know whether or not we got a critical hit or a block?
Because that's determined here in the exec calc in the execution calculation.
But we're not showing that damage number until we get to post gameplay effect execute.
That's in the attribute set dot CP here.
So we need a way to know here by the time we're showing that damage number whether or not this damage
was critical or blocked or both, we need to know that information.
And so in order to get that damage information, by the time we're here in post gameplay effect execute,
we need a few more skills and we're going to work on developing those skills in the videos to come so
that we can show more feedback when some of these different phenomena occur in our RPG damage calculations.
So this is a great milestone.
We now have a damage calculation that captures our secondary attributes that are related to combat and
changes the outcome of the damage done depending on those.
So this is a really great step because it's very common when you're just starting out and making games
to implement a very rudimentary form of combat where you have a damage value and you're subtracting
it from health and that's it.
Now that we have multiple attributes at play here, damage is a lot more interesting and it's a lot
more tied to power levels of both target and source of player and enemy.
And this is a lot more along the lines of how RPGs behave.
So it's actually really interesting and this is one of my most favorite aspects of RPG games is the
mathematics behind damage calculations.
So excellent job.
And we're going to continue our journey developing this RPG in the videos to come.
I'll see you in the next video.