Add box score and transitions

Add constants defining the top of the outfield wall (not used yet)
Take scores out of mutable global state (that might be just about all of it sewn up)
Finish switching batttingTeam to a TeamId value
This commit is contained in:
Sage Vaillancourt 2025-02-17 13:21:28 -05:00
parent 6007ac971f
commit 5c45b7bba0
17 changed files with 602 additions and 55 deletions

View File

@ -44,6 +44,7 @@ function Announcer:popIn()
end) end)
end end
---@param text string
function Announcer:say(text) function Announcer:say(text)
self.textQueue[#self.textQueue + 1] = text self.textQueue[#self.textQueue + 1] = text
if #self.textQueue == 1 then if #self.textQueue == 1 then

View File

@ -8,6 +8,8 @@ Glove = playdate.graphics.image.new("images/game/Glove.png")
-- luacheck: ignore -- luacheck: ignore
PlayerFrown = playdate.graphics.image.new("images/game/PlayerFrown.png") PlayerFrown = playdate.graphics.image.new("images/game/PlayerFrown.png")
-- luacheck: ignore -- luacheck: ignore
BigBat = playdate.graphics.image.new("images/game/BigBat.png")
-- luacheck: ignore
GloveHoldingBall = playdate.graphics.image.new("images/game/GloveHoldingBall.png") GloveHoldingBall = playdate.graphics.image.new("images/game/GloveHoldingBall.png")
-- luacheck: ignore -- luacheck: ignore
GameLogo = playdate.graphics.image.new("images/game/GameLogo.png") GameLogo = playdate.graphics.image.new("images/game/GameLogo.png")

View File

@ -125,6 +125,18 @@ C.WalkedRunnerSpeed = 10
C.ResetFieldersAfterSeconds = 2.5 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 },
}
if not playdate then if not playdate then
return C return C
end end

View File

@ -35,8 +35,23 @@ function dbg.loadTheBases(br)
br.runners[4].nextBase = C.Bases[C.Home] br.runners[4].nextBase = C.Bases[C.Home]
end end
---@return BoxScoreData
function dbg.mockBoxScoreData(inningCount)
inningCount = inningCount or 9
local data = {
home = {},
away = {},
}
for i = 1, inningCount do
data.home[i] = math.floor(math.random() * 5)
data.away[i] = math.floor(math.random() * 5)
end
return data
end
---@param points XyPair[] ---@param points XyPair[]
function dbg.drawLine(points) function dbg.drawLine(points)
playdate.graphics.setColor(playdate.graphics.kColorWhite)
for i = 2, #points do for i = 2, #points do
local prev = points[i - 1] local prev = points[i - 1]
local next = points[i] local next = points[i]

79
src/draw/box-score.lua Normal file
View File

