Welcome back.
Now that we have our own ability system globals class and it's overriding Alec gameplay effect context,
we know that every time we create a gameplay effect context at least using make effect context like
we're doing in aura projectile spell.
We know that the object created is an aura gameplay effect context.
So now we need to know how exactly we can utilize our new effect context.
How can we set the values of the booleans on the context?
Well, we're going to know when it's a blocked hit and a critical hit in our damage execution calculation.
So that would be the place to do it.
So why don't we head over to that class?
I'm going to go ahead and just close all tabs.
And go into ability system exec calc and exec calc damage dot CP and here I know whether or not I got
a critical hit and whether or not I got a blocked hit as we perform those calculations here.
Now I'm going to scroll up to our constable.
Be blocked here as soon as I know that this is a blocked hit.
I'd like to access the gameplay effect context associated with this gameplay effect that's using this
exec calc and set its blocked boolean.
So how do we do that?
Well, first we need to access the gameplay effect context, right?
And because we have access to the gameplay effect spec, it's called spec here, we can get that.
So we can type spec dot and here's the function get context.
Now get context returns an F gameplay effect context handle so we can create a local f gameplay effect
context handle called effect context handle and handle should be uppercase there.
There we go.
Now we have the effect context handle, but this is the context handle.
Right?
How do we get that effect context from it?
Well, if we type effect context handle dot, then we have a get function.
If we call get this returns a pointer to the gameplay effect context itself.
So that gives us an F gameplay effect context pointer and we can call it context if we like.
And now we have access to the context.
Now if we use the arrow operator and take a look at all the stuff built in to the gameplay effect context
class.
Well, where's our setters and getters for our new booleans?
Remember we had a set Is blocked hit.
I don't see that here.
Writer isn't showing me with autocomplete.
Why is that?
Because context is not an aura gameplay effect context.
It's an gameplay effect context.
And that's because get returns a gameplay effect context.
But what we need is an aura gameplay effect context.
So how do we get one?
Well, we have to cast and we have to specifically static cast.
So what we can do is make an F aura gameplay effect context pointer and call this aura context.
Now this type is in our header file that we created called aura ability type.
So we have to include that.
I can just hit alt enter and include that here and now.
We can set this equal to the result of a static cast.
Now this is a regular C plus plus style static cast.
So in the angle brackets, we have to have F aura gameplay effect context with the star, the cast function,
the unreal engine specific cast function doesn't require the star, but static cast does.
This will perform a compile time static cast and we're going to cast that gameplay effect context pointer.
So after doing this cast, we now have the aura context and then we can call functions on it like set
is blocked hit, so we can take Aura context call set is blocked, hit perfectly fine and we can set
it because we know be blocked.
Whatever that value is, we can set that passing that in.
We now know that set is blocked hit, we'll set that value.
So if we want to access those properties that we've added to aura gameplay effect context, this is
how we use a static cast.
Now this is kind of a lot of work just to call.
Set is blocked hit.
So for convenience it'd be nice if we had some ability system blueprint library functions that can set
these properties and that would also give us the opportunity to expose the ability to get these properties
in Blueprint.
So why don't we open our aura ability system library?
I'll get the CP and the dot h file open here.
And why don't we create a couple of functions for this?
Now, some people would prefer to only expose getters to blueprint, and if you want to set those properties
they would say you should only do that here in C plus plus perform the static cast like we did and call
the setter, etcetera.
But if you wanted to, you could expose the setter to blueprint as well.
We'll go ahead and do both.
Now I'm going to create a static function.
This will be a bool returning function and this will be for getting whether or not we have a blocked
hit.
So I'll call this is blocked hit and the function itself can take in the gameplay effect context handle.
That's pretty easily accessible from within blueprint.
So it's going to take an F gameplay effect context handle.
I'll pass it in by const reference and I'll call this effect context handle.
Now this can be a new function.
We can expose it to blueprint and if it's just going to be a simple getter, it can be a blueprint,
pure function.
So we'll make it blueprint pure.
We can give it a category and I'm going to put it in the category Aura ability system library and the
sub category can be gameplay effects.
So is blocked.
Hit is going to be relatively simple.
I'm going to go ahead and just generate the definition and have it here in the CPP file and and what
it's going to do is it's going to access the boolean on the aura gameplay effect context, which means
we're going to need to cast.
So I'm going to make an aura gameplay effect context pointer.
I'm going to let Rider include the header for that call this aura effect context and set it equal to
the result of a static cast.
And I'm going to cast to this type F aura gameplay effect context.
Go ahead and paste that in the angle brackets.
And since we're passing in the effect context handle, I can take the effect context, handle and call
get to get the effect context itself.
Now if we're calling effect context handle dot get.
This returns a const F gameplay effect context pointer.
And if we're static casting then we have to store the result in a const because we're getting a const
version of this.
If we wanted to store this in a non const, we'd have to const cast to cast away the const ness.
And we also have to make sure that we're casting to specifically a const F or a gameplay effect context
pointer.
Now, if this effect context is a valid pointer, then we can access the is blocked hit getter function.
So I'll simply place an if statement here and wrap this whole expression in an if statement and this
function can return the aura effect context is blocked hit and if the static cast fails, we can return
false.
So now we have a blueprint.
Pure is blocked hit function that can just take in a gameplay effect context handle and do that static
cast here on the C plus plus side.
So it's sort of insulating all of this stuff from the blueprint developer we can do the same thing for
is critical hit.
I can basically copy this function.
And paste it and call this one is critical hit.
And for this it's going to be almost the same.
We can go ahead and generate the definition and just take the same exact function body from is blocked
hit.
The only difference is we're going to call is critical hit.
So that right there exposes these two functions to blueprint.
Now we can see what these look like in Blueprint.
If we just run in debug mode, we can create a couple of these nodes in a blueprint.
So what I'd like to do is just create those nodes and see how they look in blueprint.
So I'm going to go to blueprints, Ability system, gameplay abilities, Fire Firebolt and open the
Firebolt.
And right here I'd like to just see what those nodes look like.
So I'm just going to right click and call is critical hit.
Here it is.
Let's get that node and here's the blueprint pure node.
I'm also going to right click and get is blocked hit and these take in effect context handle structure.
Now from here within an ability, there are some functions to get effect context there's an get effect
context function.
It requires an effect spec handle but we see that it returns a gameplay effect context handle and as
we can see, our blueprint pure function can easily accept that.
So that's what our ability system library is.
Critical hit blueprint pure function looks like.
I'm going to go ahead and close down the editor.
I can save all.
That's fine.
And let's see what some setters would look like.
Let's say we'd like to set is blocked hit.
Now for this one, I'll make a static void function called set is blocked hit.
Now for this we're not only going to take in a gameplay effect context handle, we're also going to
take in a boolean, right?
And we're not going to pass in the gameplay effect context handle as a const reference because we can't
call a setter that will change this context handle.
If it's a const reference, it has to be a non const reference.
So this has to be a gameplay effect context handle.
By Non-const reference called effect context handle and we'll have a bool called b n is blocked hit.
Now this one won't be a blueprint pure function.
It should be blueprint callable because it's really causing side effects, right?
It's going to actually change something and blueprint pure functions are not suitable for that.
We're going to use a blueprint callable and we can go ahead and generate the definition and this one
will be similar.
But there are a couple of differences.
For one, we're not going to use const, right?
We're going to take the effect context, handle and cast to a non-const So we're going to say F or a
gameplay effect context.
That's a pointer.
We're going to call it ora effect context.
We're going to set it equal to the result of a static cast to this type F or a gameplay effect context.
We're going to cast effect, context handle, dot get and we're going to check this in an if statement.
So notice no const here at all.
All of these are non const and that's because the effect context handle is non const.
If we had this passed in by const reference, we get errors all over the place so we can't pass it in
by a const reference.
Now, once we have the effect context, we can take it ora effect context and we can call set is blocked
hit, which takes a boolean and we can pass in b in is blocked hit.
So a pretty simple function and it's exposed a blueprint.
And we can look at what this looks like in the blueprint event graph, and we're going to find out that
because this is a non-const reference, we're going to find that there's a little bit of a problem with
this blueprint exposed function.
Let's go ahead and run and debug mode and create one of these nodes in blueprint.
Okay, so I'm going to open up my firebolt ability and I'm going to right click and type set is blocked.
Hit.
Here's my new function.
Now there's a problem, and I'm sure you see it right away.
The effect context handle is an output pin.
How are we going to pass in the effect context handle if it's not an input pin but an output pin and
we can't.
And that's because this is a non-const reference in Unreal engine.
If a function input is a non-const reference, that means that it's typically an out parameter.
It's meant to be passed in.
Yes, but the function fills it out and then it's a output execution pin.
Now that's by default.
If we want this to be an input execution pin, then there's an important step that we have to do to
tell the blueprint node that that's what we want.
So I'm going to close the editor and go back to set is blocked hit.
And the way that we tell the function that this is going to be an input parameter in the blueprint is
that we use you param and inside of its parentheses we put ref ref.
So this is a input parameter.
That's a non-const reference.
If we put this in the function signature, then it's going to know that this should be an input and
not an output.
So with just that little change, let's run a debug mode again.
And opening back up our gameplay ability.
We see that our set is blocked, hit Node has changed.
We now have an input execution pin for the effect context handle and notice that it's now a diamond
shape and not a circle for the input pin.
So if you've ever seen that diamond shape, now you know what that means.
We have a non-const reference set to be an input, not an output pin.
And now we have this nice handy set is blocked hit function.
We don't have to worry that our effect context handle is not the aura type.
We know that the object is, but the type in blueprint is not.
But we can pass in an effect context, handle and set.
Whether or not that context is blocking hit boolean is true.
Now that's just setting the is blocking hit boolean we can create one for is critical hit by basically
doing the same thing.
I'm going to duplicate the function but this one will be called set is critical hit the input parameter
for in is blocked hit should be renamed to in is critical hit and we have the new param.
So this is an input pin and we can generate the definition and I'm going to just copy the definition
from set is blocked hit.
The difference is we're going to call set is critical hit and pass in be in is critical hit and now
we have those blueprint callable setter functions that can set these properties from blueprint.
So now that we have these getters and setters in aura ability system library, this makes our lives
a whole lot easier when we need to set these properties.
For one here in exit calc damage, we don't have to go through all this trouble to do the static cast
and all that.
All we need to do is get our effect context, handle with spec, dot get context, and we can simply
call the aura ability system library function you aura ability system library, colon colon set is blocked
hit so we can pass in effect context handle.
And we also need a boolean for whether or not this is a blocked hit that's going to be the value of
be blocked.
So that's how we can set is blocked hit and we can do the same thing for the critical hit by scrolling
down to our critical hit calculation here, we're setting be critical hit we can use you or a ability
system library set is critical hit and we still have that effect context handle that we got up here
it's called effect context handle.
We can pass that in and we can pass in the Boolean, be critical hit like so now because we're doing
this, by the time we get all the way over to the attribute set in post gameplay effect, execute here,
we can query whether or not that was a critical hit so we can get all the way down to perhaps where
it matters here in show floating text.
This I think is where it matters because this is where we want to know if we got a critical hit or not.
I think our show floating text function should take in two booleans for whether or not we got blocked
or critical hits.
So I'm just going to go to show floating text in the H file and after passing in props and damage,
I'm going to also pass in a bool called be blocked hit and bool be critical hit.
I'm going to add those to the function definition.
So going back to the CPP file, we're going to add those in right here.
Now, what we do with those, we'll handle those soon.
I just want to pass them in for now and we can pass those in by accessing our functions from Ability
System library.
I'm just going to make a const bool called be block equals you or a ability system library is blocked
hit and we need our game play effect context, don't we.
Well we have a bunch of things in props props including our effect context handle.
Now this requires an effect.
Context handle right so props dot effect context handle can be just popped right in there.
And now we have be block.
We can pass that in right here be block and of course we need be critical hit so let's make another
one const bool be critical hit and we'll use you or ability system library is critical hit passing in
props dot effect context handle and we can pass in be critical hit right on in to show floating text
now show floating text will have those values All right so that's a great stopping point in the next
video we can handle what we do with these Boolean values.
But before we go on any further, we can just test this out by causing some damage and seeing that those
be block and be critical hit values are being set.
So let's go ahead and just run in debug mode.
And what I'd like to do is make sure our block chance is 100 so we at least get a successful block.
Now I'm back in the editor.
I'll go ahead and open up my firebolt ability and get rid of these.
I can just quickly make sure set is critical.
Hit is there and it looks good.
And there it is.
Okay, cool.
So I'm going to close firebolt and let's just cause some damage.
I'm going to go ahead and just launch a fireball.
And here in show floating text, we've made it this far.
We have damage.
We have blocked hit.
That's false.
We have be critical hit.
That's false.
Okay, cool.
But let's just change our block chance to 100% in our test secondary attributes effect so we'll go to
ability system gameplay effects, default attributes, secondary attributes test.
This is what's being used by our enemies and we'll set our block chance to 100 so we have 100% chance
to block and we'll go ahead and cause some damage.
And by the time we get to show floating text be blocked, hit is true and be critical.
Hit is false.
It's very rare to get a critical hit because, well, if you go and look at the attributes and take
a look at critical hit chance, it's three.
And that's basically almost never right.
So we could always change that.
We can make it a little bit easier to get a critical hit.
But anyway, the point is that things are working.
We're now using our custom gameplay effect context or a gameplay effect context.
We created some ability system library functions.
These static functions, they're exposed to blueprint and they just require an effect.
Context handle and booleans.
In the case of the setters.
And now our lives are easier because whenever we're wanting to set those, we call those very easy to
use functions.
And when we want to get those values, we get those wherever we have our effect.
Context handle.
And now that show floating text is receiving those values.
Whenever we get a block or a critical hit, we can decide how to show that visually to the user.
So excellent job.
We're doing some nice, cool, advanced stuff here.
It's really exciting and I'll see you in the next video.