Welcome back.
Now that we have all these resistance attributes, it's time to take them into account when it comes
to combat.
So here in calc damage, we can do that.
Now we're getting our damage as a set by call or magnitude, and we're setting the set by caller magnitude
based on the damage type.
So what we're doing here is now we're looping through the team map in our gameplay tags called Damage
Types to Resistances, and we're just using the key for that.
We're getting the set by caller magnitude for that key.
And if it's set, then we're adding that to our damage.
Now we can take resistance into account, which means we need to capture resistance attributes as well
so we can scroll all the way up to our damage statics and we can capture those resistance attributes
we need to capture them from the target, don't we?
So let's do that.
We're going to go ahead and just copy this boilerplate line and paste it here, and we're going to,
instead of critical damage, type in fire resistance.
Now that we plan on capturing fire resistance, we're going to copy one of these lines where we're using
the target and we're going to paste it here.
And instead of critical hit resistance, we're going to use fire resistance captured from the target
without snapshotting.
Now, in addition to fire resistance, we want the other three resistances.
So we're going to go ahead and paste three more times.
And instead of fire resistance, next will be lightning resistance, Next will be arcane resistance.
And next we'll have physical resistance.
And in addition to fire resistance down here, we need to capture three more.
These will be lightning resistance, arcane resistance and physical resistance.
Now, that's not the only thing we need to do, right?
We have to add this to relevant attributes to capture on the exec calc itself.
If so, we're going to do that for our four resistances here as well.
So pasting four times.
First we're going to have fire resistance def remember these have to be def.
Next is lightning resistance def next we have arcane resistance def.
And finally we have physical resistance.
Def.
Okay, so each time we capture an attribute in our exec calc, we have a little bit of boilerplate steps
here.
Now, one more boilerplate step isn't going to hurt.
We already have one, two, three things to do if we add one more.
That's not so bad.
In the places where there are boilerplate steps, it's okay to concentrate all the boilerplate steps
into those places.
Other places that are generalized, that are independent of the number of attributes and things.
We don't want to add boilerplate steps to any of those areas.
But in the case where we're capturing attributes, we have to decide which attributes to capture and
that's specific to damage.
So that's okay.
Now, I mentioned adding one more boilerplate step because these capture defs really need to be associated
with some gameplay tags.
They should be associated with those attribute tags.
Why?
Because we're looping through.
Let me find that for loop.
Here it is.
We're looping through damage types to resistances and we have access to the damage type tag.
We have access to the resistance tag, but we don't know how to get the specific capture def associated
with those tags.
We don't want to do these one by one for each resistance.
We want a general for loop, which means we should map these capture defs to their corresponding attribute
tags.
So I'm going to make a team map in or a damage statics and that way we can map these together.
So I'm going to have a team map right here.
It's going to be team map mapping and gameplay tag to an F gameplay attribute capture definition.
That's what these capture deaths are.
And this is going to be tags to capture deaths.
And that way we can map the gameplay tag to the capture death.
We can do that in aura damage statics right here in the constructor.
And so as we see all the boilerplate steps, then there's nothing to remember.
We just go through all the boilerplate steps together and that's now going to involve mapping the attribute
tags to the capture definitions.
And we should do that for all of these, I think.
So what I'm going to do is take tags to capture deaths, call add on it and we're going to add aura
gameplay tags, get dot attributes, and we'll just start at the top with armor.
So attribute secondary armor and we're going to map that to armor def.
Now, if we don't want to type for a gameplay tags dot get every time we can make a const or a gameplay
tags reference called, we'll just say tags.
We'll set it equal to F aura gameplay tags get.
And here we can simply say tags, dot attributes, secondary armor.
And we'll just really quickly time lapse mapping all of these captured attributes to their capture.
Def.
Okay, so we've added the tags to capture deaths and now damage statics has this map and we always know
which capture death is associated with which resistance tag.
That makes it easy because now when we're looping through to get the set by caller magnitudes, we can
also get the resistances corresponding to that resistance tag.
And we know which damage type is associated with which resistance type.
Thanks to damage types to resistances.
In fact, we can gather our thoughts by creating some local variables.
Here we can say const F gameplay tag.
Damage type.
Equals pair.
And hoops rider Autocompleted something.
I always go up to the top and make sure that we didn't get an unwanted include.
And it looks like I did in this case.
As soon as I remove that and go back up, I see that this include was added automatically.
Not exactly what I wanted.
So I have damage type.
That's going to be pair dot key.
Right.
We can also make a const f gameplay tag called resistance tag.
Or just resistance.
That's going to be pair dot value.
And then we can have a const F gameplay attribute capture definition called capture def.
And that can be equal to damage statics or damage statics.
Calling that function.
And then we can have tags to capture defs and tags to capture defs can be indexed with the resistance
tag so resistance can be passed in there.
Now we have to make sure that we're only trying to index for a tag that exists in here.
So we'll get a crash otherwise.
And if we really want to be explicit with this, we can use a check F what we can check is we can say
or damage statics.
We can call that we can get tags to capture deaths and we can say.
Contains.
We can see if it contains a specific tag.
We're going to use that resistance tag, which means I'm going to want this resistance tag defined first.
I'll move those both up there and we're going to say contains resistance and we're checking this.
So if this fails, then we're going to have a crash log message and we're going to say tags to capture
deaths doesn't contain tag and we'll do a percent s.
In and we'll just say exit calc.
Underscore damage and we're going to have to provide that string for percent s.
That's going to be resistance dot to string.
So if we ever try to index tags to capture deaths with a resistance that doesn't exist in it will crash,
but we'll get a nice handy crash log for that.
So now we have the capture def as well.
Now this is great because here in the for loop we can capture that attribute value.
So how are we going to capture that attribute value?
Well, we do it just like we did with our other attributes we've captured.
So we're going to make a float called resistance, set it equal to zero.
It's not any specific resistance.
Actually, we need to call this something else because our gameplay tag is called resistance.
We're going to call this actually damage type tag and resistance tag here.
And we'll replace resistance with resistance tag.
Everywhere we're using it.
And then this will just be our actual resistance value and we capture it by getting our execution params.
And calling attempt calculate captured attribute magnitude.
We need the capture definition and we have the capture def right here.
So we've looked that up from our map and that's the capture def associated with the resistance tag.
Right?
So we pass that in.
Next, we need our evaluation parameters followed by our resistance local variable.
And now we have our resistance.
Now here's where we can clamp or make sure it's not a negative value.
What I'd like to do is clamp and we should make sure resistance is never greater than 100.
If resistance is a 1 to 1 ratio to percentage reduction for damage.
In other words, if each point in a given resistance type reduces 1% of that type of damage, then resistance
should never be greater than 100.
So we're going to say resistance equals F math clamp and we're going to clamp between 0 and 100.
And of course, resistance has to be the first input there.
So now we have a resistance and we're in a for loop.
So this means we're doing this for each of the resistances, each of the damage types.
Now, because this is a resistance, we want to reduce damage by a certain percentage and we know that
this const float damage type value here is the damage associated with this given damage type.
This is the damage type value.
So what I'd like to do is I'd like to have this value calculated.
First up here, I'd like it to no longer be a const float and we're going to reduce it by resistance
percentage.
So the way we're going to reduce our damage type value is we're going to take damage type value times
equals.
So we're going to set it equal to itself times something.
And that's something is going to be a fraction of what it was before based on resistance.
So here's how we'll do the math.
We've done something like this already.
We're going to take 100 f minus resistance and divide this by 100.
So if resistance is ten, 100 minus ten is 90, 90 over 100 is 0.9.
So we would multiply damage type value by 0.9, set it equal to the result, effectively reducing damage
type value by 10%.
Once we've done this, we add the damage type value to overall total damage and we've now taken resistances
into account and it's as simple as that.
So all that's left now is to see if we're reducing damage by a certain amount.
Let's go ahead and run in debug mode.
Okay, so I'll go ahead and open up what we had open there.
And let's go ahead and just see how much damage we're causing at first.
We'll see if we're reducing any.
It's kind of hard to know.
So what we can do to really see what's going on is place a breakpoint and then launch a fireball.
Now, in the break point, we can see what some of these values are.
So first of all, resistance tag, that's attributes, resistance, arcane.
Now we're looping through all of these damage types and resistances, right?
So we expect the set by caller magnitude to be zero for damage type value and we do see zero.
So that means damage type value ends up being zero and damage gets zero added to it.
Now if we click resume, then we'll pause on the next damage type and resistance.
This is lightning again, that should be zero resuming.
We get physical, that should be zero and resuming.
We get fire.
Now the damage type of the fireball is fire.
So that means we should get a value.
Now we see just about ten for the set by caller magnitude.
Now we're capturing resistance and our enemies have zero resistance.
Right?
That's because we never actually set those modifiers for their resistances.
But what we can do is we can add them to our test attribute.
I'd like to do that.
I'm going to remove the breakpoint and resume and come back into the editor, at least want to see this
working.
So we're going to go to blueprints, Ability system, gameplay effects, default attributes and G secondary
attributes test.
And let's go ahead and just add a fire resistance attribute.
So I'm going to go ahead and collapse some of these and let's add a modifier.
We're going to add the attribute fire resistance.
We're going to make this override, make the modifier magnitude a scalable float.
And why don't we just set the fire resistance to 50 and now we expect half the damage?
From fire.
To not be applied.
And usually Non-blocked non-critical hits were five.
Now we see three.
And of course, we're rounding to integers here.
Critical hit used to be 20.
Now we're seeing 15.
So we're ignoring a percentage of fire damage.
We can place the breakpoint back and see what these values are.
Exactly.
Now, the resistance tag is arcane.
We're going to resume until we see fire and we do damage type is damage.
Fire resistance is resistance.
Fire damage type value 4.999.
Now, of course, this is after reducing the damage by the resistance.
The resistance here is 50.
We set that in the test attribute.
So now we've reduced the damage type value by 50%.
So damage should now be 4.999 or 5, in other words.
So we see that we're effectively reducing damage.
Excellent.
So now we have damage types and they're taken into account.
Now it's a little bit hard to tweak these enemy parameters, isn't it, because we have so many mathematical
interrelationships between our attributes and so that makes it a little bit difficult to tweak these
things.
So throughout the course, we're going to learn ways to fine tune the game and see how we can get all
of our attributes to work together to produce a positive gameplay experience.
But one step at a time.
For now, we have our resistances.
We can see auras, resistances we can't see the enemy's resistances, but we see that aura has her resistances
set all to nine.
They're all based on resilience and the enemies are reducing a percentage of fire damage as well.
Okay.
Excellent job.
We now have resistances.
I'll see you in the next video.