@ -0,0 +1,79 @@
---@class BoxScore
---@field data BoxScoreData
BoxScore = {}
---@param data BoxScoreData
function BoxScore.new(data)
return setmetatable({
data = data,
}, { __index = BoxScore })
end
-- TODO: Convert the box-score into a whole "scene"
-- * Scroll left and right through games that go into extra innings
-- * Scroll up and down through other stats.
-- + Balls and strikes
-- + Batting average
-- + Graph of team scores over time
-- + Farthest hit ball
local MarginY <const> = 70
local ScoreFont <const> = playdate.graphics.font.new("fonts/Asheville-Sans-14-Bold.pft")
local NumWidth <const> = ScoreFont:getTextWidth("0")
local NumHeight <const> = ScoreFont:getHeight()
local AwayWidth <const> = ScoreFont:getTextWidth("AWAY")
local InningMargin = 4
local InningDrawWidth <const> = (InningMargin * 2) + (NumWidth * 2)
local ScoreDrawHeight = NumHeight * 2
-- luacheck: ignore 143
---@type pd_graphics_lib
local gfx = playdate.graphics
local function formatScore(n)
if n <= 9 then
return " " .. n
elseif n <= 19 then
return " " .. n
else
return tostring(n)
end
end
local HomeY <const> = -4 + (NumHeight * 2) + MarginY
local AwayY <const> = -4 + (NumHeight * 3) + MarginY
local function drawInning(x, inningNumber, homeScore, awayScore)
gfx.setColor(gfx.kColorBlack)
gfx.setColor(gfx.kColorWhite)
gfx.setLineWidth(1)
gfx.drawRect(x, 34 + MarginY, InningDrawWidth, ScoreDrawHeight)
inningNumber = " " .. inningNumber
homeScore = formatScore(homeScore)
awayScore = formatScore(awayScore)
x = x - 8 + (InningDrawWidth / 2)
ScoreFont:drawTextAligned(inningNumber, x, -4 + NumHeight + MarginY, gfx.kAlignRight)
ScoreFont:drawTextAligned(awayScore, x, HomeY, gfx.kAlignRight)
ScoreFont:drawTextAligned(homeScore, x, AwayY, gfx.kAlignRight)
end
function BoxScore:update()
local originalDrawMode = gfx.getImageDrawMode()
gfx.clear(gfx.kColorBlack)
gfx.setImageDrawMode(gfx.kDrawModeInverted)
gfx.setColor(gfx.kColorBlack)
local inningStart = 4 + (AwayWidth * 1.5)
local widthAndMarg = InningDrawWidth + 4
ScoreFont:drawTextAligned(" HOME", 10, HomeY, gfx.kAlignRight)
ScoreFont:drawTextAligned("AWAY", 10, AwayY, gfx.kAlignRight)
for i = 1, #self.data.away do
drawInning(inningStart + ((i - 1) * widthAndMarg), i, self.data.home[i], self.data.away[i])
end
local homeScore, awayScore = utils.totalScores(self.data)
drawInning(4 + inningStart + (widthAndMarg * #self.data.away), "F", homeScore, awayScore)
gfx.setImageDrawMode(originalDrawMode)
end

View File

@ -83,11 +83,10 @@ local ScoreboardHeight <const> = 55
local Indicator = "> " local Indicator = "> "
local IndicatorWidth <const> = ScoreFont:getTextWidth(Indicator) local IndicatorWidth <const> = ScoreFont:getTextWidth(Indicator)
---@param teams any
---@param battingTeam any ---@param battingTeam any
---@return string, number, string, number ---@return string, number, string, number
function getIndicators(teams, battingTeam) function getIndicators(battingTeam)
if teams.home == battingTeam then if battingTeam == "home" then
return Indicator, 0, "", IndicatorWidth return Indicator, 0, "", IndicatorWidth
end end
return "", IndicatorWidth, Indicator, 0 return "", IndicatorWidth, Indicator, 0
@ -101,11 +100,11 @@ local stats = {
battingTeam = nil, battingTeam = nil,
} }
function drawScoreboardImpl(x, y, teams) function drawScoreboardImpl(x, y)
local homeScore = stats.homeScore local homeScore = stats.homeScore
local awayScore = stats.awayScore local awayScore = stats.awayScore
local homeIndicator, homeOffset, awayIndicator, awayOffset = getIndicators(teams, stats.battingTeam) local homeIndicator, homeOffset, awayIndicator, awayOffset = getIndicators(stats.battingTeam)
local homeScoreText = homeIndicator .. "HOME " .. (homeScore > 9 and homeScore or " " .. homeScore) local homeScoreText = homeIndicator .. "HOME " .. (homeScore > 9 and homeScore or " " .. homeScore)
local awayScoreText = awayIndicator .. "AWAY " .. (awayScore > 9 and awayScore or " " .. awayScore) local awayScoreText = awayIndicator .. "AWAY " .. (awayScore > 9 and awayScore or " " .. awayScore)
@ -146,17 +145,17 @@ end
local newStats = stats local newStats = stats
function drawScoreboard(x, y, teams, outs, battingTeam, inning) function drawScoreboard(x, y, homeScore, awayScore, outs, battingTeam, inning)
if if
newStats.homeScore ~= teams.home.score newStats.homeScore ~= homeScore
or newStats.awayScore ~= teams.away.score or newStats.awayScore ~= awayScore
or newStats.outs ~= outs or newStats.outs ~= outs
or newStats.inning ~= inning or newStats.inning ~= inning
or newStats.battingTeam ~= battingTeam or newStats.battingTeam ~= battingTeam
then then
newStats = { newStats = {
homeScore = teams.home.score, homeScore = homeScore,
awayScore = teams.away.score, awayScore = awayScore,
outs = outs, outs = outs,
inning = inning, inning = inning,
battingTeam = battingTeam, battingTeam = battingTeam,
@ -165,5 +164,5 @@ function drawScoreboard(x, y, teams, outs, battingTeam, inning)
stats = newStats stats = newStats
end) end)
end end
drawScoreboardImpl(x, y, teams) drawScoreboardImpl(x, y)
end end

106
src/draw/transitions.lua Normal file
View File

@ -0,0 +1,106 @@
Transitions = {
---@type Scene | nil
nextScene = nil,
---@type Scene | nil
previousScene = nil,
}
local gfx = playdate.graphics
-- local function animateOut() end
-- local function animateIn() end
local previousSceneImage
local previousSceneMask
local nextSceneImage
-- local nextSceneOffScreen = false
-- local stillAnimating = false
-- TODO: Okay but like imagine.
-- Push a blank image context,
-- draw the previous scene on one side,
-- draw the next scene on the other,
-- SWING a bat to cover the seam.
local batImageTable = {}
local batOffset = 80
local degStep = 3
function loadBatImageTable()
for deg = 90 - (degStep * 3), 270 + (degStep * 3), degStep do
local img = gfx.image.new(C.Screen.W, C.Screen.H)
gfx.pushContext(img)
BigBat:drawRotated(C.Center.x, C.Screen.H + batOffset, 90 + deg)
gfx.popContext()
batImageTable[deg] = img
end
end
loadBatImageTable()
local function update()
local lastAngle
local seamAngle = math.rad(270)
while seamAngle > math.rad(90) do
local deltaSeconds = playdate.getElapsedTime()
playdate.resetElapsedTime()
seamAngle = seamAngle - (deltaSeconds * 3)
local seamAngleDeg = math.floor(math.deg(seamAngle))
seamAngleDeg = seamAngleDeg - (seamAngleDeg % degStep)
-- Skip re-drawing if no change
if lastAngle ~= seamAngleDeg then
lastAngle = seamAngleDeg
nextSceneImage:draw(0, 0)
gfx.pushContext(previousSceneMask)
gfx.setImageDrawMode(gfx.kDrawModeFillBlack)
batImageTable[seamAngleDeg]:draw(0, 0)
gfx.popContext()
previousSceneImage:setMaskImage(previousSceneMask)
previousSceneImage:draw(0, 0)
batImageTable[seamAngleDeg]:draw(0, 0)
end
coroutine.yield()
end
playdate.update = function()
Transitions.nextScene:update()
end
end
---@param nextScene fun() The next playdate.update function
function transitionTo(nextScene)
if not Transitions.nextScene then
error("Expected Transitions to already have nextScene defined! E.g. by calling transitionBetween")
end
local previousScene = Transitions.nextScene
transitionBetween(previousScene, nextScene)
end
---@param previousScene Scene Has the current playdate.update function
---@param nextScene Scene Has the next playdate.update function
function transitionBetween(previousScene, nextScene)
playdate.wait(2) -- TODO: There's some sort of timing wack here.
playdate.update = update
previousSceneImage = gfx.image.new(C.Screen.W, C.Screen.H)
gfx.pushContext(previousSceneImage)
previousScene:update()
gfx.popContext()
nextSceneImage = gfx.image.new(C.Screen.W, C.Screen.H)
gfx.pushContext(nextSceneImage)
nextScene:update()
gfx.popContext()
previousSceneMask = gfx.image.new(C.Screen.W, C.Screen.H, gfx.kColorWhite)
previousSceneImage:setMaskImage(previousSceneMask)
Transitions.nextScene = nextScene
Transitions.previousScene = previousScene
end

View File

@ -182,7 +182,7 @@ function Fielding:userThrowTo(targetBase, ball, throwFlyMs)
end) end)
end end
function Fielding:celebrate() function Fielding.celebrate()
FielderDanceAnimator:reset(C.DanceBounceMs) FielderDanceAnimator:reset(C.DanceBounceMs)
end end

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View File

