From 4d69e77d9fed576ca2f958f4b048d5404fc8de2a Mon Sep 17 00:00:00 2001 From: Sage Vaillancourt Date: Sun, 9 Feb 2025 12:30:53 -0500 Subject: [PATCH] Class-ify npc -> Npc In the future, may keep a small memory of past pitches/plays, and use it to adjust swings, baserunning, etc. --- src/main.lua | 9 +++++---- src/npc.lua | 46 ++++++++++++++++++++++++++++------------------ 2 files changed, 33 insertions(+), 22 deletions(-) diff --git a/src/main.lua b/src/main.lua index fcc148d..cc6cbaa 100644 --- a/src/main.lua +++ b/src/main.lua @@ -42,6 +42,7 @@ local gfx , C = playdate.graphics, C local announcer = Announcer.new() local baserunning = Baserunning.new(announcer) local fielding = Fielding.new() +local npc = Npc.new(baserunning.runners, fielding.fielders) ---@alias SimpleAnimator { currentValue: fun(self): number; reset: fun(self, durationMs: number | nil) } @@ -389,8 +390,8 @@ local function updateGameState() batAngleDeg = (playdate.getCrankPosition() + C.CrankOffsetDeg) % 360 batSpeed = crankLimited else - batAngleDeg = npc.updateBatAngle(ball, catcherThrownBall, deltaSeconds) - batSpeed = npc.batSpeed() * deltaSeconds + batAngleDeg = npc:updateBatAngle(ball, catcherThrownBall, deltaSeconds) + batSpeed = npc:batSpeed() * deltaSeconds end updateBatting(batAngleDeg, batSpeed) @@ -410,7 +411,7 @@ local function updateGameState() end end elseif offenseState == C.Offense.running then - local appliedSpeed = playerOnOffense and crankLimited or npc.runningSpeed(baserunning.runners) + local appliedSpeed = playerOnOffense and crankLimited or npc:runningSpeed() if updateNonBatterRunners(appliedSpeed) then secondsSinceLastRunnerMove = 0 else @@ -441,7 +442,7 @@ local function updateGameState() if fielderHoldingBall then local outedSomeRunner = baserunning:outEligibleRunners(fielderHoldingBall) if playerOnOffense then - npc.fielderAction(fielding, baserunning, offenseState, fielderHoldingBall, outedSomeRunner, ball, launchBall) + npc:fielderAction(offenseState, fielderHoldingBall, outedSomeRunner, ball, launchBall) end end diff --git a/src/npc.lua b/src/npc.lua index 833ddf1..6c32542 100644 --- a/src/npc.lua +++ b/src/npc.lua @@ -2,14 +2,27 @@ local npcBatDeg = 0 local BaseNpcBatSpeed = 1500 local npcBatSpeed = 1500 +---@class Npc +---@field runners Runner[] +---@field fielders Fielder[] -- selene: allow(unscoped_variables) -npc = {} +Npc = {} + +---@param runners Runner[] +---@param fielders Fielder[] +---@return Npc +function Npc.new(runners, fielders) + return setmetatable({ + runners = runners, + fielders = fielders, + }, { __index = Npc }) +end ---@param ball XyPair ---@param catcherThrownBall boolean ---@param deltaSec number ---@return number -function npc.updateBatAngle(ball, catcherThrownBall, deltaSec) +function Npc:updateBatAngle(ball, catcherThrownBall, deltaSec) if not catcherThrownBall and ball.y > 200 and ball.y < 230 and (ball.x < C.Center.x + 15) then npcBatDeg = npcBatDeg + (deltaSec * npcBatSpeed) else @@ -19,17 +32,16 @@ function npc.updateBatAngle(ball, catcherThrownBall, deltaSec) return npcBatDeg end -function npc.batSpeed() +function Npc:batSpeed() return npcBatSpeed end ----@param runners Runner[] ---@return number -function npc.runningSpeed(runners) - if #runners == 0 then +function Npc:runningSpeed() + if #self.runners == 0 then return 0 end - local touchedBase = utils.isTouchingBase(runners[1].x, runners[1].y) + local touchedBase = utils.isTouchingBase(self.runners[1].x, self.runners[1].y) if not touchedBase or touchedBase == C.Bases[C.Home] then return 10 end @@ -72,7 +84,7 @@ end --- Returns x,y of the out target ---@param runners Runner[] ---@return number|nil, number|nil -function npc.getNextOutTarget(runners) +local function getNextOutTarget(runners) -- TODO: Handle missed throws, check for fielders at target, etc. local targets = getForcedOutTargets(runners) if #targets ~= 0 then @@ -85,14 +97,14 @@ function npc.getNextOutTarget(runners) end end ----@param fielding Fielding +---@param fielders Fielder[] ---@param fielder Fielder ---@param runners Runner[] ---@param launchBall LaunchBall -function npc.tryToMakeAPlay(fielding, fielder, runners, ball, launchBall) - local targetX, targetY = npc.getNextOutTarget(runners) +local function tryToMakeAPlay(fielders, fielder, runners, ball, launchBall) + local targetX, targetY = getNextOutTarget(runners) if targetX ~= nil and targetY ~= nil then - local nearestFielder = utils.getNearestOf(fielding.fielders, targetX, targetY) + local nearestFielder = utils.getNearestOf(fielders, targetX, targetY) nearestFielder.target = utils.xy(targetX, targetY) if nearestFielder == fielder then ball.heldBy = fielder @@ -102,27 +114,25 @@ function npc.tryToMakeAPlay(fielding, fielder, runners, ball, launchBall) end end ----@param fielding Fielding ----@param baserunning Baserunning ---@param offenseState OffenseState ---@param fielder Fielder ---@param outedSomeRunner boolean ---@param ball { x: number, y: number, heldBy: Fielder | nil } ---@param launchBall LaunchBall -function npc.fielderAction(fielding, baserunning, offenseState, fielder, outedSomeRunner, ball, launchBall) +function Npc:fielderAction(offenseState, fielder, outedSomeRunner, ball, launchBall) if offenseState ~= C.Offense.running then return end if outedSomeRunner then -- Delay a little before the next play playdate.timer.new(750, function() - npc.tryToMakeAPlay(fielding, fielder, baserunning.runners, ball, launchBall) + tryToMakeAPlay(self.fielders, fielder, self.runners, ball, launchBall) end) else - npc.tryToMakeAPlay(fielding, fielder, baserunning.runners, ball, launchBall) + tryToMakeAPlay(self.fielders, fielder, self.runners, ball, launchBall) end end if not playdate then - return npc + return Npc end