Stats

In short

Every tunable number on the batter is a StatType. Batters, level perks, upgrades, synergies, ballparks and bosses all change stats with the same StatModifier (Add or Percent). The final value is (base + sum of Adds) x (1 + sum of Percents), and the multiplier never goes below 0.

How it works

  • PlayerStats.Get(stat) sums every Add and every Percent for that stat over the modifier list, then applies the formula above. GetInt rounds that to the nearest whole number.
  • Run stats (RunState.RecalculateStats), in order: batter modifiers, character level perks, every owned upgrade’s modifiers, active synergies’ bonuses. Order does not change the result.
  • For each at-bat the run stats are cloned and the park’s and the pitcher’s batterModifiers are added (RunManager.PlayCurrentRound; co-op does the same in CoopRun). These never touch the run’s own stats.
  • Batting cage: batter modifiers, level perks, starting kit and the park’s modifiers (no shop items, no synergies, no boss).
  • Text: StatModifier.Describe() writes Percent as +20% Power; Adds as +5 Launch Angle, except Timing Window in ms and the two Green stats as percentages.

Numbers

StatTypeShown asBaseFormatWhat reads it
PowerPower1x1.00SwingResolver.FromContact: exit velocity = the contact zone’s range (84 to 121 mph) x Power x the other factors
ContactContact1x1.00SwingResolver.HitRadius: reach = ball radius + barrel radius + 0.12 x Contact; Classify: perfect and nice zones x max(0.2, Contact)
TimingWindowTiming Window0.11ms (x1000)SwingResolver.HitRadius: reach x sqrt(TimingWindow / 0.11)
LaunchBonusLaunch Angle0+n degSwingResolver.FromContact: added to the rolled launch angle (clamped -15 to 75)
HomeRunMultiplierHR Multiplier1x1.00ScoreCalculator.Score: multiplies the home run score
CoinBonusCoins per HR0whole numberRunManager.InningCoins: coins per home run = 1 + CoinBonus
ExtraOutsExtra Outs0whole numberOuts per inning (RunManager, CoopRun)
RerollDiscountReroll Discount0whole numberShopService.RerollCost: subtracted after difficulty pricing, never below 0
GreenBonusGreen HR Score0.25+25%ScoreCalculator.GreenMultiplier: 1 + GreenBonus on a green swing
GreenStreakBonusGreen Streak Score0+n% per greenGreenMultiplier: + GreenStreakBonus x earlier greens in a row

Who changes each stat

StatSources
PowerMaple Bat +8%, Corked Bat +18%, Launch Pad Bat +4%, Titanium Bat +30%, Pine Tar Grip +6%, Spiked Cleats +6%; Baked Bean +20%, String Bean -8%; Baked Bean level perks +1% x3
ContactSweet Spot Tape +20%, Pine Tar Grip +10%, Sweet Spot Sticker +10%, Corked Bat -10%; String Bean +30%; Barrel Master +20%; Knuckle Sandwich -20%; String Bean level perks +2% x3
Timing WindowBatting Gloves +15%, Pocket Metronome +25%; Clockwork +20%; Baked Bean -15%; The Ace -15%; Midnight Yard -10%; Peapod level perks +2% x3
Launch AngleLaunch Pad Bat +5, Spiked Cleats +2
HR MultiplierShowboat Chain +25%, Pocket Metronome +15%; Slugger +50%
Coins per HRLucky Penny +1; High Roller +2; Pinto level perks +1 (level 2), +1 (level 5)
Extra OutsComfy Cleats +2; Pinto +2; Pinto level perk +1 (level 10)
Reroll DiscountReroll Coupon +1
Green HR ScoreGreen Light +0.25, Sweet Spot Sticker +0.15; In the Zone +0.5
Green Streak ScoreHot Streak Wristband +0.15

Example: Corked Bat plus Pine Tar Grip give Power (1 + 0) x (1 + 0.18 + 0.06) = 1.24. Example green: base 0.25 and Hot Streak 0.15 on your 3rd green in a row = 1 + 0.25 + 0.15 x 2 = x1.55.

In the code

FileWhat it does
Assets/_Project/Scripts/Stats/StatType.csThe enum; StatInfo.BaseValue, DisplayName, Format
Assets/_Project/Scripts/Stats/StatModifier.csModifierOp (Add, Percent); StatModifier.Add / Percent; Describe
Assets/_Project/Scripts/Stats/PlayerStats.csGet, GetInt, Clone
Assets/_Project/Scripts/Batting/SwingResolver.csReads Power, Contact, Timing Window, Launch Angle
Assets/_Project/Scripts/Batting/HitTables.csZone widths that Contact scales; exit velocity ranges that Power scales
Assets/_Project/Scripts/Ballparks/ScoreCalculator.csReads HR Multiplier and the Green stats

Gotchas

Timing Window is not seconds any more

The enum comment says “seconds early/late you can be”, but the only gameplay reader scales the bat’s hit radius by sqrt(TimingWindow / 0.11). The timing ring’s windows come from test-swinging the real bat (TimingWindowScanner). The 0.11 base is duplicated as SwingResolver.BaseTimingWindow.

Contact does two jobs since PR #46

More Contact means more reach (a taller aim helper) and wider contact zones: at Contact 1.3 the perfect zone is 0.04 x 1.3 = 0.052 m either side of the sweet spot (derived). Only the reach is visible. See Batting Explained.

  • Batter styles (trajectory, pull or push side, curve) are not stats; they live on BatterDefinition. See Numbers.
  • Percents add, not multiply: two +25% items are +50%, and The Ace (-15%) plus Midnight Yard (-10%) is -25%.
  • Coins per HR, Extra Outs and Reroll Discount are rounded with GetInt.
  • Park and boss modifiers apply only during the at-bat, so a park can’t change Coins per HR or Reroll Discount (none do).
  • In co-op, outs per turn use CoopRules.OutsForTurn(ExtraOuts). See Co-op Rules.