@ -0,0 +1,295 @@
tracking=1
space 3
! 2
" 5
# 9
$ 8
% 12
& 11
' 3
( 5
) 5
* 8
+ 8
, 3
- 6
. 2
/ 6
0 9
1 4
2 9
3 9
4 9
5 9
6 9
7 9
8 10
9 9
: 2
; 2
< 7
= 7
> 7
? 9
@ 11
A 10
B 9
C 9
D 9
E 8
F 8
G 9
H 9
I 2
J 8
K 10
L 9
M 12
N 9
O 9
P 9
Q 9
R 9
S 9
T 10
U 9
V 10
W 14
X 8
Y 8
Z 8
[ 3
\ 6
] 3
^ 6
_ 8
` 3
a 8
b 8
c 8
d 8
e 8
f 6
g 8
h 8
i 2
j 4
k 8
l 2
m 12
n 8
o 8
p 8
q 8
r 6
s 8
t 6
u 8
v 8
w 12
x 9
y 8
z 8
{ 6
| 2
} 6
~ 10
… 8
¥ 8
‼ 5
™ 8
© 11
® 11
。 16
、 16
ぁ 16
あ 16
ぃ 16
い 16
ぅ 16
う 16
ぇ 16
え 16
ぉ 16
お 16
か 16
が 16
き 16
ぎ 16
く 16
ぐ 16
け 16
げ 16
こ 16
ご 16
さ 16
ざ 16
し 16
じ 16
す 16
ず 16
せ 16
ぜ 16
そ 16
ぞ 16
た 16
だ 16
ち 16
ぢ 16
っ 16
つ 16
づ 16
て 16
で 16
と 16
ど 16
な 16
に 16
ぬ 16
ね 16
の 16
は 16
ば 16
ぱ 16
ひ 16
び 16
ぴ 16
ふ 16
ぶ 16
ぷ 16
へ 16
べ 16
ぺ 16
ほ 16
ぼ 16
ぽ 16
ま 16
み 16
む 16
め 16
も 16
ゃ 16
や 16
ゅ 16
ゆ 16
ょ 16
よ 16
ら 16
り 16
る 16
れ 16
ろ 16
ゎ 16
わ 16
ゐ 16
ゑ 16
を 16
ん 16
ゔ 16
ゕ 16
ゖ 16
゛ 1
゜ 0
ゝ 16
ゞ 16
ゟ 16
16
ァ 16
ア 16
ィ 16
イ 16
ゥ 16
ウ 16
ェ 16
エ 16
ォ 16
オ 16
カ 16
ガ 16
キ 16
ギ 16
ク 16
グ 16
ケ 16
ゲ 16
コ 16
ゴ 16
サ 16
ザ 16
シ 16
ジ 16
ス 16
ズ 16
セ 16
ゼ 16
ソ 16
ゾ 16
タ 16
ダ 16
チ 16
ヂ 16
ッ 16
ツ 16
ヅ 16
テ 16
デ 16
ト 16
ド 16
ナ 16
ニ 16
ヌ 16
ネ 16
16
ハ 16
バ 16
パ 16
ヒ 16
ビ 16
ピ 16
フ 16
ブ 16
プ 16
ヘ 16
ベ 16
ペ 16
ホ 16
ボ 16
ポ 16
マ 16
ミ 16
ム 16
メ 16
モ 16
ャ 16
ヤ 16
ュ 16
ユ 16
ョ 16
ヨ 16
ラ 16
リ 16
ル 16
レ 16
ロ 16
ヮ 16
ワ 16
ヰ 16
ヱ 16
ヲ 16
ン 16
ヴ 16
ヵ 16
ヶ 16
ヷ 16
ヸ 16
ヹ 16
ヺ 16
・ 16
ー 16
ヽ 16
ヾ 16
ヿ 16
「 16
」 16
円 16
<EFBFBD> 13

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 9.4 KiB

BIN
src/images/game/BigBat.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 34 KiB

View File

@ -24,9 +24,7 @@ local function startGame()
awayTeamSprites = AwayTeamSprites, awayTeamSprites = AwayTeamSprites,
}) })
playdate.resetElapsedTime() playdate.resetElapsedTime()
playdate.update = function() transitionBetween(MainMenu, next)
next:update()
end
end end
local function pausingEaser(baseEaser) local function pausingEaser(baseEaser)
@ -64,9 +62,10 @@ local function arrayElementFromCrank(array, crankPosition)
return array[i] return array[i]
end end
local currentLogo = nil local currentLogo
function MainMenu.update() --luacheck: ignore
function MainMenu:update()
playdate.timer.updateTimers() playdate.timer.updateTimers()
crankStartPos = crankStartPos or playdate.getCrankPosition() crankStartPos = crankStartPos or playdate.getCrankPosition()

View File

@ -8,6 +8,8 @@ import 'CoreLibs/timer.lua'
import 'CoreLibs/ui.lua' import 'CoreLibs/ui.lua'
-- stylua: ignore end -- stylua: ignore end
--- @alias Scene { update: fun(self: self) }
--- @alias EasingFunc fun(number, number, number, number): number --- @alias EasingFunc fun(number, number, number, number): number
--- @alias LaunchBall fun( --- @alias LaunchBall fun(
@ -24,9 +26,11 @@ import 'CoreLibs/ui.lua'
import 'utils.lua' import 'utils.lua'
import 'constants.lua' import 'constants.lua'
import 'assets.lua' import 'assets.lua'
import 'draw/player.lua' import 'draw/box-score.lua'
import 'draw/overlay.lua'
import 'draw/fielder.lua' import 'draw/fielder.lua'
import 'draw/overlay.lua'
import 'draw/player.lua'
import 'draw/transitions.lua'
import 'main-menu.lua' import 'main-menu.lua'
@ -44,19 +48,18 @@ import 'npc.lua'
local gfx <const>, C <const> = playdate.graphics, C local gfx <const>, C <const> = playdate.graphics, C
---@alias Team { score: number, benchPosition: XyPair } ---@alias Team { benchPosition: XyPair }
---@type table<TeamId, Team> ---@type table<TeamId, Team>
local teams <const> = { local teams <const> = {
home = { home = {
score = 0, -- TODO: Extract this last bit of global mutable state.
benchPosition = utils.xy(C.Screen.W + 10, C.Center.y), benchPosition = utils.xy(C.Screen.W + 10, C.Center.y),
}, },
away = { away = {
score = 0,
benchPosition = utils.xy(-10, C.Center.y), benchPosition = utils.xy(-10, C.Center.y),
}, },
} }
---@alias BoxScoreData table<TeamId, number[]>
---@alias TeamId 'home' | 'away' ---@alias TeamId 'home' | 'away'
--- Well, maybe not "Settings", but passive state that probably won't change much, if at all, during a game. --- Well, maybe not "Settings", but passive state that probably won't change much, if at all, during a game.
@ -73,6 +76,7 @@ local teams <const> = {
---@field catcherThrownBall boolean ---@field catcherThrownBall boolean
---@field offenseState OffenseState ---@field offenseState OffenseState
---@field inning number ---@field inning number
---@field boxScore BoxScoreData
---@field batBase XyPair ---@field batBase XyPair
---@field batTip XyPair ---@field batTip XyPair
---@field batAngleDeg number ---@field batAngleDeg number
@ -104,8 +108,6 @@ Game = {}
---@param state MutableState | nil ---@param state MutableState | nil
---@return Game ---@return Game
function Game.new(settings, announcer, fielding, baserunning, npc, state) function Game.new(settings, announcer, fielding, baserunning, npc, state)
teams.away.score = 0
teams.home.score = 0
announcer = announcer or Announcer.new() announcer = announcer or Announcer.new()
fielding = fielding or Fielding.new() fielding = fielding or Fielding.new()
settings.userTeam = nil -- "away" settings.userTeam = nil -- "away"
@ -137,6 +139,10 @@ function Game.new(settings, announcer, fielding, baserunning, npc, state)
battingTeamSprites = settings.awayTeamSprites, battingTeamSprites = settings.awayTeamSprites,
fieldingTeamSprites = settings.homeTeamSprites, fieldingTeamSprites = settings.homeTeamSprites,
runnerBlipper = runnerBlipper, runnerBlipper = runnerBlipper,
boxScore = {
home = { 0 },
away = { 0 },
},
}, },
}, { __index = Game }) }, { __index = Game })
@ -210,10 +216,6 @@ local function getOppositeTeamId(teamId)
end end
end end
function Game:getBattingTeam()
return teams[self.state.battingTeam] or error("Unknown battingTeam: " .. (self.state.battingTeam or "nil"))
end
function Game:getFieldingTeam() function Game:getFieldingTeam()
return teams[getOppositeTeamId(self.state.battingTeam)] return teams[getOppositeTeamId(self.state.battingTeam)]
end end
@ -265,24 +267,33 @@ end
function Game:nextHalfInning() function Game:nextHalfInning()
pitchTracker:reset() pitchTracker:reset()
local gameOver = self.state.inning == self.settings.finalInning and teams.away.score ~= teams.home.score local homeScore, awayScore = utils.totalScores(self.state.boxScore)
if not gameOver then local gameOver = self.state.battingTeam == "home"
self.fielding:celebrate() and self.state.inning == self.settings.finalInning
self.state.secondsSinceLastRunnerMove = -7 and awayScore ~= homeScore
self.fielding:benchTo(self:getFieldingTeam().benchPosition)
self.announcer:say("SWITCHING SIDES...")
end
if gameOver then if gameOver then
self.announcer:say("AND THAT'S THE BALL GAME!") self.announcer:say("AND THAT'S THE BALL GAME!")
else playdate.timer.new(3000, function()
transitionTo(BoxScore.new(self.state.boxScore))
end)
return
end
Fielding.celebrate()
self.state.secondsSinceLastRunnerMove = -7
self.fielding:benchTo(self:getFieldingTeam().benchPosition)
self.announcer:say("SWITCHING SIDES...")
self.fielding:resetFielderPositions() self.fielding:resetFielderPositions()
if self.state.battingTeam == teams.home then if self.state.battingTeam == "home" then
self.state.inning = self.state.inning + 1 self.state.inning = self.state.inning + 1
self.state.boxScore.home[self.state.inning] = 0
self.state.boxScore.away[self.state.inning] = 0
end end
self.state.battingTeam = getOppositeTeamId(self.state.battingTeam) self.state.battingTeam = getOppositeTeamId(self.state.battingTeam)
playdate.timer.new(2000, function() playdate.timer.new(2000, function()
if self.state.battingTeam == teams.home then if self.state.battingTeam == "home" then
self.state.battingTeamSprites = self.settings.homeTeamSprites self.state.battingTeamSprites = self.settings.homeTeamSprites
self.state.runnerBlipper = self.homeTeamBlipper self.state.runnerBlipper = self.homeTeamBlipper
self.state.fieldingTeamSprites = self.settings.awayTeamSprites self.state.fieldingTeamSprites = self.settings.awayTeamSprites
@ -292,13 +303,13 @@ function Game:nextHalfInning()
self.state.runnerBlipper = self.awayTeamBlipper self.state.runnerBlipper = self.awayTeamBlipper
end end
end) end)
end
end end
---@param scoredRunCount number ---@param scoredRunCount number
function Game:score(scoredRunCount) function Game:score(scoredRunCount)
local batting = self:getBattingTeam() local battingTeamBoxScore = self.state.boxScore[self.state.battingTeam]
batting.score = batting.score + scoredRunCount battingTeamBoxScore[self.state.inning] = battingTeamBoxScore[self.state.inning] + scoredRunCount
self.announcer:say("SCORE!") self.announcer:say("SCORE!")
end end
@ -513,7 +524,8 @@ function Game:updateGameState()
if self.state.secondsSinceLastRunnerMove > C.ResetFieldersAfterSeconds then if self.state.secondsSinceLastRunnerMove > C.ResetFieldersAfterSeconds then
-- End of play. Throw the ball back to the pitcher -- End of play. Throw the ball back to the pitcher
self.state.ball:launch(C.PitchStartX, C.PitchStartY, playdate.easingFunctions.linear, nil, true) self.state.ball:launch(C.PitchStartX, C.PitchStartY, playdate.easingFunctions.linear, nil, true)
self.fielding:markAllIneligible() -- This is ugly, and ideally would not be necessary if Fielding handled the return throw directly. -- This is ugly, and ideally would not be necessary if Fielding handled the return throw directly.
self.fielding:markAllIneligible()
self.fielding:resetFielderPositions() self.fielding:resetFielderPositions()
self.state.offenseState = C.Offense.batting self.state.offenseState = C.Offense.batting
-- TODO: Remove, or replace with nextBatter() -- TODO: Remove, or replace with nextBatter()
@ -629,11 +641,21 @@ function Game:update()
if math.abs(offsetX) > 10 or math.abs(offsetY) > 10 then if math.abs(offsetX) > 10 or math.abs(offsetY) > 10 then
drawMinimap(self.baserunning.runners, self.fielding.fielders) drawMinimap(self.baserunning.runners, self.fielding.fielders)
end end
drawScoreboard(0, C.Screen.H * 0.77, teams, self.baserunning.outs, self:getBattingTeam(), self.state.inning) local homeScore, awayScore = utils.totalScores(self.state.boxScore)
drawScoreboard(
0,
C.Screen.H * 0.77,
homeScore,
awayScore,
self.baserunning.outs,
self.state.battingTeam,
self.state.inning
)
drawBallsAndStrikes(290, C.Screen.H - 20, pitchTracker.balls, pitchTracker.strikes) drawBallsAndStrikes(290, C.Screen.H - 20, pitchTracker.balls, pitchTracker.strikes)
self.announcer:draw(C.Center.x, 10) self.announcer:draw(C.Center.x, 10)
if playdate.isCrankDocked() then if playdate.isCrankDocked() then
-- luacheck: ignore
playdate.ui.crankIndicator:draw() playdate.ui.crankIndicator:draw()
end end
end end

View File

@ -22,6 +22,7 @@ end
---@param catcherThrownBall boolean ---@param catcherThrownBall boolean
---@param deltaSec number ---@param deltaSec number
---@return number ---@return number
-- luacheck: no unused
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 if not catcherThrownBall and ball.y > 200 and ball.y < 230 and (ball.x < C.Center.x + 15) then
npcBatDeg = npcBatDeg + (deltaSec * npcBatSpeed) npcBatDeg = npcBatDeg + (deltaSec * npcBatSpeed)

View File

@ -232,6 +232,22 @@ function utils.getNearestOf(array, x, y, extraCondition)
return nearest, nearestDistance return nearest, nearestDistance
end end
---@param box BoxScore
---@return number homeScore, number awayScore
function utils.totalScores(box)
local homeScore = 0
for _, score in pairs(box.home) do
homeScore = homeScore + score
end
local awayScore = 0
for _, score in pairs(box.away) do
awayScore = awayScore + score
end
return homeScore, awayScore
end
PitchOutcomes = { PitchOutcomes = {
StrikeOut = {}, StrikeOut = {},
Walk = {}, Walk = {},