Ability Wrappers
Ability wrappers are used as a bridge between abilities and NPC goals in order to merge these two systems and make them work together, they are only used for NPCs.
The main entry point for them is AbilityWrapperGoal and it handles a lot of the core functionality of abilities such
as unlocking, equipping and using them automatically unlike manually as a human player would normally interact with
them. Generally speaking there's more things an NPC can't handle the same way a user has, most notably here "looking"
around with the mouse, for these case by case situations the class also exposes a series of abstract methods called
after all the defaults are taking care of.
For example the canUseWrapper method is called at the end of the canUse method after checking if the NPC can use
this ability, these checks are meant to be generic and not opinionated, so in this example some of the checks include
checking to see if the NPC is stunned, alive or if the ability's canUse succeeds.
The difference between an ability's canUse and an ability wrapper's canUseWrapper is that the ability's canUse
should handle all the cases as generically as possibly, for both human and player cases, the canUseWrapper method
however will only handle NPC possibilities.
At the end of the day there's nothing fancy about the AbilityWrapperGoal that couldn't be reimplemented by another dev
for their more specific needs. It is meant as a set of sane defaults and to cut down on the boilerplate code for when
handling an NPC's abilities.
How to use
Generic wrappers added by the mod:
AlwaysActive- an ability that's always active, passives should probably use this wrapper for exampleActiveBuff- like the above however its only active if the NPC has a target and they can see it (name might change in the future)Use- might be preferable to the above, the major is difference is that this one stops after 1 usage of the ability, whereasActiveBuffremains active until manually stoppedActiveGuard- used whenever the target gets too close as opposed to its reactive variant which triggers based on the amount of hits takenReactiveGuard- like the above but triggers based on the number of hits taken (by default 3) while the target is in rangeAntiAir- used when the target goes high up, such as after geppo or by flyingAntiProjectile- used when a projectile is coming towards the npcCloseMelee- used if the target is in melee rangeDash- used for dashes towards the targetReactiveRetreat- like above but moves away from the targetGrab- used for grabs, has slightly more specialized checks for grab moves thanCloseMeleeHaki- mostly anAlwaysActiveclone with specialized haki checks for when hardening/imbuing should be usedJump- used for jump abilities, by default it requires the target to be near ground level too however it can also be used if the target is in air by toggling that behavior offProjectile- shoots a projectile, has specialized code to use bows/guns events that regular NPCs wouldn't normally useRepeater- used for repeater abilities
For readability all of the above got truncated, from XAbilityWrapperGoal to just X. That means for example that AlwaysActive's real name would be AlwaysActiveAbilityWrapperGoal
It's important to note that these wrappers are meant to be generic, and are essentially just parameters for how an NPC should react to certain behaviors, they are NOT the ability itself.
For example a regular player might see a target to their right and want to shoot a projectile at them. This might seem like a super basic thing just move the mouse and shoot, however behind the curtains a lot of processing is done by our brains, determine if the ability is usable, determine how far the target is and if its worth using a projectile that might never reach, determine if you should even start the fight. NPCs have none of these features, they don't know what a camera, mouse or keyboard is. Goals are the bridge between them and the abilities.
So in a way goals are a bunch of if/else statements checking things like distance from target, visibility, rotating them towards the target, moving them in the right position all the things that our brains would naturally do for us.
On top of this the names are merely guides / helpers, because at their core they're just detecting and reacting to the world around them you can potentially use one of the above wrappers in any way it works for your NPCs.
Multiple goals can link to the same ability as well as there will only be 1 ability with the goal that can fire first
activating it. A popular use for this is for Soru which is often used as both Dash and ReactiveRetreat, depending
on the NPC's state either using it offensively or defensively.
NBT Goals
NBT Goals is a fancy name for a system that allows users to spawn NPC with abilities, in theory any NPC should do however the ability selection is limited to wrappers offered by the mod or addons and on top of that the normal ability limitations, for example:
- animation types, some animations are made specifically for humanoid models and only for humanoid models, using these with non-humanoids will result in the animation not being played at all
- item requirements, for example swordsman abilities require a sword held, even if its just data value and not visible
- state requirements, for example abilities that require resources to use (baku or jiki for example)
The command to spawn such an NPC goes like this:
/summon minecraft:creeper ~ ~ ~ {ForgeCaps: {"mineminenomi:nbt_goals": {goals: [{type: "JUMP", priority: 1, abilityId: "mineminenomi:concasse"}]}}}
So let's dissect it a bit.
What's a type ? Simply put, a representation of the wrapper goals from above. Here are the available types as of right now:
PASSIVE(AlwaysActive)DASH(Dash)GRAB(Grab)JUMP(Jump)PRROJECTILE(Projectile)PUNCH(CloseMelee)REPEATER(Repeater)NOOP- Special type with no ability usage
This is still very experimental, the whole type system will most likely be turned into something more modular like using the id of a goal wrapper directly instead of using an enum
What's a priority ? This is based on the vanilla goal system, which uses a priority system, essentially it goes in order from 0 to n running goals based on that. Multiple goals can have the same priority however their order of execution can be random.
What's abilityId ? That's just the id of an ability, same kinds used by the /ability give command.