Bodychecking, Staggers and Knockouts#
Every successful bodycheck does one of two things to the skater it hits:
- Knockout (KO): the skater is thrown and lies flat on the ice for a few seconds.
- Stagger: a short stun. The skater may drop the puck.
The game picks one of these from a single integer hit score. This page explains how that score is built, what happens on each result, and the side systems: helmets, sticks, immunity, referees and shot blocking.
1. The hit score#
HandleHitted(bodychecker, hitted, hitDirection, point) computes:
score = (Checking_attacker − Checking_victim)
+ SizeBonus
+ VulnerableBonus
+ PuckBonus
− SlowSpeedPenalty
− WinddownPenalty
Both Checking values come from ForwardStats.GetChecking(includeInjury: true), so a Shoulder injury counts (see injuries).
| Term | Value | Condition |
|---|---|---|
SizeBonus (SIZE_BONUS_XXL) |
+60 | Attacker is size ExtraExtraBig (5), whatever the victim's size |
SizeBonus (SIZE_BONUS_BIGGER) |
+30 | Attacker's size class is above the victim's |
| SizeBonus | 0 | Same size class |
SizeBonus (SIZE_BONUS_SMALLER) |
−20 | Attacker is smaller |
VulnerableBonus (VULNERABLE_BONUS) |
+15 | victim.IsVulnerable(), or the attacker is in GrapplingState |
PuckBonus (PUCK_BONUS) |
+5 | victim.HadPuckRecently() |
| SlowSpeedPenalty | 10 / linear / 0 | Based on the attacker's speed (previousVelocity magnitude), see below |
WinddownPenalty (WINDDOWN_PENALTY) |
−15 | More than 0.4 s (WINDDOWN_TIME) have passed since the attacker's current movement state started. Not applied to SNES-squad skaters (_isSnesSquad) |
Size classes, from Data.SkaterSize: ExtraSmall 0, Small 1, Medium 2, Big 3, ExtraBig 4, ExtraExtraBig 5.
Slow speed penalty. Let v be the attacker's speed in m/s:
| Attacker speed | Penalty |
|---|---|
v ≤ 2 (SLOW_SPEED_MIN) |
10 |
| 2 < v < 6 | round(10 − 10·(v − 2)/4) |
v ≥ 6 (SLOW_SPEED_MAX) |
0 |
Vulnerable states. Forward.IsVulnerable returns true while the victim is in one of these movement states: Shooting, Slapshot, OneTimer, Pokecheck, Braking, SideDashing, Freezing or Incantation.
Knockout or stagger?#
The hit is a knockout when both of these hold:
score ≥ 29(KNOCKOUT_THRESHOLD) orIsGuaranteedKnockout(attacker, victim)is true.victim.CanBeKnockedOutBy(attacker)is true, and the attacker does not have the Dead Weight talent (Rogue.Powerups.Chaos.Anchor, "Can't be bodychecked / Can't bodycheck").
Otherwise the hit is a stagger.
IsGuaranteedKnockout is true in any of these cases:
| Source | Effect |
|---|---|
Attacker has One Strike (Rogue.Onepunch) |
"Your bodychecks always succeed" |
| Attacker is Enraged (StatusTag 3) | Every bodycheck knocks out |
Victim is in FreezingState or IncantationState |
Frozen or chanting skaters always go down |
Violent Plushie relic (Rogue.ViolentPlushie) on either team |
Every bodycheck knocks out (it also halves get-up time, see §3) |
Worked examples:
- Two Medium skaters with equal Checking, at full speed, with fresh contact: score = 0, so a stagger.
- A Big skater checking a Medium skater: score = +30 from size alone, so a knockout even with equal Checking.
- Equal sizes: the attacker needs +29 Checking over the victim, or a mix of the +15/+5 bonuses (for example, 9 more Checking against a shooting puck carrier: 9 + 15 + 5 = 29).
Things checked before scoring#
- If the victim has Spiked Armor (
Rogue.SpikedArmor) or the ImmuneToKnockout tag,HandleAntiBodycheckruns and the attacker is punished. The attacker loses the puck, scattered at random. Against Spiked Armor the attacker is knocked out; otherwise the attacker is staggered with stagger score 40 (branch mapping inferred). - A victim with ImmuneToKnockout then takes nothing from the hit, neither a KO nor a stagger.
BrawlChallengeTriggers.NotifyBodycheckLandedfires next. A bodycheck can lead to a brawl offer (see fights).
Source: Skaters.SkaterCollision::HandleHitted, IsGuaranteedKnockout, HandleAntiBodycheck, constants on SkaterCollision; Skaters.Forward::IsVulnerable.
2. Knockout throw (force)#
Let remap = 41 + 59·clamp01((score − 10)/70). This ranges from 41 to 100 and is the same value RemapKnockoutScore returns.
| remap | Horizontal impulse along the hit direction | Vertical impulse |
|---|---|---|
| < 80 | 2 + 3·clamp01(remap/80), about 3.5–5 | 0 |
| ≥ 80 | Lerp(5, 13, InverseLerp(80, 300, remap)), about 5–5.7 | Lerp(9, 28, InverseLerp(70, 300, remap)), about 9.8–11.5 |
Modifiers, in the order the code applies them:
| Condition | Effect |
|---|---|
| Victim on a soccer team and remap ≥ 80 | 70% chance (Random < 0.7) the vertical part is removed |
| Ice friction | Random.Range(0.02, 0.2) |
| Attacker Enraged | +8 × direction to the throw; friction set to 0.02 |
Attacker has Bonecrusher (Rogue.BigBodycheck) |
+12 × direction, friction 0.02, and the victim loses their stick. At talent level ≥ 2, another +8 × direction |
Victim has Figure Check (Rogue.FigureCheck) |
The KO is replaced by HandleFigureCheckForward ("spin out instead of getting knocked out") |
Forward.Knockout, unless the KO is grounded or a soccer flop |
The vertical component is raised to at least 7 |
Fall type. GetKnockoutFall picks one of three falls: Launch (the default), Crumple or Slide. It is skipped for soccer-team victims and for power-up knockouts (IsPowerupKnockout).
| Fall | Behaviour |
|---|---|
| Crumple | New velocity = 0.8 × the victim's old velocity + 1.5 × hit direction (CrumpleSpeedKept 0.8, CrumplePush 1.5); friction 0.05; no vertical component |
| Slide | No vertical component; friction 0.02 |
Which fall is chosen depends on how the victim was moving relative to the hit. The constants involved are MovingVictimMinSpeed 2, SameDirectionDotThreshold 0.5 and HeadOnDotThreshold −0.5. The exact mapping from these to each fall is inferred.
Source: SkaterCollision::HandleHitted (knockout branch), GetKnockoutFall, IsPowerupKnockout; Forward::Knockout.
3. Knockout duration and getting up#
The knockout time is built in four stages.
1. Base time, in HandleHitted:
timeKnockout = clamp(remap / 15, 1, 4) seconds.
- At the threshold (score 29) this is about 3.8 s.
- Any score of 32 or more gives 4 s.
- A guaranteed KO with a low score can go as low as 41/15 ≈ 2.73 s.
2. Adjustments in Forward.Knockout:
| Condition | Effect |
|---|---|
| Attacker is a Forward and ΔChecking = attacker − victim > 40 | + (ΔChecking × 0.05 − 2) s. For example ΔChecking 60 adds 1 s; 100 adds 3 s |
Victim is a Referee (skaterType == Referee) |
× 2 |
| The KO caused an injury | + InjuryConfig.knockoutTime = +8 s |
3. Adjustments in KnockoutState.OnEnter:
| Condition | Effect |
|---|---|
| Victim size ExtraSmall or Small | × 0.5 |
| Victim size Medium | × 1 |
| Victim size Big, ExtraBig or ExtraExtraBig | × 1.5 |
| Normal (not mid-air, not forced soccer flop) | + 0.75 s (GroundedKnockoutExtraTime); chain-KO window opens 0.3 s later |
| Victim's team is a soccer team | × 2 instead, with friction 1 |
Lifeless Branch (PlayerGetUpFaster) lvl 1, or Violent Plushie on either team |
× 0.5 ("get up 2x quicker") |
| Lifeless Branch lvl 2, or Springboard talent | Set to 0.25 s (InstantRecoveryTime) |
4. During the knockout:
- The skater cannot be knocked out or staggered again (
KnockoutState.CanBeKnockedOutandCanBeStaggeredboth return false). - A victim flying faster than 15 m/s (
ChainKnockoutMinSpeed) can chain-knockout skaters it hits: - force = 0.5 × speed, clamped to 5–13;
- friction 0.1;
- duration 2 s.
- The Bowling Relic turns KO'd skaters into pins: KnockoutDuration 2.5, force 5–13, vertical 3.
Source: SkaterCollision::HandleHitted; Forward::Knockout; KnockoutState::OnEnter, HasQuickerRecovery, KnockoutState constants; catalog entries for PlayerGetUpFaster, SpringBoard, ViolentPlushie and BowlingRelic.
4. Stagger (non-KO hit)#
Stagger score. The value passed to Forward.Staggered is clamp(score + 30, 0, 40). The same value is used as the helmet-drop "power" (§5).
Stagger push.
(0.4 + 2.5·clamp01(remap/60)) × sizeMult × hitDirection
sizeMult is 1.25 if the attacker is bigger, 0.75 if smaller and 1 if the same size (STAGGER_FORCE_*_MULTIPLIER). Because remap is always at least 41, the base push is 2.1–2.9.
Stagger length. StaggeredState.OnEnter plays the stagger animation at
timeScale = 3.5 − 1.5·clamp01((staggerScore − 5)/55)
That is 3.5× speed for weak hits, down to about 2.55× for staggerScore 40. A harder hit therefore gives a longer stagger (seconds = clip length / timeScale, inferred).
Immunity. The ImmuneToStagger tag (StatusTag 2) cancels the stagger entirely.
Diminishing returns during brawls. These apply only while isInFightMode is set. They come from StaggerDiminisher and FighterConfig:
- Staggers within a 2.5 s window chain together.
- Each chained stagger multiplies the duration by 0.65 to the power of the number of earlier staggers in the chain (floor 0.05).
- After 3 consecutive staggers, the skater is stagger-immune for 1.5 s.
Puck drop on stagger#
This only applies if the victim has the puck.
| Rule | Value |
|---|---|
| Base drop chance | Lerp(0.1, 0.9, InverseLerp(−30, 10, score)): 10% at score ≤ −30, 90% at score ≥ 10 |
Victim skating ≥ 14 m/s (HighSpeedStaggerPuckLossSpeed) |
Chance raised to at least 90% |
| Victim was already staggered while carrying within the last 4 s | Puck is always lost |
Human-controlled team and IsBackHit true |
Puck is kept (no roll) (reason unclear) |
| When dropped | Puck flies in a random flat direction at Random.Range(2,5) m/s with Random.Range(0,3) lift; base re-pickup lock 0.8 s (AdjustStaggerPuckLossPickupLockDuration) |
Source: SkaterCollision::HandleHitted (stagger branch); Forward::Staggered; StaggerDiminisher::TryStagger; StaggeredState::OnEnter; FighterConfig asset (staggerDR*).
5. Helmets and other equipment#
Each item has drop settings in its Skaters.Equipment asset.
| Equipment | Class | Drop on KO | KO chance | Drop on stagger | Stagger chance | Power threshold |
|---|---|---|---|---|---|---|
| StandardHelmet | Standard | yes | 2% | yes | 1% | 8 |
| GoldenHelmet | Special | yes | 2% | yes | 1% | 8 |
| WingedHelmet | Standard | yes | 7.5% | no | – | – |
| Heavy / Iron / Lancelov / Propeller helmets (all levels) | Special | yes | 7.5% | no | – | – |
| FrogHelmet | StatusOnly | yes | 5% | no | – | – |
| EnragedHelmet | StatusOnly | no | – | no | – | – |
| DefaultGloves | Gloves | no | (7.5%) | no | – | – |
How the rolls work:
- On knockout:
Forward.NotifyEquipmentsKnockoutrolls oneRandom.valuefor the KO. Every equipped item withcanDropOnKoanddropOnKoChance > rollis unequipped and falls off. - On stagger:
Forward.TryDropHelmet(Bodycheck, power)rolls once. An item drops whencanDropOnBodyChecked,dropOnBodyCheckedChance > roll, andpower ≥ dropOnBodyCheckedPowerThreshold. Power is the stagger score, 0–40. - On punch: the same roll, but without the power threshold.
Stat effects of the special helmets are listed in status effects.
Source: Skaters.Equipment assets; Forward::TryDropHelmet, Forward::NotifyEquipmentsKnockout.
6. Sticks: losing and breaking#
Stick handling happens in Forward.Knockout, after the KO state starts. It applies only if the victim currently has a stick (numStick > 0).
- Lumberjack. If the victim's opponents own Lumberjack (
StickBreakingKnockoutRelic), the stick breaks (SkaterAbility.BreakStick) whenRandom.value < 0.25at relic level 1, or< 0.5at level ≥ 2. - Lost stick. Otherwise, if the KO was flagged to lose the stick (for example Bonecrusher), the stick is knocked loose (
SkaterAbility.LoseStick). It flies at a random speed of 2.5–8 with 1.5–8 lift.
The code shows no base stick-break roll on an ordinary KO. Sticks also break from other sources, such as Glass Stick, shots and passes. A skater without a stick cannot shoot or pass until they get one back (glossary). Replay.StickLifecycleProvider and BrokenStickLifecycleProvider only hold the stick prefabs used for replays.
Source: Forward::Knockout (tail section), StickBreakingKnockoutRelicController::ShouldBreak, catalog entry for StickBreakingKnockoutRelic.
7. Immunity and who can be knocked out#
Forward.CanBeKnockedOut and CanBeKnockedOutBy return false in these cases:
- An internal flag on the skater blocks it (
Forward+0x4ED). - The skater is a referee currently taking a faceoff (
IsRefereeInFaceoff). - The skater has Dead Weight (
Anchor). - The skater has the ImmuneToKnockout tag, unless the caller passes
ignoreImmunity. - The skater's current movement state refuses knockouts.
KnockoutStatedoes;BlockingShotStatedoes not (state check inferred from the overrides).
The Immune status effect gives ImmuneToKnockout, ImmuneToStagger and ImmuneToPokecheck for 1 s by default (see status effects).
8. Referees#
- A referee is a
ForwardwithskaterType = Referee(5), so the same bodycheck rules apply. The glossary says: "Referees can be bodychecked." - A referee's KO lasts twice as long (§3).
- A referee cannot be knocked out while running a faceoff.
Power-ups that involve referees:
| Power-up | Effect |
|---|---|
Frogeree (FrogOnHitRef) |
Knocking out the ref frogs opponents for 30 s |
| Referee Rumble | Your team becomes enraged when the ref is knocked out |
Briberee (RefHitOtherTeam) |
The ref bodychecks your opponents |
Part of the Play (RefBlockShot) |
The ref tries to block opposing shots and gets +2 size |
| Two-Headed Zebra | Adds one extra referee |
| Whistle Blower | Referees join your team and can be controlled |
9. Blocking shots#
ForwardBlockshot holds eight sets of directional colliders: E, NE, N, NW, W, SW, S and SE. Activate(direction) turns on the set facing the skater's direction while it is in BlockingShotState (the shot-block slide).
While blocking:
- the skater cannot be staggered, cannot bodycheck and cannot pass;
- the skater can still be knocked out (
CanBeKnockedOutreturns true).
Source: ForwardBlockshot; Movements.MovementStates.BlockingShotState overrides.
Comments