Extract almost all NPC fielding logic
This commit is contained in:
parent
80c15161e3
commit
30f2eada72
|
@ -94,7 +94,9 @@ C.ThrowMeterDrainPerSec = 150
|
||||||
|
|
||||||
--- Controls how hard the ball can be hit, and
|
--- Controls how hard the ball can be hit, and
|
||||||
--- how fast the ball can be thrown.
|
--- how fast the ball can be thrown.
|
||||||
C.CrankPower = 3
|
C.CrankPower = 10
|
||||||
|
|
||||||
|
C.PitchPower = 0.3
|
||||||
|
|
||||||
--- How fast baserunners move after a walk
|
--- How fast baserunners move after a walk
|
||||||
C.WalkedRunnerSpeed = 10
|
C.WalkedRunnerSpeed = 10
|
||||||
|
|
83
src/main.lua
83
src/main.lua
|
@ -85,7 +85,7 @@ local teams <const> = {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
local PlayerTeam <const> = teams.home
|
local PlayerTeam <const> = teams.away
|
||||||
local battingTeam = teams.away
|
local battingTeam = teams.away
|
||||||
local outs = 0
|
local outs = 0
|
||||||
local inning = 1
|
local inning = 1
|
||||||
|
@ -206,18 +206,10 @@ local function pitch(pitchFlyTimeMs, pitchTypeIndex)
|
||||||
secondsSincePitchAllowed = 0
|
secondsSincePitchAllowed = 0
|
||||||
end
|
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 function updateForcedRunners()
|
||||||
local stillForced = true
|
local stillForced = true
|
||||||
for _, base in ipairs(C.Bases) do
|
for _, base in ipairs(C.Bases) do
|
||||||
local runnerTargetingBase = getRunnerWithNextBase(base)
|
local runnerTargetingBase = utils.getRunnerWithNextBase(runners, base)
|
||||||
if runnerTargetingBase then
|
if runnerTargetingBase then
|
||||||
if stillForced then
|
if stillForced then
|
||||||
runnerTargetingBase.forcedTo = base
|
runnerTargetingBase.forcedTo = base
|
||||||
|
@ -287,66 +279,6 @@ local function score(runnerIndex)
|
||||||
announcer:say("SCORE!")
|
announcer:say("SCORE!")
|
||||||
end
|
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()
|
local function readThrow()
|
||||||
if throwMeter > C.ThrowMeterMax then
|
if throwMeter > C.ThrowMeterMax then
|
||||||
return (C.PitchFlyMs / (throwMeter / C.ThrowMeterMax))
|
return (C.PitchFlyMs / (throwMeter / C.ThrowMeterMax))
|
||||||
|
@ -404,16 +336,17 @@ local function outEligibleRunners(fielder)
|
||||||
return didOutRunner
|
return didOutRunner
|
||||||
end
|
end
|
||||||
|
|
||||||
local function updateNpcFielder(fielder, outedSomeRunner)
|
local function npcFielderAction(fielder, outedSomeRunner)
|
||||||
if offenseMode ~= C.Offense.running then
|
if offenseMode ~= C.Offense.running then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
if outedSomeRunner then
|
if outedSomeRunner then
|
||||||
|
-- Delay a little before the next play
|
||||||
playdate.timer.new(750, function()
|
playdate.timer.new(750, function()
|
||||||
npcTryToMakeAnOut(fielder)
|
npc.tryToMakeAPlay(fielder, runners, ball, throwBall)
|
||||||
end)
|
end)
|
||||||
else
|
else
|
||||||
npcTryToMakeAnOut(fielder)
|
npc.tryToMakeAPlay(fielder, runners, ball, throwBall)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -617,7 +550,7 @@ local function updateGameState()
|
||||||
|
|
||||||
if playerOnDefense then
|
if playerOnDefense then
|
||||||
throwMeter = math.max(0, throwMeter - (deltaSeconds * C.ThrowMeterDrainPerSec))
|
throwMeter = math.max(0, throwMeter - (deltaSeconds * C.ThrowMeterDrainPerSec))
|
||||||
throwMeter = throwMeter + math.abs(crankLimited)
|
throwMeter = throwMeter + math.abs(crankLimited * C.PitchPower)
|
||||||
end
|
end
|
||||||
|
|
||||||
if offenseMode == C.Offense.batting then
|
if offenseMode == C.Offense.batting then
|
||||||
|
@ -699,7 +632,7 @@ local function updateGameState()
|
||||||
buttonControlledThrow(Field.fielders.pitcher, throwFly)
|
buttonControlledThrow(Field.fielders.pitcher, throwFly)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
updateNpcFielder(fielder, outedSomeRunner)
|
npcFielderAction(fielder, outedSomeRunner)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
64
src/npc.lua
64
src/npc.lua
|
@ -30,6 +30,66 @@ function npc.runningSpeed(runners)
|
||||||
return 0
|
return 0
|
||||||
end
|
end
|
||||||
|
|
||||||
if not playdate then
|
---@return Base[]
|
||||||
return utils
|
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
|
end
|
||||||
|
|
|
@ -142,6 +142,14 @@ function utils.isTouchingBase(x, y)
|
||||||
end)
|
end)
|
||||||
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
|
--- Returns true only if the point is below the given line, within the x bounds of said line, and above the bottomBound
|
||||||
--- @return boolean
|
--- @return boolean
|
||||||
function utils.pointDirectlyUnderLine(pointX, pointY, lineX1, lineY1, lineX2, lineY2, bottomBound)
|
function utils.pointDirectlyUnderLine(pointX, pointY, lineX1, lineY1, lineX2, lineY2, bottomBound)
|
||||||
|
|
Loading…
Reference in New Issue