From ad82035ccc62bba98f95b0873bcda8e729a999da Mon Sep 17 00:00:00 2001 From: Sage Vaillancourt Date: Wed, 19 Feb 2025 17:13:06 -0500 Subject: [PATCH] Pan back from home runs Move secondsSinceLastRunnerMove into Baserunning Tweak draw offset logic - a little jumpy, but better at following the long ball Taller GrassBackground Move secondsSinceLastPitch into pitchTracker Extract pitchTracker and throwMeter Slightly more truthful utils.moveAtSpeed() --- src/baserunning.lua | 15 ++-- src/constants.lua | 6 +- src/draw/panner.lua | 52 +++++++++++++ src/fielding.lua | 13 +++- src/graphics.lua | 5 +- src/images/game/GrassBackground.png | Bin 35043 -> 44351 bytes src/main.lua | 114 ++++++++++++++++------------ src/pitching.lua | 83 ++++++++++++++++++++ src/utils.lua | 104 ++++--------------------- 9 files changed, 242 insertions(+), 150 deletions(-) create mode 100644 src/draw/panner.lua create mode 100644 src/pitching.lua diff --git a/src/baserunning.lua b/src/baserunning.lua index b8a74c4..7f26082 100644 --- a/src/baserunning.lua +++ b/src/baserunning.lua @@ -12,6 +12,8 @@ ---@field scoredRunners Runner[] ---@field batter Runner | nil ---@field outs number +-- TODO: Replace with timer, repeatedly reset, instead of constantly setting to 0 +---@field secondsSinceLastRunnerMove number ---@field announcer Announcer ---@field onThirdOut fun() Baserunning = {} @@ -237,9 +239,9 @@ end --- Update non-batter runners. --- Returns true only if at least one of the given runners moved during this update ---@param appliedSpeed number | fun(runner: Runner): number ----@return boolean someRunnerMoved, number runnersScored +---@return boolean runnersStillMoving, number runnersScored, number secondsSinceLastMove function Baserunning:updateNonBatterRunners(appliedSpeed, forcedOnly, deltaSeconds) - local someRunnerMoved = false + local runnersStillMoving = false local runnersScored = 0 local speedIsFunction = type(appliedSpeed) == "function" @@ -251,18 +253,21 @@ function Baserunning:updateNonBatterRunners(appliedSpeed, forcedOnly, deltaSecon speed = appliedSpeed(runner) end local thisRunnerMoved, thisRunnerScored = self:updateRunner(runner, runnerIndex, speed, deltaSeconds) - someRunnerMoved = someRunnerMoved or thisRunnerMoved + runnersStillMoving = runnersStillMoving or thisRunnerMoved if thisRunnerScored then runnersScored = runnersScored + 1 end end end - if someRunnerMoved then + if runnersStillMoving then + self.secondsSinceLastRunnerMove = 0 self:updateForcedRunners() + else + self.secondsSinceLastRunnerMove = self.secondsSinceLastRunnerMove + deltaSeconds end - return someRunnerMoved, runnersScored + return runnersStillMoving, runnersScored, self.secondsSinceLastRunnerMove end -- luacheck: ignore diff --git a/src/constants.lua b/src/constants.lua index 4ac30ca..fddcfc1 100644 --- a/src/constants.lua +++ b/src/constants.lua @@ -70,8 +70,8 @@ C.BallOffscreen = 999 C.PitchAfterSeconds = 6 C.ReturnToPitcherAfterSeconds = 2.4 C.PitchFlyMs = 1050 -C.PitchStartX = 195 -C.PitchStartY, C.PitchEndY = 105, 240 +C.PitchStart = utils.xy(195, 105) +C.PitchEndY = 240 C.DefaultLaunchPower = 4 @@ -91,7 +91,7 @@ C.SmallestBallRadius = 6 C.BatLength = 35 ----@alias OffenseState "batting" | "running" | "walking" +---@alias OffenseState "batting" | "running" | "walking" | "homeRun" --- An enum for what state the offense is in ---@type table C.Offense = { diff --git a/src/draw/panner.lua b/src/draw/panner.lua new file mode 100644 index 0000000..20841d2 --- /dev/null +++ b/src/draw/panner.lua @@ -0,0 +1,52 @@ +---@class Panner +Panner = {} + +local function panCoroutine(ball) + local offset = utils.xy(getDrawOffset(ball.x, ball.y)) + while true do + local target, deltaSeconds = coroutine.yield(offset.x, offset.y) + if target == nil then + offset = utils.xy(getDrawOffset(ball.x, ball.y)) + else + while utils.moveAtSpeed(offset, 200 * deltaSeconds, target, 20) do + target, deltaSeconds = coroutine.yield(offset.x, offset.y) + end + -- -- Pan back to ball + -- while utils.moveAtSpeed(offset, 200 * deltaSeconds, ball, 20) do + -- target, deltaSeconds = coroutine.yield(offset.x, offset.y) + -- end + end + end +end + +---@param ball XyPair +function Panner.new(ball) + return setmetatable({ + coroutine = coroutine.create(function() + panCoroutine(ball) + end), + panTarget = nil, + }, { __index = Panner }) +end + +---@param deltaSeconds number +---@return number offsetX, number offsetY +function Panner:get(deltaSeconds) + if self.holdUntil and self.holdUntil() then + self:reset() + end + local _, offsetX, offsetY = coroutine.resume(self.coroutine, self.panTarget, deltaSeconds) + return offsetX, offsetY +end + +---@param panTarget XyPair +---@param holdUntil fun(): boolean +function Panner:panTo(panTarget, holdUntil) + self.panTarget = panTarget + self.holdUntil = holdUntil +end + +function Panner:reset() + self.holdUntil = nil + self.panTarget = nil +end diff --git a/src/fielding.lua b/src/fielding.lua index b524f23..223cef6 100644 --- a/src/fielding.lua +++ b/src/fielding.lua @@ -5,8 +5,9 @@ --- @field target XyPair | nil --- @field speed number +-- luacheck: ignore 631 ---@class Fielding ----@field fielders table +---@field fielders { first: Fielder, second: Fielder, shortstop: Fielder, third: Fielder, pitcher: Fielder, catcher: Fielder, left: Fielder, center: Fielder, right: Fielder } ---@field fielderHoldingBall Fielder | nil Fielding = {} @@ -113,7 +114,7 @@ end ---@param deltaSeconds number ---@return Fielder | nil fielderHoldingBall nil if no fielder is currently touching the ball function Fielding:updateFielderPositions(ball, deltaSeconds) - local fielderHoldingBall = nil + local fielderHoldingBall for _, fielder in pairs(self.fielders) do local inCatchingRange = updateFielderPosition(deltaSeconds, fielder, ball) if inCatchingRange and fielder.catchEligible then @@ -137,10 +138,14 @@ function Fielding.markIneligible(fielder) end) end -function Fielding:markAllIneligible() +function Fielding:markAllEligible(eligible) for _, fielder in pairs(self.fielders) do - fielder.catchEligible = false + fielder.catchEligible = eligible end +end + +function Fielding:resetEligibility() + self:markAllEligible(false) playdate.timer.new(750, function() for _, fielder in pairs(self.fielders) do fielder.catchEligible = true diff --git a/src/graphics.lua b/src/graphics.lua index a5bfb95..7bd8479 100644 --- a/src/graphics.lua +++ b/src/graphics.lua @@ -7,7 +7,8 @@ function getDrawOffset(ballX, ballY) if ballY > C.Screen.H or ballX >= C.BallOffscreen then return 0, 0 end - offsetY = math.max(0, -1 * ballY) + -- Keep the ball approximately in the center, once it's past C.Center.y - 30 + offsetY = math.max(0, (-1 * ballY) + C.Center.y - 30) if ballX > 0 and ballX < C.Screen.W then offsetX = 0 @@ -17,7 +18,7 @@ function getDrawOffset(ballX, ballY) offsetX = math.min(C.Screen.W * 2, (ballX * -1) + C.Screen.W) end - return offsetX * 1.3, offsetY * 1.5 + return offsetX * 1.3, offsetY end ---@class Blipper diff --git a/src/images/game/GrassBackground.png b/src/images/game/GrassBackground.png index b01de023c1cc3f31434246f3a46943201f63a21d..00bae5403d008f9d9dde47c6b0711912eb9790fc 100644 GIT binary patch literal 44351 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 = { ---@field batBase XyPair ---@field batTip XyPair ---@field batAngleDeg number --- TODO: Replace with timers, repeatedly reset, instead of constantly setting to 0 ----@field secondsSinceLastRunnerMove number ----@field secondsSincePitchAllowed number -- These are only sort-of global state. They are purely graphical, -- but they need to be kept in sync with the rest of the globals. ---@field runnerBlipper Blipper @@ -97,6 +96,7 @@ local teams = { ---@field private npc Npc ---@field private homeTeamBlipper Blipper ---@field private awayTeamBlipper Blipper +---@field private panner Panner ---@field private state MutableState Game = {} @@ -124,6 +124,7 @@ function Game.new(settings, announcer, fielding, baserunning, npc, state) fielding = fielding, homeTeamBlipper = homeTeamBlipper, awayTeamBlipper = awayTeamBlipper, + panner = Panner.new(ball), state = state or { batBase = utils.xy(C.Center.x - 34, 215), batTip = utils.xy(0, 0), @@ -135,8 +136,6 @@ function Game.new(settings, announcer, fielding, baserunning, npc, state) inning = 1, pitchIsOver = false, didSwing = false, - secondsSinceLastRunnerMove = 0, - secondsSincePitchAllowed = 0, battingTeamSprites = settings.awayTeamSprites, fieldingTeamSprites = settings.homeTeamSprites, runnerBlipper = runnerBlipper, @@ -151,7 +150,7 @@ function Game.new(settings, announcer, fielding, baserunning, npc, state) o.fielding:resetFielderPositions(teams.home.benchPosition) playdate.timer.new(2000, function() - ball:launch(C.PitchStartX, C.PitchStartY, playdate.easingFunctions.linear, nil, false) + o:returnToPitcher() end) BootTune:play() @@ -170,22 +169,22 @@ local Pitches = { -- Fastball function() return { - x = gfx.animator.new(0, C.PitchStartX, C.PitchStartX, playdate.easingFunctions.linear), - y = gfx.animator.new(C.PitchFlyMs / 1.3, C.PitchStartY, C.PitchEndY, playdate.easingFunctions.linear), + x = gfx.animator.new(0, C.PitchStart.x, C.PitchStart.x, playdate.easingFunctions.linear), + y = gfx.animator.new(C.PitchFlyMs / 1.3, C.PitchStart.y, C.PitchEndY, playdate.easingFunctions.linear), } end, -- Curve ball function() return { - x = gfx.animator.new(C.PitchFlyMs, C.PitchStartX + 20, C.PitchStartX, utils.easingHill), - y = gfx.animator.new(C.PitchFlyMs, C.PitchStartY, C.PitchEndY, playdate.easingFunctions.linear), + x = gfx.animator.new(C.PitchFlyMs, C.PitchStart.x + 20, C.PitchStart.x, utils.easingHill), + y = gfx.animator.new(C.PitchFlyMs, C.PitchStart.y, C.PitchEndY, playdate.easingFunctions.linear), } end, -- Slider function() return { - x = gfx.animator.new(C.PitchFlyMs, C.PitchStartX - 20, C.PitchStartX, utils.easingHill), - y = gfx.animator.new(C.PitchFlyMs, C.PitchStartY, C.PitchEndY, playdate.easingFunctions.linear), + x = gfx.animator.new(C.PitchFlyMs, C.PitchStart.x - 20, C.PitchStart.x, utils.easingHill), + y = gfx.animator.new(C.PitchFlyMs, C.PitchStart.y, C.PitchEndY, playdate.easingFunctions.linear), } end, -- Wobbbleball @@ -193,11 +192,11 @@ local Pitches = { return { x = { currentValue = function() - return C.PitchStartX + (10 * math.sin((ball.yAnimator:currentValue() - C.PitchStartY) / 10)) + return C.PitchStart.x + (10 * math.sin((ball.yAnimator:currentValue() - C.PitchStart.y) / 10)) end, reset = function() end, }, - y = gfx.animator.new(C.PitchFlyMs * 1.3, C.PitchStartY, C.PitchEndY, playdate.easingFunctions.linear), + y = gfx.animator.new(C.PitchFlyMs * 1.3, C.PitchStart.y, C.PitchEndY, playdate.easingFunctions.linear), } end, } @@ -260,7 +259,18 @@ function Game:pitch(pitchFlyTimeMs, pitchTypeIndex) self.state.ball.yAnimator:reset() end - self.state.secondsSincePitchAllowed = 0 + pitchTracker.secondsSinceLastPitch = 0 +end + +function Game:pitcherIsReady() + local pitcher = self.fielding.fielders.pitcher + local pitcherIsOnTheMound = utils.distanceBetweenPoints(pitcher, C.PitcherStartPos) < C.BaseHitbox + return pitcherIsOnTheMound + and ( + self.state.ball.heldBy == pitcher + or utils.distanceBetweenPoints(pitcher, self.state.ball) < C.BallCatchHitbox + or utils.distanceBetweenPoints(self.state.ball, C.PitchStart) < 2 + ) end function Game:nextHalfInning() @@ -279,7 +289,6 @@ function Game:nextHalfInning() end Fielding.celebrate() - self.state.secondsSinceLastRunnerMove = -7 self.fielding:benchTo(self:getFieldingTeam().benchPosition) self.announcer:say("SWITCHING SIDES...") @@ -338,14 +347,14 @@ function Game:buttonControlledThrow(throwFlyMs, forbidThrowHome) end self.fielding:userThrowTo(targetBase, self.state.ball, throwFlyMs) - self.state.secondsSinceLastRunnerMove = 0 + self.baserunning.secondsSinceLastRunnerMove = 0 self.state.offenseState = C.Offense.running return true end function Game:nextBatter() - self.state.secondsSincePitchAllowed = -3 + pitchTracker.secondsSinceLastPitch = -3 self.baserunning.batter = nil playdate.timer.new(2000, function() pitchTracker:reset() @@ -390,6 +399,7 @@ function Game:updateBatting(batDeg, batSpeed) if batSpeed > 0 + and self.state.ball.y < 232 and utils.pointDirectlyUnderLine( self.state.ball.x, self.state.ball.y, @@ -399,7 +409,6 @@ function Game:updateBatting(batDeg, batSpeed) self.state.batTip.y, C.Screen.H ) - and self.state.ball.y < 232 then -- Hit! BatCrackReverb:play() @@ -434,6 +443,12 @@ function Game:updateBatting(batDeg, batSpeed) if utils.within(1, self.state.ball.x, ballDestX) and utils.within(1, self.state.ball.y, ballDestY) then self.announcer:say("HOME RUN!") self.state.offenseState = C.Offense.homeRun + -- Linger on the home-run ball for a moment, before panning to the bases. + playdate.timer.new(1000, function() + self.panner:panTo(utils.xy(0, 0), function() + return self:pitcherIsReady() + end) + end) end end) end @@ -447,14 +462,20 @@ function Game:updateBatting(batDeg, batSpeed) end ---@param appliedSpeed number | fun(runner: Runner): number ----@return boolean someRunnerMoved +---@return boolean runnersStillMoving, number secondsSinceLastRunnerMove function Game:updateNonBatterRunners(appliedSpeed, forcedOnly) - local runnerMoved, runnersScored = + local runnersStillMoving, runnersScored, secondsSinceLastRunnerMove = self.baserunning:updateNonBatterRunners(appliedSpeed, forcedOnly, self.state.deltaSeconds) if runnersScored ~= 0 then self:score(runnersScored) end - return runnerMoved + return runnersStillMoving, secondsSinceLastRunnerMove +end + +function Game:returnToPitcher() + self.fielding:resetEligibility() + self.fielding.fielders.pitcher.catchEligible = true + self.state.ball:launch(C.PitchStart.x, C.PitchStart.y, playdate.easingFunctions.linear, nil, true) end ---@param throwFly number @@ -494,18 +515,17 @@ function Game:updateGameState() local pitcher = self.fielding.fielders.pitcher if utils.distanceBetween(pitcher.x, pitcher.y, C.PitcherStartPos.x, C.PitcherStartPos.y) < C.BaseHitbox then - self.state.secondsSincePitchAllowed = self.state.secondsSincePitchAllowed + self.state.deltaSeconds + pitchTracker.secondsSinceLastPitch = pitchTracker.secondsSinceLastPitch + self.state.deltaSeconds end - if self.state.secondsSincePitchAllowed > C.ReturnToPitcherAfterSeconds and not self.state.pitchIsOver then + if pitchTracker.secondsSinceLastPitch > C.ReturnToPitcherAfterSeconds and not self.state.pitchIsOver then local outcome = pitchTracker:updatePitchCounts(self.state.didSwing, self:fieldingTeamCurrentInning()) if outcome == PitchOutcomes.StrikeOut then self:strikeOut() elseif outcome == PitchOutcomes.Walk then self:walk() end - -- Catcher has the ball. Throw it back to the pitcher - self.state.ball:launch(C.PitchStartX, C.PitchStartY, playdate.easingFunctions.linear, nil, true) + self:returnToPitcher() self.state.pitchIsOver = true self.state.didSwing = false end @@ -525,7 +545,7 @@ function Game:updateGameState() -- Walk batter to the plate self.baserunning:updateRunner(self.baserunning.batter, nil, crankLimited, self.state.deltaSeconds) - if self.state.secondsSincePitchAllowed > C.PitchAfterSeconds then + if pitchTracker.secondsSinceLastPitch > C.PitchAfterSeconds then if userOnDefense then local throwFly = throwMeter:readThrow() if throwFly and not self:buttonControlledThrow(throwFly, true) then @@ -540,32 +560,32 @@ function Game:updateGameState() or function(runner) return self.npc:runningSpeed(runner, self.state.ball) end - if self:updateNonBatterRunners(appliedSpeed) then - self.state.secondsSinceLastRunnerMove = 0 - else - self.state.secondsSinceLastRunnerMove = self.state.secondsSinceLastRunnerMove + self.state.deltaSeconds - if self.state.secondsSinceLastRunnerMove > C.ResetFieldersAfterSeconds then - -- End of play. Throw the ball back to the pitcher - self.state.ball:launch(C.PitchStartX, C.PitchStartY, playdate.easingFunctions.linear, nil, true) - -- This is ugly, and ideally would not be necessary if Fielding handled the return throw directly. - self.fielding:markAllIneligible() - self.fielding:resetFielderPositions() - self.state.offenseState = C.Offense.batting - -- TODO: Remove, or replace with nextBatter() - if not self.baserunning.batter then - self.baserunning:pushNewBatter() - end - end + local _, secondsSinceLastRunnerMove = self:updateNonBatterRunners(appliedSpeed, false) + if secondsSinceLastRunnerMove > C.ResetFieldersAfterSeconds then + -- End of play. Throw the ball back to the pitcher + self.state.offenseState = C.Offense.batting + self:returnToPitcher() end elseif self.state.offenseState == C.Offense.walking then if not self:updateNonBatterRunners(C.WalkedRunnerSpeed, true) then self.state.offenseState = C.Offense.batting end elseif self.state.offenseState == C.Offense.homeRun then - self:updateNonBatterRunners(C.WalkedRunnerSpeed * 3, false) + self:updateNonBatterRunners(C.WalkedRunnerSpeed * 2, false) if #self.baserunning.runners == 0 then - self.state.offenseState = C.Offense.batting self.baserunning:pushNewBatter() + -- Give the player a moment to enjoy their home run. + self.fielding:resetFielderPositions() + playdate.timer.new(1500, function() + self:returnToPitcher() + end) + actionQueue:upsert("waitForPitcherToHaveBall", 10000, function() + while not self:pitcherIsReady() do + coroutine.yield() + end + self.fielding:markAllEligible(true) + self.state.offenseState = C.Offense.batting + end) end end @@ -597,10 +617,10 @@ function Game:update() gfx.clear() gfx.setColor(gfx.kColorBlack) - local offsetX, offsetY = getDrawOffset(ball.x, ball.y) + local offsetX, offsetY = self.panner:get(self.state.deltaSeconds) gfx.setDrawOffset(offsetX, offsetY) - GrassBackground:draw(-400, -240) + GrassBackground:draw(-400, -720) ---@type { y: number, drawAction: fun() }[] local characterDraws = {} diff --git a/src/pitching.lua b/src/pitching.lua new file mode 100644 index 0000000..94412e0 --- /dev/null +++ b/src/pitching.lua @@ -0,0 +1,83 @@ +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 diff --git a/src/utils.lua b/src/utils.lua index 34af323..5bc364b 100644 --- a/src/utils.lua +++ b/src/utils.lua @@ -70,17 +70,24 @@ end ---@param mover { x: number, y: number } ---@param speed number ---@param target { x: number, y: number } ----@return boolean -function utils.moveAtSpeed(mover, speed, target) +---@param tau number | nil +---@return boolean isStillMoving +function utils.moveAtSpeed(mover, speed, target, tau) local x, y, distance = utils.normalizeVector(mover.x, mover.y, target.x, target.y) - if distance > 1 then - mover.x = mover.x - (x * speed) - mover.y = mover.y - (y * speed) - return true + if distance == 0 then + return false end - return false + if distance > (tau or 1) then + mover.x = mover.x - (x * speed) + mover.y = mover.y - (y * speed) + else + mover.x = target.x + mover.y = target.y + end + + return true end function utils.within(within, n1, n2) @@ -249,87 +256,6 @@ function utils.totalScores(stats) return homeScore, awayScore end -PitchOutcomes = { - StrikeOut = "StrikeOut", - Walk = "Walk", -} - -pitchTracker = { - --- Position of the pitch, or nil, if one has not been recorded. - ---@type number | nil - recordedPitchX = nil, - - 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 delta number ----@param chargeAmount number -function throwMeter:applyCharge(delta, chargeAmount) - self.value = math.max(0, self.value - (delta * C.ThrowMeterDrainPerSec)) - self.value = self.value + math.abs(chargeAmount * C.UserThrowPower) -end - if not playdate then - return utils, { pitchTracker = pitchTracker, PitchOutcomes = PitchOutcomes, throwMeter = throwMeter } + return utils end