PitchOutcomes = { StrikeOut = "StrikeOut", Walk = "Walk", } pitchTracker = { --- Position of the pitch, or nil, if one has not been recorded. ---@type number | nil recordedPitchX = nil, -- TODO: Replace with timer, repeatedly reset, instead of constantly setting to 0 secondsSinceLastPitch = 0, strikes = 0, balls = 0, } function pitchTracker:reset() self.strikes = 0 self.balls = 0 end function pitchTracker:recordIfPassed(ball) if ball.y < C.StrikeZoneStartY then self.recordedPitchX = nil elseif not pitchTracker.recordedPitchX then self.recordedPitchX = ball.x end end ---@param didSwing boolean ---@param fieldingTeamInningData TeamInningData function pitchTracker:updatePitchCounts(didSwing, fieldingTeamInningData) if not self.recordedPitchX then return end local currentPitchingStats = fieldingTeamInningData.pitching if didSwing or self.recordedPitchX > C.StrikeZoneStartX and self.recordedPitchX < C.StrikeZoneEndX then self.strikes = self.strikes + 1 currentPitchingStats.strikes = currentPitchingStats.strikes + 1 if self.strikes >= 3 then self:reset() return PitchOutcomes.StrikeOut end else self.balls = self.balls + 1 currentPitchingStats.balls = currentPitchingStats.balls + 1 if self.balls >= 4 then self:reset() return PitchOutcomes.Walk end end end ----------------- -- Throw Meter -- ----------------- throwMeter = { value = 0, } function throwMeter:reset() self.value = 0 end ---@return number | nil flyTimeMs Returns nil when a throw is NOT requested. function throwMeter:readThrow() if self.value > C.ThrowMeterMax then return (C.PitchFlyMs / (self.value / C.ThrowMeterMax)) end return nil end --- Applies the given charge, but drains some meter for how much time has passed ---@param deltaSeconds number ---@param chargeAmount number function throwMeter:applyCharge(deltaSeconds, chargeAmount) self.value = math.max(0, self.value - (deltaSeconds * C.ThrowMeterDrainPerSec)) self.value = self.value + math.abs(chargeAmount * C.UserThrowPower) end