From 30f2eada72a1efc7f2adac537c0810e0ed4d61e8 Mon Sep 17 00:00:00 2001 From: Sage Vaillancourt Date: Sat, 8 Feb 2025 19:04:10 -0500 Subject: [PATCH] Extract almost all NPC fielding logic --- src/constants.lua | 4 ++- src/main.lua | 83 +++++------------------------------------------ src/npc.lua | 64 ++++++++++++++++++++++++++++++++++-- src/utils.lua | 8 +++++ 4 files changed, 81 insertions(+), 78 deletions(-) diff --git a/src/constants.lua b/src/constants.lua index 7b257af..703fe69 100644 --- a/src/constants.lua +++ b/src/constants.lua @@ -94,7 +94,9 @@ C.ThrowMeterDrainPerSec = 150 --- Controls how hard the ball can be hit, and --- how fast the ball can be thrown. -C.CrankPower = 3 +C.CrankPower = 10 + +C.PitchPower = 0.3 --- How fast baserunners move after a walk C.WalkedRunnerSpeed = 10 diff --git a/src/main.lua b/src/main.lua index c43a73e..2534147 100644 --- a/src/main.lua +++ b/src/main.lua @@ -85,7 +85,7 @@ local teams = { }, } -local PlayerTeam = teams.home +local PlayerTeam = teams.away local battingTeam = teams.away local outs = 0 local inning = 1 @@ -206,18 +206,10 @@ local function pitch(pitchFlyTimeMs, pitchTypeIndex) secondsSincePitchAllowed = 0 end ----@param base Base ----@return Runner | nil -local function getRunnerWithNextBase(base) - return utils.first(runners, function(runner) - return runner.nextBase == base - end) -end - local function updateForcedRunners() local stillForced = true for _, base in ipairs(C.Bases) do - local runnerTargetingBase = getRunnerWithNextBase(base) + local runnerTargetingBase = utils.getRunnerWithNextBase(runners, base) if runnerTargetingBase then if stillForced then runnerTargetingBase.forcedTo = base @@ -287,66 +279,6 @@ local function score(runnerIndex) announcer:say("SCORE!") end ----@return Base[] -local function npcGetForcedOutTargets() - local targets = {} - for _, base in ipairs(C.Bases) do - local runnerTargetingBase = getRunnerWithNextBase(base) - if runnerTargetingBase then - targets[#targets + 1] = base - else - return targets - end - end - return targets -end - ---- Returns the position,distance of the basest closest to the runner furthest from a base ----@return Base | nil, number | nil -local function getBaseOfStrandedRunner() - local farRunnersBase, farDistance - for _, runner in pairs(runners) do - if runner ~= batter then - local nearestBase, distance = utils.getNearestOf(C.Bases, runner.x, runner.y) - if farRunnersBase == nil or farDistance < distance then - farRunnersBase = nearestBase - farDistance = distance - end - end - end - - return farRunnersBase, farDistance -end - ---- Returns x,y of the out target ----@return number|nil, number|nil -local function npcGetNextOutTarget() - -- TODO: Handle missed throws, check for fielders at target, etc. - local targets = npcGetForcedOutTargets() - if #targets ~= 0 then - return targets[#targets].x, targets[#targets].y - end - - local baseCloseToStrandedRunner = getBaseOfStrandedRunner() - if baseCloseToStrandedRunner then - return baseCloseToStrandedRunner.x, baseCloseToStrandedRunner.y - end -end - ----@param fielder Fielder -local function npcTryToMakeAnOut(fielder) - local targetX, targetY = npcGetNextOutTarget() - if targetX ~= nil and targetY ~= nil then - local nearestFielder = utils.getNearestOf(Field.fielders, targetX, targetY) - nearestFielder.target = utils.xy(targetX, targetY) - if nearestFielder == fielder then - ball.heldBy = fielder - else - throwBall(targetX, targetY, playdate.easingFunctions.linear, nil, true) - end - end -end - local function readThrow() if throwMeter > C.ThrowMeterMax then return (C.PitchFlyMs / (throwMeter / C.ThrowMeterMax)) @@ -404,16 +336,17 @@ local function outEligibleRunners(fielder) return didOutRunner end -local function updateNpcFielder(fielder, outedSomeRunner) +local function npcFielderAction(fielder, outedSomeRunner) if offenseMode ~= C.Offense.running then return end if outedSomeRunner then + -- Delay a little before the next play playdate.timer.new(750, function() - npcTryToMakeAnOut(fielder) + npc.tryToMakeAPlay(fielder, runners, ball, throwBall) end) else - npcTryToMakeAnOut(fielder) + npc.tryToMakeAPlay(fielder, runners, ball, throwBall) end end @@ -617,7 +550,7 @@ local function updateGameState() if playerOnDefense then throwMeter = math.max(0, throwMeter - (deltaSeconds * C.ThrowMeterDrainPerSec)) - throwMeter = throwMeter + math.abs(crankLimited) + throwMeter = throwMeter + math.abs(crankLimited * C.PitchPower) end if offenseMode == C.Offense.batting then @@ -699,7 +632,7 @@ local function updateGameState() buttonControlledThrow(Field.fielders.pitcher, throwFly) end else - updateNpcFielder(fielder, outedSomeRunner) + npcFielderAction(fielder, outedSomeRunner) end end diff --git a/src/npc.lua b/src/npc.lua index 2f596e3..2e62c84 100644 --- a/src/npc.lua +++ b/src/npc.lua @@ -30,6 +30,66 @@ function npc.runningSpeed(runners) return 0 end -if not playdate then - return utils +---@return Base[] +local function getForcedOutTargets(runners) + local targets = {} + for _, base in ipairs(C.Bases) do + local runnerTargetingBase = utils.getRunnerWithNextBase(runners, base) + if runnerTargetingBase then + targets[#targets + 1] = base + else + return targets + end + end + return targets +end + +--- Returns the position,distance of the basest closest to the runner furthest from a base +---@return Base | nil, number | nil +local function getBaseOfStrandedRunner(runners) + local farRunnersBase, farDistance + for _, runner in pairs(runners) do + if runner ~= batter then + local nearestBase, distance = utils.getNearestOf(C.Bases, runner.x, runner.y) + if farRunnersBase == nil or farDistance < distance then + farRunnersBase = nearestBase + farDistance = distance + end + end + end + + return farRunnersBase, farDistance +end + +--- Returns x,y of the out target +---@return number|nil, number|nil +function npc.getNextOutTarget(runners) + -- TODO: Handle missed throws, check for fielders at target, etc. + local targets = getForcedOutTargets(runners) + if #targets ~= 0 then + return targets[#targets].x, targets[#targets].y + end + + local baseCloseToStrandedRunner = getBaseOfStrandedRunner(runners) + if baseCloseToStrandedRunner then + return baseCloseToStrandedRunner.x, baseCloseToStrandedRunner.y + end +end + +---@param fielder Fielder +function npc.tryToMakeAPlay(fielder, runners, ball, throwBall) + local targetX, targetY = npc.getNextOutTarget(runners) + if targetX ~= nil and targetY ~= nil then + local nearestFielder = utils.getNearestOf(Field.fielders, targetX, targetY) + nearestFielder.target = utils.xy(targetX, targetY) + if nearestFielder == fielder then + ball.heldBy = fielder + else + throwBall(targetX, targetY, playdate.easingFunctions.linear, nil, true) + end + end +end + +if not playdate then + return npc end diff --git a/src/utils.lua b/src/utils.lua index a438e00..e68b68b 100644 --- a/src/utils.lua +++ b/src/utils.lua @@ -142,6 +142,14 @@ function utils.isTouchingBase(x, y) end) end +---@param base Base +---@return Runner | nil runner The runner whose next base matches the given base. +function utils.getRunnerWithNextBase(runners, base) + return utils.first(runners, function(runner) + return runner.nextBase == base + end) +end + --- Returns true only if the point is below the given line, within the x bounds of said line, and above the bottomBound --- @return boolean function utils.pointDirectlyUnderLine(pointX, pointY, lineX1, lineY1, lineX2, lineY2, bottomBound)