diff --git a/src/baserunning.lua b/src/baserunning.lua index 661aeea..b8a74c4 100644 --- a/src/baserunning.lua +++ b/src/baserunning.lua @@ -16,7 +16,8 @@ ---@field onThirdOut fun() Baserunning = {} --- TODO: Implement slides. Would require making fielders' gloves "real objects" whose state is tracked. +-- TODO: Implement slides? Would require making fielders' gloves "real objects" whose state is tracked. +-- TODO: Don't allow runners to occupy the same base! ---@param announcer Announcer ---@return Baserunning diff --git a/src/constants.lua b/src/constants.lua index a5ecd5f..4ac30ca 100644 --- a/src/constants.lua +++ b/src/constants.lua @@ -98,6 +98,7 @@ C.Offense = { batting = "batting", running = "running", walking = "walking", + homeRun = "homeRun", } ---@alias Side "offense" | "defense" @@ -124,17 +125,23 @@ C.WalkedRunnerSpeed = 10 C.ResetFieldersAfterSeconds = 2.5 C.OutfieldWall = { - { x = 0, y = 137 }, - { x = 233, y = 32 }, - { x = 450, y = 29 }, - { x = 550, y = 59 }, - { x = 739, y = 64 }, - { x = 850, y = 19 }, - { x = 1100, y = 31 }, - { x = 1185, y = 181 }, - { x = 1201, y = 224 }, + { x = -400, y = -103 }, + { x = -167, y = -208 }, + { x = 50, y = -211 }, + { x = 150, y = -181 }, + { x = 339, y = -176 }, + { x = 450, y = -221 }, + { x = 700, y = -209 }, + { x = 785, y = -59 }, + { x = 801, y = -16 }, } +C.BottomOfOutfieldWall = {} + +for i, v in ipairs(C.OutfieldWall) do + C.BottomOfOutfieldWall[i] = utils.xy(v.x, v.y + 40) +end + if not playdate then return C end diff --git a/src/fielding.lua b/src/fielding.lua index 4b0a9c8..b524f23 100644 --- a/src/fielding.lua +++ b/src/fielding.lua @@ -80,7 +80,10 @@ end ---@return boolean inCatchingRange local function updateFielderPosition(deltaSeconds, fielder, ballPos) if fielder.target ~= nil then - if not utils.moveAtSpeed(fielder, fielder.speed * deltaSeconds, fielder.target) then + if + utils.pointIsSquarelyAboveLine(fielder, C.BottomOfOutfieldWall) + or not utils.moveAtSpeed(fielder, fielder.speed * deltaSeconds, fielder.target) + then fielder.target = nil end end diff --git a/src/images/launcher/wrapping-pattern.png b/src/images/launcher/wrapping-pattern.png new file mode 100644 index 0000000..54f73c7 Binary files /dev/null and b/src/images/launcher/wrapping-pattern.png differ diff --git a/src/main.lua b/src/main.lua index 6d19a50..2d70da1 100644 --- a/src/main.lua +++ b/src/main.lua @@ -416,8 +416,7 @@ function Game:updateBatting(batDeg, batSpeed) local ballDestX = self.state.ball.x + (ballVelX * C.BattingPower) local ballDestY = self.state.ball.y + (ballVelY * C.BattingPower) pitchTracker:reset() - local hitBallScaler = gfx.animator.new(2000, 9 + (mult * mult * 0.5), C.SmallestBallRadius, utils.easingHill) - self.state.ball:launch(ballDestX, ballDestY, playdate.easingFunctions.outQuint, 2000, nil, hitBallScaler) + local flyTimeMs = 2000 -- TODO? A dramatic eye-level view on a home-run could be sick. local battingTeamStats = self:battingTeamCurrentInning() battingTeamStats.hits[#battingTeamStats.hits + 1] = utils.xy(ballDestX, ballDestY) @@ -428,8 +427,21 @@ function Game:updateBatting(batDeg, batSpeed) -- TODO: Have a fielder chase for the fly-out return end - self.baserunning:convertBatterToRunner() + if utils.pointIsSquarelyAboveLine(utils.xy(ballDestX, ballDestY), C.OutfieldWall) then + playdate.timer.new(flyTimeMs, function() + -- Verify that the home run wasn't intercepted + 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 + end + end) + end + + local hitBallScaler = gfx.animator.new(2000, 9 + (mult * mult * 0.5), C.SmallestBallRadius, utils.easingHill) + self.state.ball:launch(ballDestX, ballDestY, playdate.easingFunctions.outQuint, flyTimeMs, nil, hitBallScaler) + + self.baserunning:convertBatterToRunner() self.fielding:haveSomeoneChase(ballDestX, ballDestY) end end @@ -490,14 +502,7 @@ function Game:updateGameState() end if self.state.secondsSincePitchAllowed > C.ReturnToPitcherAfterSeconds and not self.state.pitchIsOver then - local outcome = pitchTracker:updatePitchCounts(self.state.didSwing) - local currentPitchingStats = self:fieldingTeamCurrentInning().pitching - if outcome == PitchOutcomes.Strike or outcome == PitchOutcomes.StrikeOut then - currentPitchingStats.strikes = currentPitchingStats.strikes + 1 - end - if outcome == PitchOutcomes.Ball or outcome == PitchOutcomes.Walk then - currentPitchingStats.balls = currentPitchingStats.balls + 1 - end + local outcome = pitchTracker:updatePitchCounts(self.state.didSwing, self:fieldingTeamCurrentInning()) if outcome == PitchOutcomes.StrikeOut then self:strikeOut() elseif outcome == PitchOutcomes.Walk then @@ -560,6 +565,12 @@ function Game:updateGameState() 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) + if #self.baserunning.runners == 0 then + self.state.offenseState = C.Offense.batting + self.baserunning:pushNewBatter() + end end local fielderHoldingBall = self.fielding:updateFielderPositions(self.state.ball, self.state.deltaSeconds) diff --git a/src/utils.lua b/src/utils.lua index 3932358..5c1d4ef 100644 --- a/src/utils.lua +++ b/src/utils.lua @@ -83,6 +83,10 @@ function utils.moveAtSpeed(mover, speed, target) return false end +function utils.within(within, n1, n2) + return math.abs(n1 - n2) < within +end + ---@generic T ---@param array T[] ---@param condition fun(T): boolean @@ -266,19 +270,24 @@ pitchTracker = { end, ---@param didSwing boolean - updatePitchCounts = function(self, didSwing) + ---@param fieldingTeamInningData TeamInningData + updatePitchCounts = function(self, 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