Class ShieldInterceptAction
Sweeps a shield volume for ability objects in flight and destroys what it catches — the outward-looking half of a block.
[Serializable]
public class ShieldInterceptAction : BaseAction, IAction
- Inheritance
-
ShieldInterceptAction
- Implements
- Inherited Members
Remarks
Why this exists alongside the gate. DamageMitigation.TryBlockAtVolume already
guarantees the OUTCOME: a projectile whose impact lands inside a raised shield is stopped and
deals nothing, decided by the incoming object's own swept query, which is tunnel-proof and
runs inside the caster's rewind. What it cannot do is stop something that was never going to
hit you. A tower shield held out to the side should sweep an arrow out of the air whether or
not that arrow was aimed at your body, and a fireball should die on the shield face rather
than reaching your chest and expiring there. That is what this adds.
It cannot change whether damage lands, and that is deliberate. Both halves read the same authored ShieldVolume, so anything this catches would have been gated anyway if it had gone on to strike. Its ordering is therefore free to be imperfect — see below — because the worst it can do is stop a projectile a tick later than it might have, or stop one that was going to miss.
Tick order, stated rather than relied upon. Every AbilityObject subscribes to
TimeManager.OnTick when it spawns, so an object already in flight ticks BEFORE a shield
object spawned this tick — it moves and resolves its own sweep first. A fast projectile can
therefore reach the body on the same tick this would have caught it. The gate is what makes
that harmless; this is an accelerator, not the mechanism.
Wire it to the channel's OnTick. A channelled block re-spawns its object every tick, so an OnSpawn event fires this once per tick for the life of the channel — which is the same cadence and the simpler authoring. Put it on OnTick instead for a shield that is one long-lived object rather than a stream of short ones.
Fields
InterceptLayers
Layers the sweep looks on. Should be the layer ability objects live on.
[Tooltip("Layers to sweep for incoming ability objects.")]
public LayerMask InterceptLayers
Field Value
- LayerMask
MaxIntercepts
Maximum objects to stop in one tick. Zero or less means no cap.
[Tooltip("Objects the shield may stop in one tick. 0 or less means no cap.")]
[Min(0)]
public int MaxIntercepts
Field Value
Remarks
Matches CappedCount(int, int) and every other capped path in the project. A cap here is a balance knob — how many arrows one shield can eat in a tick — rather than a performance one; the query is bounded by the shield's own size.
Volume
The shield's dimensions, in the blocking character's own space.
[Tooltip("Shield dimensions in the blocker's own space. Leave Shape as None to sweep whatever volumes the character's active block buffs already define.")]
public ShieldVolume Volume
Field Value
Remarks
Authored here as well as on the buff, on purpose. This action is what a designer reaches for when the shield's REACH is a property of the ability rather than of the buff it applies — a shield bash that sweeps forward, a parry that only covers the weapon arm. Leave Shape at None and this action instead sweeps every volume the character's active block buffs have raised, so the common case authors the dimensions exactly once, on the buff.
Methods
Execute(ICharacter, EventData)
Sweeps the shield and destroys the ability objects inside it.
public override void Execute(ICharacter initiator, EventData eventData)
Parameters
initiatorICharacterThe blocking character.
eventDataEventDataThe event the block ability dispatched this from.