Class-ify npc -> Npc

In the future, may keep a small memory of past pitches/plays, and use it to adjust swings, baserunning, etc.
This commit is contained in:
Sage Vaillancourt 2025-02-09 12:30:53 -05:00
parent 575c9e0a18
commit 4d69e77d9f
2 changed files with 33 additions and 22 deletions

View File

@ -42,6 +42,7 @@ local gfx <const>, C <const> = 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

View File

@ -2,14 +2,27 @@ local npcBatDeg = 0
local BaseNpcBatSpeed <const> = 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