Critical Shots (Crits)#
A critical shot ("crit") is a shot rolled as critical at release. Crits hit harder (more puck speed), are a little more accurate, make the goalie less likely to save, knock out skaters the puck touches, and trigger a set of crit-themed relics.
1. The crit roll#
Total = permanent + conditional (CritOddsResult.Total)
IsCrit = Random.Range(1, 101) <= Total (integer roll, 1..100)
- Base crit chance is 2%.
GetCriticalOddsstarts withpermanent = 2, conditional = 0. - If
Total >= 100the shot is always a crit. Several effects return +500 to force a crit. permanentandconditionalare added together for the roll. TheisConditionalflag only decides which bucket a source goes into, which matters for UI and quests, not for the roll itself.- The roll is made once, when the shot is released.
Source: Skaters.CriticalShot::IsCriticalShot, ::GetCriticalOdds, Skaters.CritOddsResult, Skaters.CritModifierResult.
1.1 How sources combine#
GetCriticalOdds(forward, shotType) builds the total in this order:
- Start at 2 (permanent).
- Every talent / power-up on the skater (
SkaterData.powerups) that implementsICritModifieris asked for a value. - The skater's active ability (
SkaterData.ability) is asked, if it implementsICritModifier. - Every team relic (
TeamData.relics) that implementsICritModifieris asked. - Pucky Charms (BothTeamCrit): if the opposing team owns it and your team does not, its
oddsIncreaseis also added to your shots. That is the "for both teams" part. - Puck Pucks (CriticalMass): if your team owns it, both buckets are multiplied by
multiplier(2.0) and truncated to integers. The multiplier also applies to the base 2%, so the base becomes 4%.
Only positive results are added (if odds > 0). A source that returns 0 or less contributes nothing. Sources stack additively before the Critical Mass multiplier:
Total = trunc( (2 + Σ positive modifiers) × CriticalMassMultiplier ) // multiplier = 1 if not owned
1.2 Which shots can crit#
Only two code paths roll for a crit: SkaterAbility::WristShot and the slapshot coroutine SkaterAbility/<_Slapshot>::MoveNext.
| Shot | ShotType passed to the roll | Can crit? |
|---|---|---|
| Wrist shot (forehand) | Wristshot (0) |
Yes |
| Wrist shot (backhand) | Wristshot (0) |
Only if the skater has at least one crit-modifier source (HasCritModifierSource). Otherwise the rolled crit is cancelled. |
| Slapshot (including one-timer slapshots) | Slapshot (1) |
Yes |
| Yo-Yo one-timer | Yoyo (6) when isYoyo and the Yo-Yo check passes |
Yes |
| Bat, Redirect/deflection, Throw | no roll | No (no IsCriticalShot call in Bat, the redirect path or ThrowPuck) |
Notable: neither call site passes
ShotType.OneTimer (5). One-timer slapshots roll asSlapshot. Because of that, Sweet Spot (CriticalOneTimerRelic), which only adds odds whenshotType == OneTimer, appears to do nothing for the actual crit roll in this build. The bench-quest checker (BenchQuestSystem::OnShot) also callsGetCriticalOddswith the shot'sShootingArg.shotType, which may beOneTimer, so Sweet Spot can count toward quest progress such as the Kirby "100% crit chance" quest (inferred).
Source: SkaterAbility::WristShot (backhand check via SkatingAnimation::IsBackhand and CriticalShot::HasCritModifierSource), <_Slapshot>d__100::MoveNext.
1.3 Forced crits that bypass the roll#
| Effect | Rule |
|---|---|
| Charge Shot (talent) | If holdTime × chargeSpeedMulti ≥ maxChargetime (2.5 s), the slapshot is forced critical. Level 2 has chargeSpeedMulti = 1.33, so a full charge takes about 1.88 s. |
| Dry Noodle (relic) | While shotsLeft > 0 it returns +500 (a guaranteed crit). Each crit roll the team makes uses one charge (IsCriticalShot decrements the relic's counter). It has 3 shots, or 5 at level 2 (shots + upgradeShots). |
Yo-Yo level 2 (oneTimerSelfCrit) |
+500 when the shot type is Yoyo. One-timering your own yo-yo puck is always a crit. |
2. What a crit does#
| Effect | Value | Source |
|---|---|---|
| Extra shot power ("crit strength") | + trunc(50 × (1 + Bolt% / 100 + Stix% / 100)) puck speed units, added before the close-range power reduction |
CriticalShot::GetPowerValue (const ShotPowerBonus = 50) |
| Extra accuracy | +10 accuracy for the aim-error roll |
CriticalShot.AccuracyValue = 10; added in GetWristShotDirection and in the slapshot path |
| Goalie save chance | −25 (save-chance points) |
ShotQualityCalculator.CriticalBonus = 25, applied when ShootingArg.isCritical |
| Knocks out skaters it touches | see below | Puck::HandleCriticalShotKnockout from Puck::OnTriggerEnter |
| VFX | CriticalShotVFX at release plus CriticalShotTrailVFX on the puck |
Skaters.CriticalShotVfxController::OnShot |
2.1 Crit strength (power bonus)#
CritPower = trunc( 50 × (1 + BoltPct/100 + StixPct/100) )
BoltPct = Bolt relic ("D20"): 25 at level 1, 25+25 = 50 at level 2
StixPct = Stix (CritBoost) talent: 25, only at talent level ≥ 2, and only if the skater's power-ups are enabled
| Owned | Crit power bonus |
|---|---|
| nothing | +50 |
| D20 Lv1 | +62 |
| Stix Lv2 | +62 |
| D20 Lv2 | +75 |
| D20 Lv1 + Stix Lv2 | +75 |
| D20 Lv2 + Stix Lv2 | +87 |
For scale, an uncapped 100-Shot-Power wrist shot is about 50 speed and a slapshot about 70 (see shooting.md). A crit therefore roughly doubles wrist-shot speed.
2.2 Crit knockouts#
During a crit shot (ShootingArg.isCritical), any Forward the puck's trigger touches, other than the shooter, is knocked out if CanBeKnockedOut() allows it:
- knock force =
9 + 11 × clamp01((ShooterShotPower − 40) / 160)along the puck's travel direction Random.Range(5, 10)andRandom.Range(2, 5)are passed as furtherKnockoutparameters (likely the upward component and the knockout duration in seconds) (inferred mapping)willLoseStick = trueandisCausedByPuck = true, so the victim drops their stick
Immunity: skaters tagged ImmuneToKnockout are protected because CanBeKnockedOut checks the tag (inferred).
Source: Tape2Tape.Puck::HandleCriticalShotKnockout, Skaters.Forward::Knockout.
3. Crit-related talents, abilities and relics#
Values come from the serialized assets. "Cond." means the source reports isConditional = true.
3.1 Flat or always-on odds#
| In-game name | Class | Type | Effect on the formula | Data |
|---|---|---|---|---|
| Stix | CritBoost |
Talent | +oddsIncrease (perm.). At Lv2 also +25% crit strength |
odds 10, power +25% |
| Good Luck Puck | CriticalRelic |
Relic | +oddsIncrease (perm.) |
15 |
| Slot Cannon | CriticalChaos |
Chaos talent | +oddsIncrease (perm.), and −30 Shot Power through stat bonuses |
odds 20, shotPower −30 |
| Pucky Charms | BothTeamCrit |
Relic | +oddsIncrease (perm.) for the owner. Also added to the opponent's shots when they don't own it |
20 |
| Puck Pucks | CriticalMass |
Relic | ×multiplier on the final total, including the base 2% |
×2.0 |
| D20 | BoltRelic |
Relic | crit strength only (+25% / +50%), no odds | 25 / 25 |
3.2 Conditional odds#
| In-game name | Class | Condition (verified) | Odds | Bucket |
|---|---|---|---|---|
| Special D | DefenseCrit |
shooter's skaterType is LeftDef or RightDef |
+20 | perm. |
| Shrimpy Bits | SmallPlayerCrit |
shooter's ForwardData.skaterSize is ExtraSmall or Small |
+25 | perm. |
| Blowtorch | RagedCritical |
shooter has status tag Enraged |
+25 | cond. |
| Golden Wheats | GoldenHelmetCritRelic |
shooter HasGoldenHelmet |
critOddsBonus × HelmetStackOvrTalent.GetHelmetPowerupMultiplier (base 10) |
perm. |
| Sweet Spot | CriticalOneTimerRelic |
shotType == OneTimer. Not passed by the shot code, see §1.2 |
+10 (Lv1) / +15 (Lv2) | cond. |
| Crit Stacks | EscalatingCrit |
+bonusPerNonCrit × consecutiveNonCrits. The counter goes up on each of the skater's non-crit shots and resets to 0 on a crit (EscalatingCritController::OnShot) |
+5 per non-crit shot | cond. |
| Critios | GoalCritAccumulator |
+accumulatedBonus. Each goal by this skater adds bonusPerGoal (GoalCritAccumulatorController::OnGoalScored). Saved in power-up state, so it persists across games |
+2 per goal | cond. |
| Glass Cannon | ShatterStrike |
shot type is Wristshot or Slapshot (shotType ≤ 1). Downside: stick breaks on non-crits |
+50 (Lv1) / +70 (Lv2) | cond. |
| Point Sniper | PointSniper |
shooter's position z is inside either blue-line band (bounds read from a rink singleton) | +20 (Lv1) / +30 (Lv2) | cond. |
| Crease Grease | FastRebound |
some teammate shot within the last timeSinceLastShot seconds (2.0), i.e. a rebound |
+20 | cond. |
| Game-Seven Glasses | LaserPointer |
period time remaining ≤ PeriodSeconds (20 at Lv1, 30 at Lv2) |
+50 | cond. |
| Breakaway Boost | BreakawayBoostRelic |
BreakawayBoostRelicController.IsInBreakaway(shooter) |
+50 (Lv1) / +75 (Lv2; baseCritOdds + upgradeCritOdds) |
cond. |
| Dry Noodle | DryNoodle |
shotsLeft > 0 (forced crit, see §1.3) |
+500 | cond. |
| Yo-Yo Lv2 | Yoyo (ability) |
oneTimerSelfCrit and shot type Yoyo |
+500 | cond. |
3.3 On-crit trigger relics (no odds change)#
| In-game name | Class | Effect |
|---|---|---|
| Egg Crispies | CritShotKnockout |
On a crit shot (ShootingArg.isCritical), knocks out all opponents (CritShotKnockoutController::OnShot calls Forward::Knockout) |
| Swamp Scoops | CritShotFrog |
Crits frog all opponents (SetFrogged). The data has duration = 60 |
| Fragile Flakes | CritShotEnrage |
Crits enrage your team |
| Coach's Grunt | CritShotDoubleGoal |
Goals from crits count as 2 goals |
| Pizzaghetti | Pizzaghetti |
"Critical goals are worth 2 goals" (empty marker class; checked elsewhere) |
3.4 Worked examples#
| Setup | Total crit % |
|---|---|
| Nothing | 2 |
| Stix + Good Luck Puck | 2 + 10 + 15 = 27 |
| Same + Puck Pucks | 27 × 2 = 54 |
| Enraged defenseman with Blowtorch + Special D + Puck Pucks | (2 + 25 + 20) × 2 = 94 |
| Glass Cannon Lv2 + Stix + Puck Pucks | (2 + 70 + 10) × 2 = 164, a guaranteed crit |
Source: GetCritModifier overrides on each class listed (Rogue.*, Rogue.Powerups.Chaos.CriticalChaos). Data from so2/Rogue.*.json. Names from loc_en.json.